GnuCash  5.6-150-g038405b370+
gnc-plugin-page-register.cpp
1 /**********************************************************************
2  * gnc-plugin-page-register.c -- register page functions *
3  * *
4  * Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de> *
5  * Copyright (C) 2003,2005,2006 David Hampton <hampton@employees.org> *
6  * Copyright (C) 2011, Robert Fewell *
7  * *
8  * This program is free software; you can redistribute it and/or *
9  * modify it under the terms of the GNU General Public License as *
10  * published by the Free Software Foundation; either version 2 of *
11  * the License, or (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, contact: *
20  * *
21  * Free Software Foundation Voice: +1-617-542-5942 *
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
23  * Boston, MA 02110-1301, USA gnu@gnu.org *
24  **********************************************************************/
25 
36 #include <config.h>
37 
38 #include <optional>
39 
40 #include <libguile.h>
41 #include <gtk/gtk.h>
42 #include <glib/gi18n.h>
43 #include "swig-runtime.h"
44 #include "guile-mappings.h"
45 
47 #include "gnc-plugin-register.h"
49 #include "gnc-plugin-page-report.h"
50 #include "gnc-plugin-business.h"
51 
52 #include "dialog-account.h"
53 #include "dialog-dup-trans.h"
54 #include "dialog-find-account.h"
55 #include "dialog-find-transactions.h"
56 #include "dialog-print-check.h"
57 #include "dialog-invoice.h"
58 #include "dialog-transfer.h"
59 #include "dialog-utils.h"
60 #include "assistant-stock-split.h"
61 #include "assistant-stock-transaction.h"
62 #include "gnc-component-manager.h"
63 #include "gnc-date.h"
64 #include "gnc-date-edit.h"
65 #include "gnc-engine.h"
66 #include "gnc-event.h"
67 #include "gnc-features.h"
68 #include "gnc-glib-utils.h"
69 #include "gnc-gnome-utils.h"
70 #include "gnc-gobject-utils.h"
71 #include "gnc-gui-query.h"
72 #include "gnc-icons.h"
73 #include "gnc-split-reg.h"
74 #include "gnc-state.h"
75 #include "gnc-prefs.h"
76 #include "gnc-ui-util.h"
77 #include "gnc-window.h"
78 #include "gnc-main-window.h"
79 #include "gnc-session.h"
80 #include "gnc-ui.h"
81 #include "gnc-warnings.h"
82 #include "gnucash-sheet.h"
83 #include "dialog-lot-viewer.h"
84 #include "Scrub.h"
85 #include "ScrubBusiness.h"
86 #include "qof.h"
87 #include "window-reconcile.h"
88 #include "window-autoclear.h"
89 #include "window-report.h"
90 #include "engine-helpers.h"
91 #include "qofbookslots.h"
92 #include "gnc-gtk-utils.h"
93 
94 /* gschema: org.gnucash.GnuCash.general.register.JumpMultipleSplits */
95 typedef enum : gint
96 {
97  JUMP_DEFAULT = 0, /* Do nothing */
98  JUMP_LARGEST_VALUE_FIRST_SPLIT = 1,
99  JUMP_SMALLEST_VALUE_FIRST_SPLIT = 2,
100 } GncPrefJumpMultSplits;
101 
102 /* This static indicates the debugging module that this .o belongs to. */
103 static QofLogModule log_module = GNC_MOD_GUI;
104 
105 #define DEFAULT_LINES_AMOUNT 50
106 #define DEFAULT_FILTER_NUM_DAYS_GL "30"
107 
108 static void gnc_plugin_page_register_finalize (GObject* object);
109 
110 /* static Account *gnc_plugin_page_register_get_current_account (GncPluginPageRegister *page); */
111 
112 static GtkWidget* gnc_plugin_page_register_create_widget (
113  GncPluginPage* plugin_page);
114 static void gnc_plugin_page_register_destroy_widget (GncPluginPage*
115  plugin_page);
116 static void gnc_plugin_page_register_window_changed (GncPluginPage*
117  plugin_page, GtkWidget* window);
118 static gboolean gnc_plugin_page_register_focus_widget (GncPluginPage*
119  plugin_page);
120 static void gnc_plugin_page_register_focus (GncPluginPage* plugin_page,
121  gboolean current_page);
122 static void gnc_plugin_page_register_save_page (GncPluginPage* plugin_page,
123  GKeyFile* file, const gchar* group);
124 static GncPluginPage* gnc_plugin_page_register_recreate_page (
125  GtkWidget* window, GKeyFile* file, const gchar* group);
126 static void gnc_plugin_page_register_update_edit_menu (GncPluginPage* page,
127  gboolean hide);
128 static gboolean gnc_plugin_page_register_finish_pending (GncPluginPage* page);
129 
130 static gchar* gnc_plugin_page_register_get_tab_name (GncPluginPage*
131  plugin_page);
132 static gchar* gnc_plugin_page_register_get_tab_color (GncPluginPage*
133  plugin_page);
134 static gchar* gnc_plugin_page_register_get_long_name (GncPluginPage*
135  plugin_page);
136 
137 static void gnc_plugin_page_register_summarybar_position_changed (
138  gpointer prefs, gchar* pref, gpointer user_data);
139 
140 extern "C"
141 {
142 /* Callbacks for the "Sort By" dialog */
143 void gnc_plugin_page_register_sort_button_cb (GtkToggleButton* button,
144  GncPluginPageRegister* page);
145 void gnc_plugin_page_register_sort_response_cb (GtkDialog* dialog,
146  gint response, GncPluginPageRegister* plugin_page);
147 void gnc_plugin_page_register_sort_order_save_cb (GtkToggleButton* button,
148  GncPluginPageRegister* page);
149 void gnc_plugin_page_register_sort_order_reverse_cb (GtkToggleButton* button,
150  GncPluginPageRegister* page);
151 }
152 
153 static gchar* gnc_plugin_page_register_get_sort_order (GncPluginPage*
154  plugin_page);
155 void gnc_plugin_page_register_set_sort_order (GncPluginPage* plugin_page,
156  const gchar* sort_order);
157 static gboolean gnc_plugin_page_register_get_sort_reversed (
158  GncPluginPage* plugin_page);
159 void gnc_plugin_page_register_set_sort_reversed (GncPluginPage* plugin_page,
160  gboolean reverse_order);
161 
162 extern "C"
163 {
164 /* Callbacks for the "Filter By" dialog */
165 void gnc_plugin_page_register_filter_select_range_cb (GtkRadioButton* button,
166  GncPluginPageRegister* page);
167 void gnc_plugin_page_register_filter_start_cb (GtkWidget* radio,
168  GncPluginPageRegister* page);
169 void gnc_plugin_page_register_filter_end_cb (GtkWidget* radio,
170  GncPluginPageRegister* page);
171 void gnc_plugin_page_register_filter_response_cb (GtkDialog* dialog,
172  gint response, GncPluginPageRegister* plugin_page);
174  GncPluginPageRegister* plugin_page);
176  GncPluginPageRegister* plugin_page);
177 void gnc_plugin_page_register_filter_status_one_cb (GtkToggleButton* button,
178  GncPluginPageRegister* page);
179 void gnc_plugin_page_register_filter_save_cb (GtkToggleButton* button,
180  GncPluginPageRegister* page);
181 void gnc_plugin_page_register_filter_days_changed_cb (GtkSpinButton* button,
182  GncPluginPageRegister* page);
183 }
184 
185 static time64 gnc_plugin_page_register_filter_dmy2time (char* date_string);
186 static gchar* gnc_plugin_page_register_filter_time2dmy (time64 raw_time);
187 static gchar* gnc_plugin_page_register_get_filter (GncPluginPage* plugin_page);
188 void gnc_plugin_page_register_set_filter (GncPluginPage* plugin_page,
189  const gchar* filter);
190 static void gnc_plugin_page_register_set_filter_tooltip (GncPluginPageRegister* page);
191 
192 static void gnc_ppr_update_status_query (GncPluginPageRegister* page);
193 static void gnc_ppr_update_date_query (GncPluginPageRegister* page);
194 
195 /* Command callbacks */
196 static void gnc_plugin_page_register_cmd_print_check (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
197 static void gnc_plugin_page_register_cmd_cut (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
198 static void gnc_plugin_page_register_cmd_copy (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
199 static void gnc_plugin_page_register_cmd_paste (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
200 static void gnc_plugin_page_register_cmd_edit_account (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
201 static void gnc_plugin_page_register_cmd_find_account (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
202 static void gnc_plugin_page_register_cmd_find_transactions (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
203 static void gnc_plugin_page_register_cmd_edit_tax_options (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
204 static void gnc_plugin_page_register_cmd_cut_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
205 static void gnc_plugin_page_register_cmd_copy_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
206 static void gnc_plugin_page_register_cmd_paste_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
207 static void gnc_plugin_page_register_cmd_void_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
208 static void gnc_plugin_page_register_cmd_unvoid_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
209 static void gnc_plugin_page_register_cmd_reverse_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
210 static void gnc_plugin_page_register_cmd_view_sort_by (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
211 static void gnc_plugin_page_register_cmd_view_filter_by (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
212 
213 static void gnc_plugin_page_register_cmd_style_changed (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
214 static void gnc_plugin_page_register_cmd_style_double_line (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
215 static void gnc_plugin_page_register_cmd_expand_transaction (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
216 
217 static void gnc_plugin_page_register_cmd_reconcile (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
218 static void gnc_plugin_page_register_cmd_stock_assistant (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
219 static void gnc_plugin_page_register_cmd_autoclear (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
220 static void gnc_plugin_page_register_cmd_transfer (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
221 static void gnc_plugin_page_register_cmd_stock_split (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
222 static void gnc_plugin_page_register_cmd_lots (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
223 static void gnc_plugin_page_register_cmd_enter_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
224 static void gnc_plugin_page_register_cmd_cancel_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
225 static void gnc_plugin_page_register_cmd_delete_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
226 static void gnc_plugin_page_register_cmd_blank_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
227 static void gnc_plugin_page_register_cmd_goto_date (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
228 static void gnc_plugin_page_register_cmd_duplicate_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
229 static void gnc_plugin_page_register_cmd_reinitialize_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
230 static void gnc_plugin_page_register_cmd_exchange_rate (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
231 static void gnc_plugin_page_register_cmd_jump (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
232 static void gnc_plugin_page_register_cmd_reload (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
233 static void gnc_plugin_page_register_cmd_schedule (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
234 static void gnc_plugin_page_register_cmd_scrub_all (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
235 static void gnc_plugin_page_register_cmd_scrub_current (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
236 static void gnc_plugin_page_register_cmd_account_report (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
237 static void gnc_plugin_page_register_cmd_transaction_report (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
238 static void gnc_plugin_page_register_cmd_linked_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
239 static void gnc_plugin_page_register_cmd_linked_transaction_open (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
240 static void gnc_plugin_page_register_cmd_jump_linked_invoice (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
241 
242 static void gnc_plugin_page_help_changed_cb (GNCSplitReg* gsr,
243  GncPluginPageRegister* register_page);
244 static void gnc_plugin_page_popup_menu_cb (GNCSplitReg* gsr,
245  GncPluginPageRegister* register_page);
246 static void gnc_plugin_page_register_refresh_cb (GHashTable* changes,
247  gpointer user_data);
248 static void gnc_plugin_page_register_close_cb (gpointer user_data);
249 
250 static void gnc_plugin_page_register_ui_update (gpointer various,
251  GncPluginPageRegister* page);
252 static void gppr_account_destroy_cb (Account* account);
253 static void gnc_plugin_page_register_event_handler (QofInstance* entity,
254  QofEventId event_type,
255  GncPluginPageRegister* page,
256  GncEventData* ed);
257 
258 static GncInvoice* invoice_from_split (Split* split);
259 
260 /************************************************************/
261 /* Actions */
262 /************************************************************/
263 
264 #define CUT_TRANSACTION_LABEL N_("Cu_t Transaction")
265 #define COPY_TRANSACTION_LABEL N_("_Copy Transaction")
266 #define PASTE_TRANSACTION_LABEL N_("_Paste Transaction")
267 #define DUPLICATE_TRANSACTION_LABEL N_("Dup_licate Transaction")
268 #define DELETE_TRANSACTION_LABEL N_("_Delete Transaction")
269 /* Translators: This is a menu item that opens a dialog for linking an
270  external file or URL with the bill, invoice, transaction, or voucher or
271  removing such an link. */
272 #define LINK_TRANSACTION_LABEL N_("_Manage Document Link…")
273 /* Translators: This is a menu item that opens an external file or URI that may
274  be linked to the current bill, invoice, transaction, or voucher using
275  the operating system's default application for the file or URI mime type. */
276 #define LINK_TRANSACTION_OPEN_LABEL N_("_Open Linked Document")
277 /* Translators: This is a menu item that will open the bill, invoice, or voucher
278  that is posted to the current transaction if there is one. */
279 #define JUMP_LINKED_INVOICE_LABEL N_("Jump to Business item")
280 #define CUT_SPLIT_LABEL N_("Cu_t Split")
281 #define COPY_SPLIT_LABEL N_("_Copy Split")
282 #define PASTE_SPLIT_LABEL N_("_Paste Split")
283 #define DUPLICATE_SPLIT_LABEL N_("Dup_licate Split")
284 #define DELETE_SPLIT_LABEL N_("_Delete Split")
285 #define CUT_TRANSACTION_TIP N_("Cut the selected transaction into clipboard")
286 #define COPY_TRANSACTION_TIP N_("Copy the selected transaction into clipboard")
287 #define PASTE_TRANSACTION_TIP N_("Paste the transaction from the clipboard")
288 #define DUPLICATE_TRANSACTION_TIP N_("Make a copy of the current transaction")
289 #define DELETE_TRANSACTION_TIP N_("Delete the current transaction")
290 #define LINK_TRANSACTION_TIP N_("Add, change, or unlink the document linked with the current transaction")
291 #define LINK_TRANSACTION_OPEN_TIP N_("Open the linked document for the current transaction")
292 #define JUMP_LINKED_INVOICE_TIP N_("Jump to the linked invoice, bill, expense or credit note")
293 #define CUT_SPLIT_TIP N_("Cut the selected split into clipboard")
294 #define COPY_SPLIT_TIP N_("Copy the selected split into clipboard")
295 #define PASTE_SPLIT_TIP N_("Paste the split from the clipboard")
296 #define DUPLICATE_SPLIT_TIP N_("Make a copy of the current split")
297 #define DELETE_SPLIT_TIP N_("Delete the current split")
298 
299 static GActionEntry gnc_plugin_page_register_actions [] =
300 {
301  { "FilePrintAction", gnc_plugin_page_register_cmd_print_check, NULL, NULL, NULL },
302  { "EditCutAction", gnc_plugin_page_register_cmd_cut, NULL, NULL, NULL },
303  { "EditCopyAction", gnc_plugin_page_register_cmd_copy, NULL, NULL, NULL },
304  { "EditPasteAction", gnc_plugin_page_register_cmd_paste, NULL, NULL, NULL },
305  { "EditEditAccountAction", gnc_plugin_page_register_cmd_edit_account, NULL, NULL, NULL },
306  { "EditFindAccountAction", gnc_plugin_page_register_cmd_find_account, NULL, NULL, NULL },
307  { "EditFindTransactionsAction", gnc_plugin_page_register_cmd_find_transactions, NULL, NULL, NULL },
308  { "EditTaxOptionsAction", gnc_plugin_page_register_cmd_edit_tax_options, NULL, NULL, NULL },
309  { "CutTransactionAction", gnc_plugin_page_register_cmd_cut_transaction, NULL, NULL, NULL },
310  { "CopyTransactionAction", gnc_plugin_page_register_cmd_copy_transaction, NULL, NULL, NULL },
311  { "PasteTransactionAction", gnc_plugin_page_register_cmd_paste_transaction, NULL, NULL, NULL },
312  { "DuplicateTransactionAction", gnc_plugin_page_register_cmd_duplicate_transaction, NULL, NULL, NULL },
313  { "DeleteTransactionAction", gnc_plugin_page_register_cmd_delete_transaction, NULL, NULL, NULL },
314  { "RemoveTransactionSplitsAction", gnc_plugin_page_register_cmd_reinitialize_transaction, NULL, NULL, NULL },
315  { "RecordTransactionAction", gnc_plugin_page_register_cmd_enter_transaction, NULL, NULL, NULL },
316  { "CancelTransactionAction", gnc_plugin_page_register_cmd_cancel_transaction, NULL, NULL, NULL },
317  { "VoidTransactionAction", gnc_plugin_page_register_cmd_void_transaction, NULL, NULL, NULL },
318  { "UnvoidTransactionAction", gnc_plugin_page_register_cmd_unvoid_transaction, NULL, NULL, NULL },
319  { "ReverseTransactionAction", gnc_plugin_page_register_cmd_reverse_transaction, NULL, NULL, NULL },
320  { "LinkTransactionAction", gnc_plugin_page_register_cmd_linked_transaction, NULL, NULL, NULL },
321  { "LinkedTransactionOpenAction", gnc_plugin_page_register_cmd_linked_transaction_open, NULL, NULL, NULL },
322  { "JumpLinkedInvoiceAction", gnc_plugin_page_register_cmd_jump_linked_invoice, NULL, NULL, NULL },
323  { "ViewSortByAction", gnc_plugin_page_register_cmd_view_sort_by, NULL, NULL, NULL },
324  { "ViewFilterByAction", gnc_plugin_page_register_cmd_view_filter_by, NULL, NULL, NULL },
325  { "ViewRefreshAction", gnc_plugin_page_register_cmd_reload, NULL, NULL, NULL },
326  { "ActionsTransferAction", gnc_plugin_page_register_cmd_transfer, NULL, NULL, NULL },
327  { "ActionsReconcileAction", gnc_plugin_page_register_cmd_reconcile, NULL, NULL, NULL },
328  { "ActionsAutoClearAction", gnc_plugin_page_register_cmd_autoclear, NULL, NULL, NULL },
329  { "ActionsStockAssistantAction", gnc_plugin_page_register_cmd_stock_assistant, NULL, NULL, NULL },
330  { "ActionsStockSplitAction", gnc_plugin_page_register_cmd_stock_split, NULL, NULL, NULL },
331  { "ActionsLotsAction", gnc_plugin_page_register_cmd_lots, NULL, NULL, NULL },
332  { "BlankTransactionAction", gnc_plugin_page_register_cmd_blank_transaction, NULL, NULL, NULL },
333  { "GotoDateAction", gnc_plugin_page_register_cmd_goto_date, NULL, NULL, NULL },
334  { "EditExchangeRateAction", gnc_plugin_page_register_cmd_exchange_rate, NULL, NULL, NULL },
335  { "JumpTransactionAction", gnc_plugin_page_register_cmd_jump, NULL, NULL, NULL },
336  { "ScheduleTransactionAction", gnc_plugin_page_register_cmd_schedule, NULL, NULL, NULL },
337  { "ScrubAllAction", gnc_plugin_page_register_cmd_scrub_all, NULL, NULL, NULL },
338  { "ScrubCurrentAction", gnc_plugin_page_register_cmd_scrub_current, NULL, NULL, NULL },
339  { "ReportsAccountReportAction", gnc_plugin_page_register_cmd_account_report, NULL, NULL, NULL },
340  { "ReportsAcctTransReportAction", gnc_plugin_page_register_cmd_transaction_report, NULL, NULL, NULL },
341 
342  { "ViewStyleDoubleLineAction", gnc_plugin_page_register_cmd_style_double_line, NULL, "false", NULL },
343  { "SplitTransactionAction", gnc_plugin_page_register_cmd_expand_transaction, NULL, "false", NULL },
344  { "ViewStyleRadioAction", gnc_plugin_page_register_cmd_style_changed, "i", "@i 0", NULL },
345 };
346 static guint gnc_plugin_page_register_n_actions = G_N_ELEMENTS(gnc_plugin_page_register_actions);
347 
349 static const gchar *gnc_plugin_load_ui_items [] =
350 {
351  "FilePlaceholder3",
352  "EditPlaceholder1",
353  "EditPlaceholder2",
354  "EditPlaceholder3",
355  "EditPlaceholder5",
356  "ViewPlaceholder1",
357  "ViewPlaceholder2",
358  "ViewPlaceholder3",
359  "ViewPlaceholder4",
360  "TransPlaceholder0",
361  "TransPlaceholder1",
362  "TransPlaceholder2",
363  "TransPlaceholder3",
364  "TransPlaceholder4",
365  "ActionsPlaceholder4",
366  "ActionsPlaceholder5",
367  "ActionsPlaceholder6",
368  "ReportsPlaceholder1",
369  NULL,
370 };
371 
374 static const gchar* actions_requiring_account[] =
375 {
376  "EditEditAccountAction",
377  "ActionsReconcileAction",
378  "ActionsAutoClearAction",
379  "ActionsLotsAction",
380  NULL
381 };
382 
383 static const gchar* actions_requiring_priced_account[] =
384 {
385  "ActionsStockAssistantAction",
386  NULL
387 };
388 
390 static GncToolBarShortNames toolbar_labels[] =
391 {
392  { "ActionsTransferAction", N_ ("Transfer") },
393  { "RecordTransactionAction", N_ ("Enter") },
394  { "CancelTransactionAction", N_ ("Cancel") },
395  { "DeleteTransactionAction", N_ ("Delete") },
396  { "DuplicateTransactionAction", N_ ("Duplicate") },
397  { "SplitTransactionAction",
398  /* Translators: This is the label of a toolbar button. So keep it short. */
399  N_ ("Show Splits") },
400  { "JumpTransactionAction", N_ ("Jump") },
401  { "ScheduleTransactionAction", N_ ("Schedule") },
402  { "BlankTransactionAction", N_ ("Blank") },
403  { "ActionsReconcileAction", N_ ("Reconcile") },
404  { "ActionsStockAssistantAction", N_ ("Stock Assistant") },
405  { NULL, NULL },
406 };
407 
409 {
410  const char* action_name;
411  int value;
412  GtkWidget* widget;
413 };
414 
415 static struct status_action status_actions[] =
416 {
417  { "filter_status_reconciled", CLEARED_RECONCILED, NULL },
418  { "filter_status_cleared", CLEARED_CLEARED, NULL },
419  { "filter_status_voided", CLEARED_VOIDED, NULL },
420  { "filter_status_frozen", CLEARED_FROZEN, NULL },
421  { "filter_status_unreconciled", CLEARED_NO, NULL },
422  { NULL, 0, NULL },
423 };
424 
425 #define CLEARED_VALUE "cleared_value"
426 #define DEFAULT_FILTER "0x001f"
427 #define DEFAULT_SORT_ORDER "BY_STANDARD"
428 
429 /************************************************************/
430 /* Data Structures */
431 /************************************************************/
432 
434 {
435  GNCLedgerDisplay* ledger;
436  GNCSplitReg* gsr;
437 
438  GtkWidget* widget;
439 
440  gint event_handler_id;
441  gint component_manager_id;
442  GncGUID key; /* The guid of the Account we're watching */
443 
444  gint lines_default;
445  gboolean read_only;
446  gboolean page_focus;
447  gboolean enable_refresh; // used to reduce ledger display refreshes
448  Query* search_query; // saved search query for comparison
449  Query* filter_query; // saved filter query for comparison
450 
451  struct
452  {
453  GtkWidget* dialog;
454  GtkWidget* num_radio;
455  GtkWidget* act_radio;
456  SortType original_sort_type;
457  gboolean original_save_order;
458  gboolean save_order;
459  gboolean reverse_order;
460  gboolean original_reverse_order;
461  } sd;
462 
463  struct
464  {
465  GtkWidget* dialog;
466  GtkWidget* table;
467  GtkWidget* start_date_choose;
468  GtkWidget* start_date_today;
469  GtkWidget* start_date;
470  GtkWidget* end_date_choose;
471  GtkWidget* end_date_today;
472  GtkWidget* end_date;
473  GtkWidget* num_days;
474  cleared_match_t original_cleared_match;
475  cleared_match_t cleared_match;
476  time64 original_start_time;
477  time64 original_end_time;
478  time64 start_time;
479  time64 end_time;
480  gint days;
481  gint original_days;
482  gboolean original_save_filter;
483  gboolean save_filter;
484  } fd;
486 
487 G_DEFINE_TYPE_WITH_PRIVATE (GncPluginPageRegister, gnc_plugin_page_register,
488  GNC_TYPE_PLUGIN_PAGE)
489 
490 #define GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(o) \
491  ((GncPluginPageRegisterPrivate*)gnc_plugin_page_register_get_instance_private((GncPluginPageRegister*)o))
492 
493 /************************************************************/
494 /* Implementation */
495 /************************************************************/
496 
497 static GncPluginPage*
498 gnc_plugin_page_register_new_common (GNCLedgerDisplay* ledger)
499 {
500  GncPluginPageRegister* register_page;
502  GncPluginPage* plugin_page;
503  GNCSplitReg* gsr;
504  const GList* item;
505  GList* book_list;
506  gchar* label;
507  gchar* label_color;
508  QofQuery* q;
509 
510  // added for version 4.0 onwards
511  if (!gnc_features_check_used (gnc_get_current_book(), GNC_FEATURE_REG_SORT_FILTER))
512  gnc_features_set_used (gnc_get_current_book(), GNC_FEATURE_REG_SORT_FILTER);
513 
514  // added for version 4.14 onwards
515  if (!gnc_using_equity_type_opening_balance_account (gnc_get_current_book()))
516  gnc_set_use_equity_type_opening_balance_account (gnc_get_current_book());
517 
518  /* Is there an existing page? */
519  gsr = GNC_SPLIT_REG(gnc_ledger_display_get_user_data (ledger));
520  if (gsr)
521  {
522  item = gnc_gobject_tracking_get_list (GNC_PLUGIN_PAGE_REGISTER_NAME);
523  for (; item; item = g_list_next (item))
524  {
525  register_page = (GncPluginPageRegister*)item->data;
526  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (register_page);
527  if (priv->gsr == gsr)
528  return GNC_PLUGIN_PAGE (register_page);
529  }
530  }
531 
532  register_page = GNC_PLUGIN_PAGE_REGISTER(g_object_new (GNC_TYPE_PLUGIN_PAGE_REGISTER, nullptr));
533  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (register_page);
534  priv->ledger = ledger;
535  priv->key = *guid_null();
536 
537  plugin_page = GNC_PLUGIN_PAGE (register_page);
538  label = gnc_plugin_page_register_get_tab_name (plugin_page);
539  gnc_plugin_page_set_page_name (plugin_page, label);
540  g_free (label);
541 
542  label_color = gnc_plugin_page_register_get_tab_color (plugin_page);
543  gnc_plugin_page_set_page_color (plugin_page, label_color);
544  g_free (label_color);
545 
546  label = gnc_plugin_page_register_get_long_name (plugin_page);
547  gnc_plugin_page_set_page_long_name (plugin_page, label);
548  g_free (label);
549 
550  q = gnc_ledger_display_get_query (ledger);
551  book_list = qof_query_get_books (q);
552  for (item = book_list; item; item = g_list_next (item))
553  gnc_plugin_page_add_book (plugin_page, (QofBook*)item->data);
554  // Do not free the list. It is owned by the query.
555 
556  priv->component_manager_id = 0;
557  return plugin_page;
558 }
559 
560 static gpointer
561 gnc_plug_page_register_check_commodity (Account* account, void* usr_data)
562 {
563  // Check that account's commodity matches the commodity in usr_data
564  gnc_commodity* com0 = (gnc_commodity*) usr_data;
565  gnc_commodity* com1 = xaccAccountGetCommodity (account);
566  return gnc_commodity_equal (com1, com0) ? NULL : com1;
567 }
568 
570 gnc_plugin_page_register_new (Account* account, gboolean subaccounts)
571 {
572  GNCLedgerDisplay* ledger;
573  GncPluginPage* page;
575  gnc_commodity* com0;
576  gnc_commodity* com1;
577 
578  ENTER ("account=%p, subaccounts=%s", account,
579  subaccounts ? "TRUE" : "FALSE");
580 
581  com0 = gnc_account_get_currency_or_parent (account);
582  com1 = GNC_COMMODITY(gnc_account_foreach_descendant_until (account,
583  gnc_plug_page_register_check_commodity,
584  static_cast<gpointer>(com0)));
585 
586  if (subaccounts)
587  ledger = gnc_ledger_display_subaccounts (account, com1 != NULL);
588  else
589  ledger = gnc_ledger_display_simple (account);
590 
591  page = gnc_plugin_page_register_new_common (ledger);
592  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
593  priv->key = *xaccAccountGetGUID (account);
594 
595  LEAVE ("%p", page);
596  return page;
597 }
598 
601 {
602  GNCLedgerDisplay* ledger;
603 
604  ledger = gnc_ledger_display_gl();
605  return gnc_plugin_page_register_new_common (ledger);
606 }
607 
609 gnc_plugin_page_register_new_ledger (GNCLedgerDisplay* ledger)
610 {
611  return gnc_plugin_page_register_new_common (ledger);
612 }
613 
614 static void
615 gnc_plugin_page_register_class_init (GncPluginPageRegisterClass* klass)
616 {
617  GObjectClass* object_class = G_OBJECT_CLASS (klass);
618  GncPluginPageClass* gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS (klass);
619 
620  object_class->finalize = gnc_plugin_page_register_finalize;
621 
622  gnc_plugin_class->tab_icon = GNC_ICON_ACCOUNT;
623  gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_REGISTER_NAME;
624  gnc_plugin_class->create_widget = gnc_plugin_page_register_create_widget;
625  gnc_plugin_class->destroy_widget = gnc_plugin_page_register_destroy_widget;
626  gnc_plugin_class->window_changed = gnc_plugin_page_register_window_changed;
627  gnc_plugin_class->focus_page = gnc_plugin_page_register_focus;
628  gnc_plugin_class->save_page = gnc_plugin_page_register_save_page;
629  gnc_plugin_class->recreate_page = gnc_plugin_page_register_recreate_page;
630  gnc_plugin_class->update_edit_menu_actions =
631  gnc_plugin_page_register_update_edit_menu;
632  gnc_plugin_class->finish_pending = gnc_plugin_page_register_finish_pending;
633  gnc_plugin_class->focus_page_function = gnc_plugin_page_register_focus_widget;
634 
635  gnc_ui_register_account_destroy_callback (gppr_account_destroy_cb);
636 }
637 
638 static void
639 gnc_plugin_page_register_init (GncPluginPageRegister* plugin_page)
640 {
642  GncPluginPage* parent;
643  GSimpleActionGroup *simple_action_group;
644  gboolean use_new;
645 
646  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
647 
648  /* Init parent declared variables */
649  parent = GNC_PLUGIN_PAGE (plugin_page);
650  use_new = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
651  GNC_PREF_USE_NEW);
652  g_object_set (G_OBJECT (plugin_page),
653  "page-name", _ ("General Journal"),
654  "ui-description", "gnc-plugin-page-register.ui",
655  "use-new-window", use_new,
656  NULL);
657 
658  /* Create menu and toolbar information */
659  simple_action_group = gnc_plugin_page_create_action_group (parent, "GncPluginPageRegisterActions");
660  g_action_map_add_action_entries (G_ACTION_MAP(simple_action_group),
661  gnc_plugin_page_register_actions,
662  gnc_plugin_page_register_n_actions,
663  plugin_page);
664 
665  priv->lines_default = DEFAULT_LINES_AMOUNT;
666  priv->read_only = FALSE;
667  priv->fd.cleared_match = CLEARED_ALL;
668  priv->fd.days = 0;
669  priv->enable_refresh = TRUE;
670  priv->search_query = NULL;
671  priv->filter_query = NULL;
672 }
673 
674 static void
675 gnc_plugin_page_register_finalize (GObject* object)
676 {
677  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (object));
678 
679  ENTER ("object %p", object);
680 
681  G_OBJECT_CLASS (gnc_plugin_page_register_parent_class)->finalize (object);
682  LEAVE (" ");
683 }
684 
685 Account*
687 {
689  GNCLedgerDisplayType ledger_type;
690  Account* leader;
691 
692  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
693  ledger_type = gnc_ledger_display_type (priv->ledger);
694  leader = gnc_ledger_display_leader (priv->ledger);
695 
696  if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
697  return leader;
698  return NULL;
699 }
700 
701 Transaction*
703 {
705  SplitRegister* reg;
706 
707  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
708  reg = gnc_ledger_display_get_split_register (priv->ledger);
710 }
711 
716 static gboolean
717 gnc_plugin_page_register_focus_widget (GncPluginPage* register_plugin_page)
718 {
719  if (GNC_IS_PLUGIN_PAGE_REGISTER (register_plugin_page))
720  {
721  GncWindow* gnc_window = GNC_WINDOW(GNC_PLUGIN_PAGE(register_plugin_page)->window);
722  GNCSplitReg *gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE(register_plugin_page));
723 
724  if (GNC_IS_MAIN_WINDOW(GNC_PLUGIN_PAGE(register_plugin_page)->window))
725  {
726  /* Enable the Transaction menu */
727  GAction *action = gnc_main_window_find_action (GNC_MAIN_WINDOW(register_plugin_page->window), "TransactionAction");
728  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), TRUE);
729  /* Disable the Schedule menu */
730  action = gnc_main_window_find_action (GNC_MAIN_WINDOW(register_plugin_page->window), "ScheduledAction");
731  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
732 
733  gnc_main_window_update_menu_and_toolbar (GNC_MAIN_WINDOW(register_plugin_page->window),
734  register_plugin_page,
735  gnc_plugin_load_ui_items);
736  }
737  else
738  {
739  GtkWidget *toolbar = gnc_window_get_toolbar (gnc_window);
740  GtkWidget *menubar = gnc_window_get_menubar (gnc_window);
741  GMenuModel *menubar_model = gnc_window_get_menubar_model (gnc_window);
742  GtkWidget *statusbar = gnc_window_get_statusbar (gnc_window);
743 
744  // add tooltip redirect call backs
745  gnc_plugin_add_toolbar_tooltip_callbacks (toolbar, statusbar);
746  gnc_plugin_add_menu_tooltip_callbacks (menubar, menubar_model, statusbar);
747  }
748 
749  // setup any short toolbar names
750  gnc_plugin_init_short_names (gnc_window_get_toolbar (gnc_window), toolbar_labels);
751 
752  gnc_plugin_page_register_ui_update (NULL, GNC_PLUGIN_PAGE_REGISTER(register_plugin_page));
753 
754  gnc_split_reg_focus_on_sheet (gsr);
755  }
756  return FALSE;
757 }
758 
759 /* This is the list of actions which are switched inactive in a read-only book. */
760 static const char* readonly_inactive_actions[] =
761 {
762  "EditCutAction",
763  "EditPasteAction",
764  "CutTransactionAction",
765  "PasteTransactionAction",
766  "DuplicateTransactionAction",
767  "DeleteTransactionAction",
768  "RemoveTransactionSplitsAction",
769  "RecordTransactionAction",
770  "CancelTransactionAction",
771  "UnvoidTransactionAction",
772  "VoidTransactionAction",
773  "ReverseTransactionAction",
774  "ActionsTransferAction",
775  "ActionsReconcileAction",
776  "ActionsStockSplitAction",
777  "ScheduleTransactionAction",
778  "ScrubAllAction",
779  "ScrubCurrentAction",
780  "LinkTransactionAction",
781  NULL
782 };
783 
784 /* This is the list of actions whose text needs to be changed based on whether */
785 /* the current cursor class is transaction or split. */
786 static const char* tran_vs_split_actions[] =
787 {
788  "CutTransactionAction",
789  "CopyTransactionAction",
790  "PasteTransactionAction",
791  "DuplicateTransactionAction",
792  "DeleteTransactionAction",
793  NULL
794 };
795 
796 /* This is the list of labels for when the current cursor class is transaction. */
797 static const char* tran_action_labels[] =
798 {
799  CUT_TRANSACTION_LABEL,
800  COPY_TRANSACTION_LABEL,
801  PASTE_TRANSACTION_LABEL,
802  DUPLICATE_TRANSACTION_LABEL,
803  DELETE_TRANSACTION_LABEL,
804  NULL
805 };
806 
807 /* This is the list of tooltips for when the current cursor class is transaction. */
808 static const char* tran_action_tips[] =
809 {
810  CUT_TRANSACTION_TIP,
811  COPY_TRANSACTION_TIP,
812  PASTE_TRANSACTION_TIP,
813  DUPLICATE_TRANSACTION_TIP,
814  DELETE_TRANSACTION_TIP,
815  NULL
816 };
817 
818 /* This is the list of labels for when the current cursor class is split. */
819 static const char* split_action_labels[] =
820 {
821  CUT_SPLIT_LABEL,
822  COPY_SPLIT_LABEL,
823  PASTE_SPLIT_LABEL,
824  DUPLICATE_SPLIT_LABEL,
825  DELETE_SPLIT_LABEL,
826  NULL
827 };
828 
829 /* This is the list of tooltips for when the current cursor class is split. */
830 static const char* split_action_tips[] =
831 {
832  CUT_SPLIT_TIP,
833  COPY_SPLIT_TIP,
834  PASTE_SPLIT_TIP,
835  DUPLICATE_SPLIT_TIP,
836  DELETE_SPLIT_TIP,
837  NULL
838 };
839 
840 static std::vector<GncInvoice*>
841 invoices_from_transaction (const Transaction* trans)
842 {
843  std::vector<GncInvoice*> rv;
844 
845  g_return_val_if_fail (GNC_IS_TRANSACTION (trans), rv);
846 
847  for (auto node = xaccTransGetSplitList (trans); node; node = g_list_next (node))
848  {
849  auto split = GNC_SPLIT(node->data);
850  auto account = xaccSplitGetAccount (split);
851  if (!account || !xaccAccountIsAPARType(xaccAccountGetType(account)))
852  continue;
853  auto inv = invoice_from_split (split);
854  if (inv)
855  rv.push_back (inv);
856  }
857  return rv;
858 }
859 
860 static void
861 gnc_plugin_page_register_ui_update (gpointer various,
862  GncPluginPageRegister* page)
863 {
865  SplitRegister* reg;
866  GAction* action;
867  GNCLedgerDisplayType ledger_type;
868  gboolean expanded, voided, read_only = FALSE, read_only_reg = FALSE;
869  Transaction* trans;
870  CursorClass cursor_class;
871  const char* uri;
872  Account *account;
873  GncWindow* gnc_window = GNC_WINDOW(GNC_PLUGIN_PAGE(page)->window);
874 
875  /* Set 'Split Transaction' */
876  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
877  reg = gnc_ledger_display_get_split_register (priv->ledger);
878  cursor_class = gnc_split_register_get_current_cursor_class (reg);
880 
881  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "SplitTransactionAction");
882  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), reg->style == REG_STYLE_LEDGER);
883 
884  /* Set "style" radio button */
885  ledger_type = gnc_ledger_display_type (priv->ledger);
886  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "ViewStyleRadioAction");
887 
888  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), ledger_type != LD_GL);
889  g_action_change_state (G_ACTION(action), g_variant_new_int32 (reg->style));
890 
891  /* Set double line */
892  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "ViewStyleDoubleLineAction");
893  g_action_change_state (G_ACTION(action), g_variant_new_boolean (reg->use_double_line));
894 
895  /* Split Expand */
896  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "SplitTransactionAction");
897  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), reg->style == REG_STYLE_LEDGER);
898 
899  g_signal_handlers_block_by_func (action, (gpointer)gnc_plugin_page_register_cmd_expand_transaction, page);
900  g_action_change_state (G_ACTION(action), g_variant_new_boolean (expanded));
901  g_signal_handlers_unblock_by_func (action, (gpointer)gnc_plugin_page_register_cmd_expand_transaction, page);
902 
903  account = gnc_plugin_page_register_get_account (page);
904 
905  /* Done like this as the register can be displayed in embedded window */
906  if (GNC_IS_MAIN_WINDOW(GNC_PLUGIN_PAGE(page)->window))
907  {
908  /* Enable the FilePrintAction */
909  action = gnc_main_window_find_action (GNC_MAIN_WINDOW(GNC_PLUGIN_PAGE(page)->window), "FilePrintAction");
910  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), TRUE);
911 
912  /* Set the vis of the StockAssistant */
913  gnc_main_window_set_vis_of_items_by_action (GNC_MAIN_WINDOW(GNC_PLUGIN_PAGE(page)->window),
914  actions_requiring_priced_account,
915  account &&
916  xaccAccountIsPriced (account));
917  }
918 
919  /* If we are in a readonly book, or possibly a place holder
920  * account register make any modifying action inactive */
921  if (qof_book_is_readonly (gnc_get_current_book()) ||
922  gnc_split_reg_get_read_only (priv->gsr))
923  read_only_reg = TRUE;
924 
925  gnc_plugin_set_actions_enabled (G_ACTION_MAP(gnc_plugin_page_get_action_group (GNC_PLUGIN_PAGE(page))),
926  actions_requiring_account,
927  !read_only_reg && account != NULL);
928 
929  gnc_plugin_set_actions_enabled (G_ACTION_MAP(gnc_plugin_page_get_action_group (GNC_PLUGIN_PAGE(page))),
930  actions_requiring_priced_account,
931  account && xaccAccountIsPriced (account));
932 
933  /* Set available actions based on read only */
935 
936  if (cursor_class == CURSOR_CLASS_SPLIT)
937  {
938  if (GNC_IS_MAIN_WINDOW(GNC_PLUGIN_PAGE(page)->window))
939  gnc_plugin_page_set_menu_popup_qualifier (GNC_PLUGIN_PAGE(page), "split");
940  else
941  gnc_plugin_page_set_menu_popup_qualifier (GNC_PLUGIN_PAGE(page), "split-sx");
942  }
943  else
944  {
945  if (GNC_IS_MAIN_WINDOW(GNC_PLUGIN_PAGE(page)->window))
946  gnc_plugin_page_set_menu_popup_qualifier (GNC_PLUGIN_PAGE(page), "trans");
947  else
948  gnc_plugin_page_set_menu_popup_qualifier (GNC_PLUGIN_PAGE(page), "trans-sx");
949  }
950 
951  /* If the register is not read only, make any modifying action active
952  * to start with */
953  if (!read_only_reg)
954  {
955  const char** iter;
956  for (iter = readonly_inactive_actions; *iter; ++iter)
957  {
958  /* Set the action's sensitivity */
959  GAction* action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), *iter);
960  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), TRUE);
961  }
962  main_window_update_page_set_read_only_icon (GNC_PLUGIN_PAGE(page), FALSE);
963 
964  if (trans)
965  read_only = xaccTransIsReadonlyByPostedDate (trans);
966 
967  voided = xaccTransHasSplitsInState (trans, VREC);
968 
969  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
970  "CutTransactionAction");
971  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !read_only & !voided);
972 
973  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
974  "PasteTransactionAction");
975  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !read_only & !voided);
976 
977  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
978  "DeleteTransactionAction");
979  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !read_only & !voided);
980 
981  if (cursor_class == CURSOR_CLASS_SPLIT)
982  {
983  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
984  "DuplicateTransactionAction");
985  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !read_only & !voided);
986  }
987 
988  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
989  "RemoveTransactionSplitsAction");
990  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !read_only & !voided);
991 
992  /* Set 'Void' and 'Unvoid' */
993  if (read_only)
994  voided = TRUE;
995 
996  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
997  "VoidTransactionAction");
998  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !voided);
999 
1000  if (read_only)
1001  voided = FALSE;
1002 
1003  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
1004  "UnvoidTransactionAction");
1005  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), voided);
1006  }
1007 
1008  /* Set 'Open and Remove Linked Documents' */
1009  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
1010  "LinkedTransactionOpenAction");
1011  if (trans)
1012  {
1013  uri = xaccTransGetDocLink (trans);
1014  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), (uri ? TRUE:FALSE));
1015  }
1016  /* Set 'ExecAssociatedInvoice'
1017  We can determine an invoice from a txn if either
1018  - it is an invoice transaction
1019  - it has splits with an invoice associated with it
1020  */
1021  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
1022  "JumpLinkedInvoiceAction");
1023  if (trans)
1024  {
1025  auto invoices = invoices_from_transaction (trans);
1026  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !invoices.empty());
1027  }
1028 
1029  gnc_plugin_business_split_reg_ui_update (GNC_PLUGIN_PAGE(page));
1030 
1031  // Transaction/Split paste action
1032  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
1033  "PasteTransactionAction");
1034  g_simple_action_set_enabled (G_SIMPLE_ACTION(action),
1036 
1037  /* If we are read only, make any modifying action inactive */
1038  if (read_only_reg)
1039  {
1040  const char** iter;
1041  for (iter = readonly_inactive_actions; *iter; ++iter)
1042  {
1043  /* Set the action's sensitivity */
1044  GAction* action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), *iter);
1045  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
1046  }
1047  main_window_update_page_set_read_only_icon (GNC_PLUGIN_PAGE(page), TRUE);
1048  }
1049 
1050  /* Modifying action descriptions based on cursor class */
1051  {
1052  GncMenuModelSearch *gsm = g_new0 (GncMenuModelSearch, 1);
1053  gboolean found = FALSE;
1054  const char** iter, **label_iter, **tooltip_iter;
1055  gboolean curr_label_trans = FALSE;
1056  iter = tran_vs_split_actions;
1057  label_iter = tran_action_labels;
1058 
1059  gsm->search_action_label = NULL;
1060  gsm->search_action_name = *iter;
1061  gsm->search_action_target = NULL;
1062 
1063  found = gnc_menubar_model_find_item (gnc_window_get_menubar_model (gnc_window), gsm);
1064 
1065  PINFO("Test for action '%s', found is %d, iter label is '%s'", *iter, found, _(*label_iter));
1066 
1067  if (!found)
1068  {
1069  g_free (gsm);
1070  return;
1071  }
1072 
1073  if (g_strcmp0 (gsm->search_action_label, _(*label_iter)) == 0)
1074  curr_label_trans = TRUE;
1075 
1076  g_free (gsm);
1077 
1078  if ((cursor_class == CURSOR_CLASS_SPLIT) && curr_label_trans)
1079  {
1080  gboolean found = FALSE;
1081  label_iter = split_action_labels;
1082  tooltip_iter = split_action_tips;
1083  for (iter = tran_vs_split_actions; *iter; ++iter)
1084  {
1085  /* Adjust the action's label and tooltip */
1086  found = gnc_menubar_model_update_item (gnc_window_get_menubar_model (gnc_window),
1087  *iter, NULL, _(*label_iter), NULL, _(*tooltip_iter));
1088 
1089  PINFO("split model_item action '%s', found is %d, iter label is '%s'",
1090  *iter, found, _(*label_iter));
1091 
1092  ++label_iter;
1093  ++tooltip_iter;
1094  }
1095  }
1096  else if ((cursor_class == CURSOR_CLASS_TRANS) && !curr_label_trans)
1097  {
1098  gboolean found = FALSE;
1099  label_iter = tran_action_labels;
1100  tooltip_iter = tran_action_tips;
1101  for (iter = tran_vs_split_actions; *iter; ++iter)
1102  {
1103  /* Adjust the action's label and tooltip */
1104  found = gnc_menubar_model_update_item (gnc_window_get_menubar_model (gnc_window),
1105  *iter, NULL, _(*label_iter), NULL, _(*tooltip_iter));
1106 
1107  PINFO("trans model_item action '%s', found is %d, iter label is '%s'",
1108  *iter, found, _(*label_iter));
1109 
1110  ++label_iter;
1111  ++tooltip_iter;
1112  }
1113  }
1114  // now add the callbacks to the replaced menu items.
1115  gnc_plugin_add_menu_tooltip_callbacks (gnc_window_get_menubar (gnc_window),
1116  gnc_window_get_menubar_model (gnc_window),
1117  gnc_window_get_statusbar (gnc_window));
1118 
1119  // need to add any accelerator keys, default or user added
1120  gnc_add_accelerator_keys_for_menu (gnc_window_get_menubar (gnc_window),
1121  gnc_window_get_menubar_model (gnc_window),
1122  gnc_window_get_accel_group (gnc_window));
1123  }
1124 }
1125 
1126 static void
1127 gnc_plugin_page_register_ui_initial_state (GncPluginPageRegister* page)
1128 {
1130  GSimpleActionGroup *simple_action_group;
1131  GAction *action;
1132  Account* account;
1133  SplitRegister* reg;
1134  GNCLedgerDisplayType ledger_type;
1135  gboolean is_readwrite = !qof_book_is_readonly (gnc_get_current_book());
1136 
1137  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1138  account = gnc_plugin_page_register_get_account (page);
1139 
1140  /* Get the action group */
1141  simple_action_group = gnc_plugin_page_get_action_group (GNC_PLUGIN_PAGE(page));
1142  g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP(simple_action_group));
1143 
1144  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), actions_requiring_account,
1145  is_readwrite && account != NULL);
1146 
1147  /* Set "style" radio button */
1148  ledger_type = gnc_ledger_display_type (priv->ledger);
1149  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "ViewStyleRadioAction");
1150  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), ledger_type == LD_SINGLE);
1151 
1152  reg = gnc_ledger_display_get_split_register (priv->ledger);
1153 
1154  g_signal_handlers_block_by_func (action,
1155  (gpointer)gnc_plugin_page_register_cmd_style_changed, page);
1156  g_action_change_state (G_ACTION(action), g_variant_new_int32 (reg->style));
1157  g_signal_handlers_unblock_by_func (action,
1158  (gpointer)gnc_plugin_page_register_cmd_style_changed, page);
1159 
1160  /* Set "double line" toggle button */
1161  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "ViewStyleDoubleLineAction");
1162  g_signal_handlers_block_by_func (action,
1163  (gpointer)gnc_plugin_page_register_cmd_style_double_line, page);
1164  g_action_change_state (G_ACTION(action), g_variant_new_boolean (reg->use_double_line));
1165  g_signal_handlers_unblock_by_func (action,
1166  (gpointer)gnc_plugin_page_register_cmd_style_double_line, page);
1167 }
1168 
1169 /* Virtual Functions */
1170 
1171 static const gchar*
1172 get_filter_default_num_of_days (GNCLedgerDisplayType ledger_type)
1173 {
1174  if (ledger_type == LD_GL)
1175  return DEFAULT_FILTER_NUM_DAYS_GL;
1176  else
1177  return "0";
1178 }
1179 
1180 /* For setting the focus on a register page, the default gnc_plugin
1181  * function for 'focus_page' is overridden so that the page focus
1182  * can be conditionally set. This is to allow for enabling the setting
1183  * of the sheet focus only when the page is the current one.
1184  */
1185 static void
1186 gnc_plugin_page_register_focus (GncPluginPage* plugin_page,
1187  gboolean on_current_page)
1188 {
1189  GncPluginPageRegister* page;
1191  GNCSplitReg* gsr;
1192 
1193  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
1194 
1195  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1196  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1197 
1198  gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE (plugin_page));
1199 
1200  if (on_current_page)
1201  {
1202  priv->page_focus = TRUE;
1203 
1204  // Chain up to use parent version of 'focus_page' which will
1205  // use an idle_add as the page changed signal is emitted multiple times.
1206  GNC_PLUGIN_PAGE_CLASS (gnc_plugin_page_register_parent_class)->focus_page (plugin_page, TRUE);
1207  }
1208  else
1209  priv->page_focus = FALSE;
1210 
1211  // set the sheet focus setting
1212  gnc_split_reg_set_sheet_focus (gsr, priv->page_focus);
1213 
1214  gnc_ledger_display_set_focus (priv->ledger, priv->page_focus);
1215 }
1216 
1217 static GtkWidget*
1218 gnc_plugin_page_register_create_widget (GncPluginPage* plugin_page)
1219 {
1220  GncPluginPageRegister* page;
1222  GNCLedgerDisplayType ledger_type;
1223  GncWindow* gnc_window;
1224  guint numRows;
1225  GtkWidget* gsr;
1226  SplitRegister* reg;
1227  Account* acct;
1228  gchar* order;
1229  int filter_changed = 0;
1230  gboolean create_new_page = FALSE;
1231 
1232  ENTER ("page %p", plugin_page);
1233  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1234  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1235 
1236  if (priv->widget != NULL)
1237  {
1238  LEAVE ("existing widget %p", priv->widget);
1239  return priv->widget;
1240  }
1241 
1242  priv->widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1243  gtk_box_set_homogeneous (GTK_BOX (priv->widget), FALSE);
1244  gtk_widget_show (priv->widget);
1245 
1246  // Set the name for this widget so it can be easily manipulated with css
1247  gtk_widget_set_name (GTK_WIDGET(priv->widget), "gnc-id-register-page");
1248 
1249  numRows = priv->lines_default;
1250  numRows = MIN (numRows, DEFAULT_LINES_AMOUNT);
1251 
1252  gnc_window = GNC_WINDOW(GNC_PLUGIN_PAGE(page)->window);
1253  gsr = gnc_split_reg_new (priv->ledger,
1254  gnc_window_get_gtk_window (gnc_window),
1255  numRows, priv->read_only);
1256  priv->gsr = (GNCSplitReg *)gsr;
1257  g_object_ref(gsr);
1258 
1259  gtk_widget_show (gsr);
1260  gtk_box_pack_start (GTK_BOX (priv->widget), gsr, TRUE, TRUE, 0);
1261 
1262  g_signal_connect (G_OBJECT (gsr), "help-changed",
1263  G_CALLBACK (gnc_plugin_page_help_changed_cb),
1264  page);
1265 
1266  g_signal_connect (G_OBJECT (gsr), "show-popup-menu",
1267  G_CALLBACK (gnc_plugin_page_popup_menu_cb),
1268  page);
1269 
1270  reg = gnc_ledger_display_get_split_register (priv->ledger);
1271  gnc_split_register_config (reg, reg->type, reg->style,
1272  reg->use_double_line);
1273 
1274  gnc_plugin_page_register_ui_initial_state (page);
1275  gnc_plugin_page_register_ui_update (NULL, page);
1276 
1277  ledger_type = gnc_ledger_display_type (priv->ledger);
1278 
1279  {
1280  gchar** filter;
1281  gchar* filter_str;
1282  guint filtersize = 0;
1283  /* Set the sort order for the split register and status of save order button */
1284  priv->sd.save_order = FALSE;
1285  order = gnc_plugin_page_register_get_sort_order (plugin_page);
1286 
1287  PINFO ("Loaded Sort order is %s", order);
1288 
1289  gnc_split_reg_set_sort_type (priv->gsr, SortTypefromString (order));
1290 
1291  if (order && (g_strcmp0 (order, DEFAULT_SORT_ORDER) != 0))
1292  priv->sd.save_order = TRUE;
1293 
1294  priv->sd.original_save_order = priv->sd.save_order;
1295  g_free (order);
1296 
1297  priv->sd.reverse_order = gnc_plugin_page_register_get_sort_reversed (
1298  plugin_page);
1299  gnc_split_reg_set_sort_reversed (priv->gsr, priv->sd.reverse_order, FALSE);
1300  if (priv->sd.reverse_order)
1301  priv->sd.save_order = TRUE;
1302 
1303  priv->sd.original_reverse_order = priv->sd.reverse_order;
1304 
1305  /* Set the filter for the split register and status of save filter button */
1306  priv->fd.save_filter = FALSE;
1307 
1308  filter_str = gnc_plugin_page_register_get_filter (plugin_page);
1309  filter = g_strsplit (filter_str, ",", -1);
1310  filtersize = g_strv_length (filter);
1311  g_free (filter_str);
1312 
1313  PINFO ("Loaded Filter Status is %s", filter[0]);
1314 
1315  priv->fd.cleared_match = (cleared_match_t)g_ascii_strtoll (filter[0], NULL, 16);
1316 
1317  if (filtersize > 0 && (g_strcmp0 (filter[0], DEFAULT_FILTER) != 0))
1318  filter_changed = filter_changed + 1;
1319 
1320  if (filtersize > 1 && (g_strcmp0 (filter[1], "0") != 0))
1321  {
1322  PINFO ("Loaded Filter Start Date is %s", filter[1]);
1323 
1324  priv->fd.start_time = gnc_plugin_page_register_filter_dmy2time (filter[1]);
1325  priv->fd.start_time = gnc_time64_get_day_start (priv->fd.start_time);
1326  filter_changed = filter_changed + 1;
1327  }
1328 
1329  if (filtersize > 2 && (g_strcmp0 (filter[2], "0") != 0))
1330  {
1331  PINFO ("Loaded Filter End Date is %s", filter[2]);
1332 
1333  priv->fd.end_time = gnc_plugin_page_register_filter_dmy2time (filter[2]);
1334  priv->fd.end_time = gnc_time64_get_day_end (priv->fd.end_time);
1335  filter_changed = filter_changed + 1;
1336  }
1337 
1338  // set the default for the number of days
1339  priv->fd.days = (gint)g_ascii_strtoll (
1340  get_filter_default_num_of_days (ledger_type), NULL, 10);
1341 
1342  if (filtersize > 3 &&
1343  (g_strcmp0 (filter[3], get_filter_default_num_of_days (ledger_type)) != 0))
1344  {
1345  PINFO ("Loaded Filter Days is %s", filter[3]);
1346 
1347  priv->fd.days = (gint)g_ascii_strtoll (filter[3], NULL, 10);
1348  filter_changed = filter_changed + 1;
1349  }
1350 
1351  if (filter_changed != 0)
1352  priv->fd.save_filter = TRUE;
1353 
1354  priv->fd.original_save_filter = priv->fd.save_filter;
1355  g_strfreev (filter);
1356  }
1357 
1358  if (ledger_type == LD_GL)
1359  {
1360  time64 start_time = 0, end_time = 0;
1361 
1362  if (reg->type == GENERAL_JOURNAL)
1363  {
1364  start_time = priv->fd.start_time;
1365  end_time = priv->fd.end_time;
1366  }
1367  else // search ledger and the like
1368  {
1369  priv->fd.days = 0;
1370  priv->fd.cleared_match = (cleared_match_t)g_ascii_strtoll (DEFAULT_FILTER, NULL, 16);
1371  gnc_split_reg_set_sort_type (priv->gsr,
1372  SortTypefromString (DEFAULT_SORT_ORDER));
1373  priv->sd.reverse_order = FALSE;
1374  priv->fd.save_filter = FALSE;
1375  priv->sd.save_order = FALSE;
1376  }
1377 
1378  priv->fd.original_days = priv->fd.days;
1379 
1380  priv->fd.original_start_time = start_time;
1381  priv->fd.start_time = start_time;
1382  priv->fd.original_end_time = end_time;
1383  priv->fd.end_time = end_time;
1384  }
1385 
1386  // if enable_refresh is TRUE, default, come from creating
1387  // new page instead of restoring
1388  if (priv->enable_refresh == TRUE)
1389  {
1390  create_new_page = TRUE;
1391  priv->enable_refresh = FALSE; // disable refresh
1392  }
1393 
1394  /* Update Query with Filter Status and Dates */
1395  gnc_ppr_update_status_query (page);
1396  gnc_ppr_update_date_query (page);
1397 
1398  /* Now do the refresh if this is a new page instead of restore */
1399  if (create_new_page)
1400  {
1401  priv->enable_refresh = TRUE;
1402  gnc_ledger_display_refresh (priv->ledger);
1403  }
1404 
1405  // Set filter tooltip for summary bar
1406  gnc_plugin_page_register_set_filter_tooltip (page);
1407 
1408  plugin_page->summarybar = gsr_create_summary_bar (priv->gsr);
1409  if (plugin_page->summarybar)
1410  {
1411  gtk_widget_show_all (plugin_page->summarybar);
1412  gtk_box_pack_start (GTK_BOX (priv->widget), plugin_page->summarybar,
1413  FALSE, FALSE, 0);
1414 
1415  gnc_plugin_page_register_summarybar_position_changed (NULL, NULL, page);
1416  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
1417  GNC_PREF_SUMMARYBAR_POSITION_TOP,
1418  (gpointer)gnc_plugin_page_register_summarybar_position_changed,
1419  page);
1420  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
1421  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
1422  (gpointer)gnc_plugin_page_register_summarybar_position_changed,
1423  page);
1424  }
1425 
1426  priv->event_handler_id = qof_event_register_handler
1427  ((QofEventHandler)gnc_plugin_page_register_event_handler, page);
1428  priv->component_manager_id =
1429  gnc_register_gui_component (GNC_PLUGIN_PAGE_REGISTER_NAME,
1430  gnc_plugin_page_register_refresh_cb,
1431  gnc_plugin_page_register_close_cb,
1432  page);
1433  gnc_gui_component_set_session (priv->component_manager_id,
1434  gnc_get_current_session());
1436  if (acct)
1437  gnc_gui_component_watch_entity (
1438  priv->component_manager_id, xaccAccountGetGUID (acct),
1439  QOF_EVENT_DESTROY | QOF_EVENT_MODIFY);
1440 
1441  gnc_split_reg_set_moved_cb
1442  (priv->gsr, (GFunc)gnc_plugin_page_register_ui_update, page);
1443 
1444  g_signal_connect (G_OBJECT (plugin_page), "inserted",
1445  G_CALLBACK (gnc_plugin_page_inserted_cb),
1446  NULL);
1447 
1448  /* DRH - Probably lots of other stuff from regWindowLedger should end up here. */
1449  LEAVE (" ");
1450  return priv->widget;
1451 }
1452 
1453 static void
1454 gnc_plugin_page_register_destroy_widget (GncPluginPage* plugin_page)
1455 {
1456  GncPluginPageRegister* page;
1458 
1459  ENTER ("page %p", plugin_page);
1460  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1461  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
1462 
1463  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
1464  GNC_PREF_SUMMARYBAR_POSITION_TOP,
1465  (gpointer)gnc_plugin_page_register_summarybar_position_changed,
1466  page);
1467  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
1468  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
1469  (gpointer)gnc_plugin_page_register_summarybar_position_changed,
1470  page);
1471 
1472  // Remove the page_changed signal callback
1473  gnc_plugin_page_disconnect_page_changed (GNC_PLUGIN_PAGE (plugin_page));
1474 
1475  // Remove the page focus idle function if present
1476  g_idle_remove_by_data (GNC_PLUGIN_PAGE_REGISTER (plugin_page));
1477 
1478  if (priv->widget == NULL)
1479  return;
1480 
1481  if (priv->component_manager_id)
1482  {
1483  gnc_unregister_gui_component (priv->component_manager_id);
1484  priv->component_manager_id = 0;
1485  }
1486 
1487  if (priv->event_handler_id)
1488  {
1489  qof_event_unregister_handler (priv->event_handler_id);
1490  priv->event_handler_id = 0;
1491  }
1492 
1493  if (priv->sd.dialog)
1494  {
1495  gtk_widget_destroy (priv->sd.dialog);
1496  memset (&priv->sd, 0, sizeof (priv->sd));
1497  }
1498 
1499  if (priv->fd.dialog)
1500  {
1501  gtk_widget_destroy (priv->fd.dialog);
1502  memset (&priv->fd, 0, sizeof (priv->fd));
1503  }
1504 
1505  qof_query_destroy (priv->search_query);
1506  qof_query_destroy (priv->filter_query);
1507 
1508  gtk_widget_hide (priv->widget);
1509 
1510  g_object_unref(priv->widget);
1511  priv->widget = NULL;
1512 
1513  gnc_ledger_display_close (priv->ledger);
1514  priv->ledger = NULL;
1515 
1516  LEAVE (" ");
1517 }
1518 
1519 static void
1520 gnc_plugin_page_register_window_changed (GncPluginPage* plugin_page,
1521  GtkWidget* window)
1522 {
1523  GncPluginPageRegister* page;
1525 
1526  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
1527 
1528  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1529  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1530  priv->gsr->window =
1531  GTK_WIDGET (gnc_window_get_gtk_window (GNC_WINDOW (window)));
1532 }
1533 
1534 static const gchar* style_names[] =
1535 {
1536  "Ledger",
1537  "Auto Ledger",
1538  "Journal",
1539  NULL
1540 };
1541 
1542 #define KEY_REGISTER_TYPE "RegisterType"
1543 #define KEY_ACCOUNT_NAME "AccountName"
1544 #define KEY_ACCOUNT_GUID "AccountGuid"
1545 #define KEY_REGISTER_STYLE "RegisterStyle"
1546 #define KEY_DOUBLE_LINE "DoubleLineMode"
1547 
1548 #define LABEL_ACCOUNT "Account"
1549 #define LABEL_SUBACCOUNT "SubAccount"
1550 #define LABEL_GL "GL"
1551 #define LABEL_SEARCH "Search"
1552 
1553 
1563 static void
1564 gnc_plugin_page_register_save_page (GncPluginPage* plugin_page,
1565  GKeyFile* key_file,
1566  const gchar* group_name)
1567 {
1568  GncPluginPageRegister* page;
1570  GNCLedgerDisplayType ledger_type;
1571  SplitRegister* reg;
1572  Account* leader;
1573 
1574  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
1575  g_return_if_fail (key_file != NULL);
1576  g_return_if_fail (group_name != NULL);
1577 
1578  ENTER ("page %p, key_file %p, group_name %s", plugin_page, key_file,
1579  group_name);
1580 
1581  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1582  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1583 
1584  reg = gnc_ledger_display_get_split_register (priv->ledger);
1585  ledger_type = gnc_ledger_display_type (priv->ledger);
1586  if (ledger_type > LD_GL)
1587  {
1588  LEAVE ("Unsupported ledger type");
1589  return;
1590  }
1591  if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
1592  {
1593  const gchar* label;
1594  gchar* name;
1595  gchar acct_guid[GUID_ENCODING_LENGTH + 1];
1596  label = (ledger_type == LD_SINGLE) ? LABEL_ACCOUNT : LABEL_SUBACCOUNT;
1597  leader = gnc_ledger_display_leader (priv->ledger);
1598  g_key_file_set_string (key_file, group_name, KEY_REGISTER_TYPE, label);
1599  name = gnc_account_get_full_name (leader);
1600  g_key_file_set_string (key_file, group_name, KEY_ACCOUNT_NAME, name);
1601  g_free (name);
1602  guid_to_string_buff (xaccAccountGetGUID (leader), acct_guid);
1603  g_key_file_set_string (key_file, group_name, KEY_ACCOUNT_GUID, acct_guid);
1604  }
1605  else if (reg->type == GENERAL_JOURNAL)
1606  {
1607  g_key_file_set_string (key_file, group_name, KEY_REGISTER_TYPE,
1608  LABEL_GL);
1609  }
1610  else if (reg->type == SEARCH_LEDGER)
1611  {
1612  g_key_file_set_string (key_file, group_name, KEY_REGISTER_TYPE,
1613  LABEL_SEARCH);
1614  }
1615  else
1616  {
1617  LEAVE ("Unsupported register type");
1618  return;
1619  }
1620 
1621  g_key_file_set_string (key_file, group_name, KEY_REGISTER_STYLE,
1622  style_names[reg->style]);
1623  g_key_file_set_boolean (key_file, group_name, KEY_DOUBLE_LINE,
1624  reg->use_double_line);
1625 
1626  LEAVE(" ");
1627 }
1628 
1629 
1642 static void
1643 gnc_plugin_page_register_restore_edit_menu (GncPluginPage* page,
1644  GKeyFile* key_file,
1645  const gchar* group_name)
1646 {
1647  GAction* action;
1648  GVariant *state;
1649  GError* error = NULL;
1650  gchar* style_name;
1651  gint i;
1652  gboolean use_double_line;
1653 
1654  ENTER (" ");
1655 
1656  /* Convert the style name to an index */
1657  style_name = g_key_file_get_string (key_file, group_name,
1658  KEY_REGISTER_STYLE, &error);
1659  for (i = 0 ; style_names[i]; i++)
1660  {
1661  if (g_ascii_strcasecmp (style_name, style_names[i]) == 0)
1662  {
1663  DEBUG ("Found match for style name: %s", style_name);
1664  break;
1665  }
1666  }
1667  g_free (style_name);
1668 
1669  /* Update the style menu action for this page */
1670  if (i <= REG_STYLE_JOURNAL)
1671  {
1672  DEBUG ("Setting style: %d", i);
1673  action = gnc_plugin_page_get_action (page, "ViewStyleRadioAction");
1674  g_action_activate (G_ACTION(action), g_variant_new_int32 (i));
1675  }
1676 
1677  /* Update the double line action on this page */
1678  use_double_line = g_key_file_get_boolean (key_file, group_name,
1679  KEY_DOUBLE_LINE, &error);
1680  DEBUG ("Setting double_line_mode: %d", use_double_line);
1681  action = gnc_plugin_page_get_action (page, "ViewStyleDoubleLineAction");
1682 
1683  state = g_action_get_state (G_ACTION(action));
1684 
1685  if (use_double_line != g_variant_get_boolean (state))
1686  g_action_activate (G_ACTION(action), NULL);
1687 
1688  g_variant_unref (state);
1689 
1690  LEAVE (" ");
1691 }
1692 
1693 
1703 static GncPluginPage*
1704 gnc_plugin_page_register_recreate_page (GtkWidget* window,
1705  GKeyFile* key_file,
1706  const gchar* group_name)
1707 {
1709  GncPluginPage* page;
1710  GError* error = NULL;
1711  gchar* reg_type, *acct_guid;
1712  GncGUID guid;
1713  Account* account = NULL;
1714  QofBook* book;
1715  gboolean include_subs;
1716 
1717  g_return_val_if_fail (key_file, NULL);
1718  g_return_val_if_fail (group_name, NULL);
1719  ENTER ("key_file %p, group_name %s", key_file, group_name);
1720 
1721  /* Create the new page. */
1722  reg_type = g_key_file_get_string (key_file, group_name,
1723  KEY_REGISTER_TYPE, &error);
1724  DEBUG ("Page type: %s", reg_type);
1725  if ((g_ascii_strcasecmp (reg_type, LABEL_ACCOUNT) == 0) ||
1726  (g_ascii_strcasecmp (reg_type, LABEL_SUBACCOUNT) == 0))
1727  {
1728  include_subs = (g_ascii_strcasecmp (reg_type, LABEL_SUBACCOUNT) == 0);
1729  DEBUG ("Include subs: %d", include_subs);
1730  book = qof_session_get_book (gnc_get_current_session());
1731  if (!book)
1732  {
1733  LEAVE("Session has no book");
1734  return NULL;
1735  }
1736  acct_guid = g_key_file_get_string (key_file, group_name,
1737  KEY_ACCOUNT_GUID, &error);
1738  if (string_to_guid (acct_guid, &guid)) //find account by guid
1739  {
1740  account = xaccAccountLookup (&guid, book);
1741  g_free (acct_guid);
1742  }
1743  if (account == NULL) //find account by full name
1744  {
1745  gchar* acct_name = g_key_file_get_string (key_file, group_name,
1746  KEY_ACCOUNT_NAME, &error);
1747  account = gnc_account_lookup_by_full_name (gnc_book_get_root_account (book),
1748  acct_name);
1749  g_free (acct_name);
1750  }
1751  if (account == NULL)
1752  {
1753  LEAVE ("Bad account name");
1754  g_free (reg_type);
1755  return NULL;
1756  }
1757  page = gnc_plugin_page_register_new (account, include_subs);
1758  }
1759  else if (g_ascii_strcasecmp (reg_type, LABEL_GL) == 0)
1760  {
1762  }
1763  else
1764  {
1765  LEAVE ("Bad ledger type");
1766  g_free (reg_type);
1767  return NULL;
1768  }
1769  g_free (reg_type);
1770 
1771  /* disable the refresh of the display ledger, this is for
1772  * sort/filter updates and double line/style changes */
1773  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1774  priv->enable_refresh = FALSE;
1775 
1776  /* Recreate page in given window */
1777  gnc_plugin_page_set_use_new_window (page, FALSE);
1778 
1779  /* Install it now so we can them manipulate the created widget */
1780  gnc_main_window_open_page (GNC_MAIN_WINDOW (window), page);
1781 
1782  /* Now update the page to the last state it was in */
1783  gnc_plugin_page_register_restore_edit_menu (page, key_file, group_name);
1784 
1785  /* enable the refresh */
1786  priv->enable_refresh = TRUE;
1787  LEAVE (" ");
1788  return page;
1789 }
1790 
1791 
1792 /*
1793  * Based on code from Epiphany (src/ephy-window.c)
1794  */
1795 static void
1796 gnc_plugin_page_register_update_edit_menu (GncPluginPage* page, gboolean hide)
1797 {
1799  GncPluginPageRegister* reg_page;
1800  GAction* action;
1801  gboolean can_copy = FALSE, can_cut = FALSE, can_paste = FALSE;
1802  gboolean has_selection;
1803  gboolean is_readwrite = !qof_book_is_readonly (gnc_get_current_book());
1804 
1805  reg_page = GNC_PLUGIN_PAGE_REGISTER (page);
1806  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (reg_page);
1807  has_selection = gnucash_register_has_selection (priv->gsr->reg);
1808 
1809  can_copy = has_selection;
1810  can_cut = is_readwrite && has_selection;
1811  can_paste = is_readwrite;
1812 
1813  action = gnc_plugin_page_get_action (page, "EditCopyAction");
1814  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), can_copy);
1815  action = gnc_plugin_page_get_action (page, "EditCutAction");
1816  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), can_cut);
1817  action = gnc_plugin_page_get_action (page, "EditPasteAction");
1818  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), can_paste);
1819 }
1820 
1821 static gboolean is_scrubbing = FALSE;
1822 static gboolean show_abort_verify = TRUE;
1823 
1824 static const char*
1825 check_repair_abort_YN = N_("'Check & Repair' is currently running, do you want to abort it?");
1826 
1827 static gboolean
1828 finish_scrub (GncPluginPage* page)
1829 {
1830  gboolean ret = FALSE;
1831 
1832  if (is_scrubbing)
1833  {
1834  ret = gnc_verify_dialog (GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page))),
1835  false, "%s", _(check_repair_abort_YN));
1836 
1837  show_abort_verify = FALSE;
1838 
1839  if (ret)
1840  gnc_set_abort_scrub (TRUE);
1841  }
1842  return ret;
1843 }
1844 
1845 static gboolean
1846 gnc_plugin_page_register_finish_pending (GncPluginPage* page)
1847 {
1849  GncPluginPageRegister* reg_page;
1850  SplitRegister* reg;
1851  GtkWidget* dialog, *window;
1852  gchar* name;
1853  gint response;
1854 
1855  if (is_scrubbing && show_abort_verify)
1856  {
1857  if (!finish_scrub (page))
1858  return FALSE;
1859  }
1860 
1861  reg_page = GNC_PLUGIN_PAGE_REGISTER (page);
1862  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (reg_page);
1863  reg = gnc_ledger_display_get_split_register (priv->ledger);
1864 
1865  if (!reg || !gnc_split_register_changed (reg))
1866  return TRUE;
1867 
1868  name = gnc_plugin_page_register_get_tab_name (page);
1869  window = gnc_plugin_page_get_window (page);
1870  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1871  GTK_DIALOG_DESTROY_WITH_PARENT,
1872  GTK_MESSAGE_WARNING,
1873  GTK_BUTTONS_NONE,
1874  /* Translators: %s is the name
1875  of the tab page */
1876  _ ("Save changes to %s?"), name);
1877  g_free (name);
1878  gtk_message_dialog_format_secondary_text
1879  (GTK_MESSAGE_DIALOG (dialog),
1880  "%s",
1881  _ ("This register has pending changes to a transaction. "
1882  "Would you like to save the changes to this transaction, "
1883  "discard the transaction, or cancel the operation?"));
1884  gnc_gtk_dialog_add_button (dialog, _ ("_Discard Transaction"),
1885  "edit-delete", GTK_RESPONSE_REJECT);
1886  gtk_dialog_add_button (GTK_DIALOG (dialog),
1887  _ ("_Cancel"), GTK_RESPONSE_CANCEL);
1888  gnc_gtk_dialog_add_button (dialog, _ ("_Save Transaction"),
1889  "document-save", GTK_RESPONSE_ACCEPT);
1890 
1891  response = gtk_dialog_run (GTK_DIALOG (dialog));
1892  gtk_widget_destroy (dialog);
1893 
1894  switch (response)
1895  {
1896  case GTK_RESPONSE_ACCEPT:
1897  gnc_split_register_save (reg, TRUE);
1898  return TRUE;
1899 
1900  case GTK_RESPONSE_REJECT:
1902  gnc_split_register_save (reg, TRUE);
1903  return TRUE;
1904 
1905  default:
1906  return FALSE;
1907  }
1908 }
1909 
1910 
1911 static gchar*
1912 gnc_plugin_page_register_get_tab_name (GncPluginPage* plugin_page)
1913 {
1915  GNCLedgerDisplayType ledger_type;
1916  GNCLedgerDisplay* ld;
1917  SplitRegister* reg;
1918  Account* leader;
1919 
1920  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
1921  g_strdup (_("unknown")));
1922 
1923  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
1924  ld = priv->ledger;
1926  ledger_type = gnc_ledger_display_type (ld);
1927  leader = gnc_ledger_display_leader (ld);
1928 
1929  switch (ledger_type)
1930  {
1931  case LD_SINGLE:
1932  return g_strdup (xaccAccountGetName (leader));
1933 
1934  case LD_SUBACCOUNT:
1935  return g_strdup_printf ("%s+", xaccAccountGetName (leader));
1936 
1937  case LD_GL:
1938  switch (reg->type)
1939  {
1940  case GENERAL_JOURNAL:
1941  case INCOME_LEDGER:
1942  return g_strdup (_ ("General Journal"));
1943  case PORTFOLIO_LEDGER:
1944  return g_strdup (_ ("Portfolio"));
1945  case SEARCH_LEDGER:
1946  return g_strdup (_ ("Search Results"));
1947  default:
1948  break;
1949  }
1950  break;
1951 
1952  default:
1953  break;
1954  }
1955 
1956  return g_strdup (_ ("unknown"));
1957 }
1958 
1959 static gchar*
1960 gnc_plugin_page_register_get_tab_color (GncPluginPage* plugin_page)
1961 {
1963  GNCLedgerDisplayType ledger_type;
1964  GNCLedgerDisplay* ld;
1965  Account* leader;
1966  const char* color;
1967 
1968  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
1969  g_strdup (_("unknown")));
1970 
1971  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
1972  ld = priv->ledger;
1973  ledger_type = gnc_ledger_display_type (ld);
1974  leader = gnc_ledger_display_leader (ld);
1975  color = NULL;
1976 
1977  if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
1978  color = xaccAccountGetColor (leader);
1979 
1980  return g_strdup (color ? color : "Not Set");
1981 }
1982 
1983 static void
1984 gnc_plugin_page_register_check_for_empty_group (GKeyFile *state_file,
1985  const gchar *state_section)
1986 {
1987  gsize num_keys;
1988  gchar **keys = g_key_file_get_keys (state_file, state_section, &num_keys, NULL);
1989 
1990  if (num_keys == 0)
1991  gnc_state_drop_sections_for (state_section);
1992 
1993  g_strfreev (keys);
1994 }
1995 
1996 static gchar*
1997 gnc_plugin_page_register_get_filter_gcm (GNCSplitReg *gsr)
1998 {
1999  GKeyFile* state_file = gnc_state_get_current();
2000  gchar* state_section;
2001  GError* error = NULL;
2002  char* filter = NULL;
2003 
2004  // get the filter from the .gcm file
2005  state_section = gsr_get_register_state_section (gsr);
2006  filter = g_key_file_get_string (state_file, state_section,
2007  KEY_PAGE_FILTER, &error);
2008 
2009  if (error)
2010  g_clear_error (&error);
2011  else
2012  g_strdelimit (filter, ";", ',');
2013 
2014  g_free (state_section);
2015  return filter;
2016 }
2017 
2018 static gchar*
2019 gnc_plugin_page_register_get_filter (GncPluginPage* plugin_page)
2020 {
2022  GNCLedgerDisplayType ledger_type;
2023  char* filter = NULL;
2024 
2025  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
2026  g_strdup (_("unknown")));
2027 
2028  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2029 
2030  ledger_type = gnc_ledger_display_type (priv->ledger);
2031 
2032  // load from gcm file
2033  filter = gnc_plugin_page_register_get_filter_gcm (priv->gsr);
2034 
2035  if (filter)
2036  return filter;
2037 
2038  return g_strdup_printf ("%s,%s,%s,%s", DEFAULT_FILTER,
2039  "0", "0", get_filter_default_num_of_days (ledger_type));
2040 }
2041 
2042 static void
2043 gnc_plugin_page_register_set_filter_gcm (GNCSplitReg *gsr, const gchar* filter,
2044  gchar* default_filter)
2045 {
2046  GKeyFile* state_file = gnc_state_get_current();
2047  gchar* state_section;
2048  gchar* filter_text;
2049 
2050  // save the filter to the .gcm file also
2051  state_section = gsr_get_register_state_section (gsr);
2052  if (!filter || (g_strcmp0 (filter, default_filter) == 0))
2053  {
2054  if (g_key_file_has_key (state_file, state_section, KEY_PAGE_FILTER, NULL))
2055  g_key_file_remove_key (state_file, state_section, KEY_PAGE_FILTER, NULL);
2056 
2057  gnc_plugin_page_register_check_for_empty_group (state_file, state_section);
2058  }
2059  else
2060  {
2061  filter_text = g_strdup (filter);
2062  g_strdelimit (filter_text, ",", ';'); // make it conform to .gcm file list
2063  g_key_file_set_string (state_file, state_section, KEY_PAGE_FILTER,
2064  filter_text);
2065  g_free (filter_text);
2066  }
2067  g_free (state_section);
2068 }
2069 
2070 void
2071 gnc_plugin_page_register_set_filter (GncPluginPage* plugin_page,
2072  const gchar* filter)
2073 {
2075  GNCLedgerDisplayType ledger_type;
2076  gchar* default_filter;
2077 
2078  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2079 
2080  ledger_type = gnc_ledger_display_type (priv->ledger);
2081 
2082  default_filter = g_strdup_printf ("%s,%s,%s,%s", DEFAULT_FILTER,
2083  "0", "0", get_filter_default_num_of_days (ledger_type));
2084 
2085  // save to gcm file
2086  gnc_plugin_page_register_set_filter_gcm (priv->gsr, filter, default_filter);
2087 
2088  g_free (default_filter);
2089  return;
2090 }
2091 
2092 static gchar*
2093 gnc_plugin_page_register_get_sort_order_gcm (GNCSplitReg *gsr)
2094 {
2095  GKeyFile* state_file = gnc_state_get_current();
2096  gchar* state_section;
2097  gchar* sort_text;
2098  GError* error = NULL;
2099  char* sort_order = NULL;
2100 
2101  // get the sort_order from the .gcm file
2102  state_section = gsr_get_register_state_section (gsr);
2103  sort_text = g_key_file_get_string (state_file, state_section, KEY_PAGE_SORT,
2104  &error);
2105 
2106  if (error)
2107  g_clear_error (&error);
2108  else
2109  {
2110  sort_order = g_strdup (sort_text);
2111  g_free (sort_text);
2112  }
2113  g_free (state_section);
2114  return sort_order;
2115 }
2116 
2117 static gchar*
2118 gnc_plugin_page_register_get_sort_order (GncPluginPage* plugin_page)
2119 {
2121  char* sort_order = NULL;
2122 
2123  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
2124  _ ("unknown"));
2125 
2126  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2127 
2128  // load from gcm file
2129  sort_order = gnc_plugin_page_register_get_sort_order_gcm (priv->gsr);
2130 
2131  return sort_order ? sort_order : g_strdup (DEFAULT_SORT_ORDER);
2132 }
2133 
2134 static void
2135 gnc_plugin_page_register_set_sort_order_gcm (GNCSplitReg *gsr,
2136  const gchar* sort_order)
2137 {
2138  GKeyFile* state_file = gnc_state_get_current();
2139  gchar* state_section;
2140 
2141  // save sort_order to the .gcm file also
2142  state_section = gsr_get_register_state_section (gsr);
2143  if (!sort_order || (g_strcmp0 (sort_order, DEFAULT_SORT_ORDER) == 0))
2144  {
2145  if (g_key_file_has_key (state_file, state_section, KEY_PAGE_SORT, NULL))
2146  g_key_file_remove_key (state_file, state_section, KEY_PAGE_SORT, NULL);
2147 
2148  gnc_plugin_page_register_check_for_empty_group (state_file, state_section);
2149  }
2150  else
2151  g_key_file_set_string (state_file, state_section, KEY_PAGE_SORT, sort_order);
2152 
2153  g_free (state_section);
2154 }
2155 void
2156 gnc_plugin_page_register_set_sort_order (GncPluginPage* plugin_page,
2157  const gchar* sort_order)
2158 {
2160 
2161  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2162 
2163  // save to gcm file
2164  gnc_plugin_page_register_set_sort_order_gcm (priv->gsr, sort_order);
2165 }
2166 
2167 static gboolean
2168 gnc_plugin_page_register_get_sort_reversed_gcm (GNCSplitReg *gsr)
2169 {
2170  GKeyFile* state_file = gnc_state_get_current();
2171  gchar* state_section;
2172  GError* error = NULL;
2173  gboolean sort_reversed = FALSE;
2174 
2175  // get the sort_reversed from the .gcm file
2176  state_section = gsr_get_register_state_section (gsr);
2177  sort_reversed = g_key_file_get_boolean (state_file, state_section,
2178  KEY_PAGE_SORT_REV, &error);
2179 
2180  if (error)
2181  g_clear_error (&error);
2182 
2183  g_free (state_section);
2184  return sort_reversed;
2185 }
2186 
2187 static gboolean
2188 gnc_plugin_page_register_get_sort_reversed (GncPluginPage* plugin_page)
2189 {
2191  gboolean sort_reversed = FALSE;
2192 
2193  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page), FALSE);
2194 
2195  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2196 
2197  // load from gcm file
2198  sort_reversed = gnc_plugin_page_register_get_sort_reversed_gcm (priv->gsr);
2199  return sort_reversed;
2200 }
2201 
2202 static void
2203 gnc_plugin_page_register_set_sort_reversed_gcm (GNCSplitReg *gsr,
2204  gboolean reverse_order)
2205 {
2206  GKeyFile* state_file = gnc_state_get_current();
2207  gchar* state_section;
2208 
2209  // save reverse_order to the .gcm file also
2210  state_section = gsr_get_register_state_section (gsr);
2211 
2212  if (!reverse_order)
2213  {
2214  if (g_key_file_has_key (state_file, state_section, KEY_PAGE_SORT_REV, NULL))
2215  g_key_file_remove_key (state_file, state_section, KEY_PAGE_SORT_REV, NULL);
2216 
2217  gnc_plugin_page_register_check_for_empty_group (state_file, state_section);
2218  }
2219  else
2220  g_key_file_set_boolean (state_file, state_section, KEY_PAGE_SORT_REV,
2221  reverse_order);
2222 
2223  g_free (state_section);
2224 }
2225 
2226 void
2227 gnc_plugin_page_register_set_sort_reversed (GncPluginPage* plugin_page,
2228  gboolean reverse_order)
2229 {
2231 
2232  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2233 
2234  // save to gcm file
2235  gnc_plugin_page_register_set_sort_reversed_gcm (priv->gsr, reverse_order);
2236 }
2237 
2238 static gchar*
2239 gnc_plugin_page_register_get_long_name (GncPluginPage* plugin_page)
2240 {
2242  GNCLedgerDisplayType ledger_type;
2243  GNCLedgerDisplay* ld;
2244  Account* leader;
2245 
2246  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
2247  _ ("unknown"));
2248 
2249  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2250  ld = priv->ledger;
2251  ledger_type = gnc_ledger_display_type (ld);
2252  leader = gnc_ledger_display_leader (ld);
2253 
2254  switch (ledger_type)
2255  {
2256  case LD_SINGLE:
2257  return gnc_account_get_full_name (leader);
2258 
2259  case LD_SUBACCOUNT:
2260  {
2261  gchar* account_full_name = gnc_account_get_full_name (leader);
2262  gchar* return_string = g_strdup_printf ("%s+", account_full_name);
2263  g_free ((gpointer*) account_full_name);
2264  return return_string;
2265  }
2266 
2267  default:
2268  break;
2269  }
2270 
2271  return NULL;
2272 }
2273 
2274 static void
2275 gnc_plugin_page_register_summarybar_position_changed (gpointer prefs,
2276  gchar* pref,
2277  gpointer user_data)
2278 {
2279  GncPluginPage* plugin_page;
2280  GncPluginPageRegister* page;
2282  GtkPositionType position = GTK_POS_BOTTOM;
2283 
2284  g_return_if_fail (user_data != NULL);
2285 
2286  if (!GNC_IS_PLUGIN_PAGE (user_data))
2287  return;
2288 
2289  plugin_page = GNC_PLUGIN_PAGE (user_data);
2290  page = GNC_PLUGIN_PAGE_REGISTER (user_data);
2291  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2292 
2293  if (priv == NULL)
2294  return;
2295 
2296  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL,
2297  GNC_PREF_SUMMARYBAR_POSITION_TOP))
2298  position = GTK_POS_TOP;
2299 
2300  gtk_box_reorder_child (GTK_BOX (priv->widget),
2301  plugin_page->summarybar,
2302  (position == GTK_POS_TOP ? 0 : -1));
2303 }
2304 
2310 Query*
2312 {
2313  GncPluginPageRegister* page;
2315 
2316  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page), NULL);
2317 
2318  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
2319  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2320  return gnc_ledger_display_get_query (priv->ledger);
2321 }
2322 
2323 /************************************************************/
2324 /* "Sort By" Dialog */
2325 /************************************************************/
2326 
2337 static void
2338 gnc_plugin_page_register_sort_book_option_changed (gpointer new_val,
2339  gpointer user_data)
2340 {
2342  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2343  gboolean* new_data = (gboolean*)new_val;
2344 
2345  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2346 
2347  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2348  if (*new_data)
2349  {
2350  gtk_button_set_label (GTK_BUTTON (priv->sd.num_radio),
2351  _ ("Transaction Number"));
2352  gtk_button_set_label (GTK_BUTTON (priv->sd.act_radio), _ ("Number/Action"));
2353  }
2354  else
2355  {
2356  gtk_button_set_label (GTK_BUTTON (priv->sd.num_radio), _ ("Number"));
2357  gtk_button_set_label (GTK_BUTTON (priv->sd.act_radio), _ ("Action"));
2358  }
2359  gnc_split_reg_set_sort_type_force (priv->gsr, (SortType)priv->gsr->sort_type, TRUE);
2360 }
2361 
2373 void
2375  gint response,
2376  GncPluginPageRegister* page)
2377 {
2379  GncPluginPage* plugin_page;
2380  SortType type;
2381  const gchar* order;
2382 
2383  g_return_if_fail (GTK_IS_DIALOG (dialog));
2384  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2385 
2386  ENTER (" ");
2387  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2388  plugin_page = GNC_PLUGIN_PAGE (page);
2389 
2390  if (response != GTK_RESPONSE_OK)
2391  {
2392  /* Restore the original sort order */
2393  gnc_split_reg_set_sort_reversed (priv->gsr, priv->sd.original_reverse_order,
2394  TRUE);
2395  priv->sd.reverse_order = priv->sd.original_reverse_order;
2396  gnc_split_reg_set_sort_type (priv->gsr, priv->sd.original_sort_type);
2397  priv->sd.save_order = priv->sd.original_save_order;
2398  }
2399  else
2400  {
2401  // clear the sort when unticking the save option
2402  if ((!priv->sd.save_order) && ((priv->sd.original_save_order) || (priv->sd.original_reverse_order)))
2403  {
2404  gnc_plugin_page_register_set_sort_order (plugin_page, DEFAULT_SORT_ORDER);
2405  gnc_plugin_page_register_set_sort_reversed (plugin_page, FALSE);
2406  }
2407  priv->sd.original_save_order = priv->sd.save_order;
2408 
2409  if (priv->sd.save_order)
2410  {
2411  type = gnc_split_reg_get_sort_type (priv->gsr);
2412  order = SortTypeasString (type);
2413  gnc_plugin_page_register_set_sort_order (plugin_page, order);
2414  gnc_plugin_page_register_set_sort_reversed (plugin_page,
2415  priv->sd.reverse_order);
2416  }
2417  }
2418  gnc_book_option_remove_cb (OPTION_NAME_NUM_FIELD_SOURCE,
2419  gnc_plugin_page_register_sort_book_option_changed,
2420  page);
2421  priv->sd.dialog = NULL;
2422  priv->sd.num_radio = NULL;
2423  priv->sd.act_radio = NULL;
2424  gtk_widget_destroy (GTK_WIDGET (dialog));
2425  LEAVE (" ");
2426 }
2427 
2428 
2437 void
2439  GncPluginPageRegister* page)
2440 {
2442  const gchar* name;
2443  SortType type;
2444 
2445  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
2446  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2447 
2448  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2449  name = gtk_buildable_get_name (GTK_BUILDABLE (button));
2450  ENTER ("button %s(%p), page %p", name, button, page);
2451  type = SortTypefromString (name);
2452  gnc_split_reg_set_sort_type (priv->gsr, type);
2453  LEAVE (" ");
2454 }
2455 
2456 
2465 void
2467  GncPluginPageRegister* page)
2468 {
2470 
2471  g_return_if_fail (GTK_IS_CHECK_BUTTON (button));
2472  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2473 
2474  ENTER ("Save toggle button (%p), plugin_page %p", button, page);
2475 
2476  /* Compute the new save sort order */
2477  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2478 
2479  if (gtk_toggle_button_get_active (button))
2480  priv->sd.save_order = TRUE;
2481  else
2482  priv->sd.save_order = FALSE;
2483  LEAVE (" ");
2484 }
2485 
2494 void
2496  GncPluginPageRegister* page)
2497 
2498 {
2500 
2501  g_return_if_fail (GTK_IS_CHECK_BUTTON (button));
2502  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2503 
2504  ENTER ("Reverse toggle button (%p), plugin_page %p", button, page);
2505 
2506  /* Compute the new save sort order */
2507  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2508 
2509  priv->sd.reverse_order = gtk_toggle_button_get_active (button);
2510  gnc_split_reg_set_sort_reversed (priv->gsr, priv->sd.reverse_order, TRUE);
2511  LEAVE (" ");
2512 }
2513 
2514 /************************************************************/
2515 /* "Filter By" Dialog */
2516 /************************************************************/
2517 
2518 static void
2519 gnc_ppr_update_for_search_query (GncPluginPageRegister* page)
2520 {
2522  SplitRegister* reg;
2523 
2524  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2525  reg = gnc_ledger_display_get_split_register (priv->ledger);
2526 
2527  if (reg->type == SEARCH_LEDGER)
2528  {
2529  Query* query_tmp = gnc_ledger_display_get_query (priv->ledger);
2530 
2531  // if filter_query is NULL, then the dialogue find has been run
2532  // before coming here. if query_tmp does not equal filter_query
2533  // then the dialogue find has been run again before coming here
2534  if ((priv->filter_query == NULL) ||
2535  (!qof_query_equal (query_tmp, priv->filter_query)))
2536  {
2537  qof_query_destroy (priv->search_query);
2538  priv->search_query = qof_query_copy (query_tmp);
2539  }
2540  gnc_ledger_display_set_query (priv->ledger, priv->search_query);
2541  }
2542 }
2543 
2544 
2557 static void
2558 gnc_ppr_update_status_query (GncPluginPageRegister* page)
2559 {
2561  Query* query;
2562  SplitRegister* reg;
2563 
2564  ENTER (" ");
2565  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2566  if (!priv->ledger)
2567  {
2568  LEAVE ("no ledger");
2569  return;
2570  }
2571  // check if this a search register and save query
2572  gnc_ppr_update_for_search_query (page);
2573 
2574  query = gnc_ledger_display_get_query (priv->ledger);
2575  if (!query)
2576  {
2577  LEAVE ("no query found");
2578  return;
2579  }
2580 
2581  reg = gnc_ledger_display_get_split_register (priv->ledger);
2582 
2583  /* Remove the old status match */
2584  if (reg->type != SEARCH_LEDGER)
2585  {
2586  GSList *param_list = qof_query_build_param_list (SPLIT_RECONCILE, NULL);
2587  qof_query_purge_terms (query, param_list);
2588  g_slist_free (param_list);
2589  }
2590 
2591  /* Install the new status match */
2592  if (priv->fd.cleared_match != CLEARED_ALL)
2593  xaccQueryAddClearedMatch (query, priv->fd.cleared_match, QOF_QUERY_AND);
2594 
2595  // Set filter tooltip for summary bar
2596  gnc_plugin_page_register_set_filter_tooltip (page);
2597 
2598  // clear previous filter query and save current
2599  qof_query_destroy (priv->filter_query);
2600  priv->filter_query = qof_query_copy (query);
2601 
2602  if (priv->enable_refresh)
2603  gnc_ledger_display_refresh (priv->ledger);
2604  LEAVE (" ");
2605 }
2606 
2607 
2620 static void
2621 gnc_ppr_update_date_query (GncPluginPageRegister* page)
2622 {
2624  Query* query;
2625  SplitRegister* reg;
2626 
2627  ENTER (" ");
2628  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2629  if (!priv->ledger)
2630  {
2631  LEAVE ("no ledger");
2632  return;
2633  }
2634  // check if this a search register and save query
2635  gnc_ppr_update_for_search_query (page);
2636 
2637  query = gnc_ledger_display_get_query (priv->ledger);
2638 
2639  if (!query)
2640  {
2641  LEAVE ("no query");
2642  return;
2643  }
2644 
2645  reg = gnc_ledger_display_get_split_register (priv->ledger);
2646 
2647  /* Delete any existing old date spec. */
2648  if (reg->type != SEARCH_LEDGER)
2649  {
2650  GSList *param_list = qof_query_build_param_list (SPLIT_TRANS,
2651  TRANS_DATE_POSTED, NULL);
2652  qof_query_purge_terms (query, param_list);
2653  g_slist_free (param_list);
2654  }
2655 
2656  if (priv->fd.start_time || priv->fd.end_time)
2657  {
2658  /* Build a new spec */
2659  xaccQueryAddDateMatchTT (query,
2660  priv->fd.start_time != 0, priv->fd.start_time,
2661  priv->fd.end_time != 0, priv->fd.end_time,
2662  QOF_QUERY_AND);
2663  }
2664 
2665  if (priv->fd.days > 0)
2666  {
2667  time64 start;
2668  struct tm tm;
2669 
2670  gnc_tm_get_today_start (&tm);
2671 
2672  tm.tm_mday = tm.tm_mday - priv->fd.days;
2673  start = gnc_mktime (&tm);
2674  xaccQueryAddDateMatchTT (query, TRUE, start, FALSE, 0, QOF_QUERY_AND);
2675  }
2676 
2677  // Set filter tooltip for summary bar
2678  gnc_plugin_page_register_set_filter_tooltip (page);
2679 
2680  // clear previous filter query and save current
2681  qof_query_destroy (priv->filter_query);
2682  priv->filter_query = qof_query_copy (query);
2683 
2684  if (priv->enable_refresh)
2685  gnc_ledger_display_refresh (priv->ledger);
2686  LEAVE (" ");
2687 }
2688 
2689 
2690 /* This function converts a time64 value date to a string */
2691 static gchar*
2692 gnc_plugin_page_register_filter_time2dmy (time64 raw_time)
2693 {
2694  struct tm* timeinfo;
2695  gchar date_string[11];
2696 
2697  timeinfo = gnc_localtime (&raw_time);
2698  strftime (date_string, 11, "%d-%m-%Y", timeinfo);
2699  PINFO ("Date string is %s", date_string);
2700  gnc_tm_free (timeinfo);
2701 
2702  return g_strdup (date_string);
2703 }
2704 
2705 
2706 /* This function converts a string date to a time64 value */
2707 static time64
2708 gnc_plugin_page_register_filter_dmy2time (char* date_string)
2709 {
2710  struct tm when;
2711 
2712  PINFO ("Date string is %s", date_string);
2713  memset (&when, 0, sizeof (when));
2714 
2715  sscanf (date_string, "%d-%d-%d", &when.tm_mday,
2716  &when.tm_mon, &when.tm_year);
2717 
2718  when.tm_mon -= 1;
2719  when.tm_year -= 1900;
2720 
2721  return gnc_mktime (&when);
2722 }
2723 
2724 
2735 void
2737  GncPluginPageRegister* page)
2738 {
2740  const gchar* name;
2741  gint i, value;
2742 
2743  g_return_if_fail (GTK_IS_CHECK_BUTTON (button));
2744  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2745 
2746  name = gtk_buildable_get_name (GTK_BUILDABLE (button));
2747  ENTER ("toggle button %s (%p), plugin_page %p", name, button, page);
2748 
2749  /* Determine what status bit to change */
2750  value = CLEARED_NONE;
2751  for (i = 0; status_actions[i].action_name; i++)
2752  {
2753  if (g_strcmp0 (name, status_actions[i].action_name) == 0)
2754  {
2755  value = status_actions[i].value;
2756  break;
2757  }
2758  }
2759 
2760  /* Compute the new match status */
2761  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2762  if (gtk_toggle_button_get_active (button))
2763  priv->fd.cleared_match = (cleared_match_t)(priv->fd.cleared_match | value);
2764  else
2765  priv->fd.cleared_match = (cleared_match_t)(priv->fd.cleared_match & ~value);
2766  gnc_ppr_update_status_query (page);
2767  LEAVE (" ");
2768 }
2769 
2770 
2780 void
2782  GncPluginPageRegister* page)
2783 {
2785  GtkWidget* widget;
2786  gint i;
2787 
2788  g_return_if_fail (GTK_IS_BUTTON (button));
2789  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2790 
2791  ENTER ("(button %p, page %p)", button, page);
2792 
2793  /* Turn on all the check menu items */
2794  for (i = 0; status_actions[i].action_name; i++)
2795  {
2796  widget = status_actions[i].widget;
2797  g_signal_handlers_block_by_func (widget,
2799  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
2800  g_signal_handlers_unblock_by_func (widget,
2802  }
2803 
2804  /* Set the requested status */
2805  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2806  priv->fd.cleared_match = CLEARED_ALL;
2807  gnc_ppr_update_status_query (page);
2808  LEAVE (" ");
2809 }
2810 
2811 
2812 
2822 void
2824  GncPluginPageRegister* page)
2825 {
2827  GtkWidget* widget;
2828  gint i;
2829 
2830  g_return_if_fail (GTK_IS_BUTTON (button));
2831  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2832 
2833  ENTER ("(button %p, page %p)", button, page);
2834 
2835  /* Turn off all the check menu items */
2836  for (i = 0; status_actions[i].action_name; i++)
2837  {
2838  widget = status_actions[i].widget;
2839  g_signal_handlers_block_by_func (widget,
2841  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
2842  g_signal_handlers_unblock_by_func (widget,
2844  }
2845 
2846  /* Set the requested status */
2847  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2848  priv->fd.cleared_match = CLEARED_NONE;
2849  gnc_ppr_update_status_query (page);
2850  LEAVE (" ");
2851 }
2852 
2853 
2865 static void
2866 get_filter_times (GncPluginPageRegister* page)
2867 {
2869  time64 time_val;
2870 
2871  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2872  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
2873  priv->fd.start_date_choose)))
2874  {
2875  time_val = gnc_date_edit_get_date (GNC_DATE_EDIT (priv->fd.start_date));
2876  time_val = gnc_time64_get_day_start (time_val);
2877  priv->fd.start_time = time_val;
2878  }
2879  else
2880  {
2881  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
2882  priv->fd.start_date_today)))
2883  {
2884  priv->fd.start_time = gnc_time64_get_today_start();
2885  }
2886  else
2887  {
2888  priv->fd.start_time = 0;
2889  }
2890  }
2891 
2892  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
2893  priv->fd.end_date_choose)))
2894  {
2895  time_val = gnc_date_edit_get_date (GNC_DATE_EDIT (priv->fd.end_date));
2896  time_val = gnc_time64_get_day_end (time_val);
2897  priv->fd.end_time = time_val;
2898  }
2899  else
2900  {
2901  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
2902  priv->fd.end_date_today)))
2903  {
2904  priv->fd.end_time = gnc_time64_get_today_end();
2905  }
2906  else
2907  {
2908  priv->fd.end_time = 0;
2909  }
2910  }
2911 }
2912 
2913 
2925 void
2927  GncPluginPageRegister* page)
2928 {
2930  gboolean active;
2931  const gchar* name;
2932 
2933  g_return_if_fail (GTK_IS_RADIO_BUTTON (button));
2934  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2935 
2936  ENTER ("(button %p, page %p)", button, page);
2937  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2938  name = gtk_buildable_get_name (GTK_BUILDABLE (button));
2939  active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
2940 
2941  if (active && g_strcmp0 (name, "filter_show_range") == 0)
2942  {
2943  gtk_widget_set_sensitive (priv->fd.table, active);
2944  gtk_widget_set_sensitive (priv->fd.num_days, !active);
2945  get_filter_times (page);
2946  }
2947  else if (active && g_strcmp0 (name, "filter_show_days") == 0)
2948  {
2949  gtk_widget_set_sensitive (priv->fd.table, !active);
2950  gtk_widget_set_sensitive (priv->fd.num_days, active);
2951  gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->fd.num_days), priv->fd.days);
2952  }
2953  else
2954  {
2955  gtk_widget_set_sensitive (priv->fd.table, FALSE);
2956  gtk_widget_set_sensitive (priv->fd.num_days, FALSE);
2957  priv->fd.days = 0;
2958  priv->fd.start_time = 0;
2959  priv->fd.end_time = 0;
2960  }
2961  gnc_ppr_update_date_query (page);
2962  LEAVE (" ");
2963 }
2964 
2965 void
2967 {
2969 
2970  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
2971 
2972  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2973 
2974  priv->fd.days = 0;
2975  priv->fd.start_time = 0;
2976  priv->fd.end_time = 0;
2977  priv->fd.cleared_match = (cleared_match_t)g_ascii_strtoll (DEFAULT_FILTER, NULL, 16);
2978 
2979  gnc_ppr_update_date_query (GNC_PLUGIN_PAGE_REGISTER(plugin_page));
2980 }
2981 
2992 void
2994  GncPluginPageRegister* page)
2995 {
2997 
2998  g_return_if_fail (GTK_IS_SPIN_BUTTON (button));
2999  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3000 
3001  ENTER ("(button %p, page %p)", button, page);
3002  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3003 
3004  priv->fd.days = gtk_spin_button_get_value (GTK_SPIN_BUTTON (button));
3005  gnc_ppr_update_date_query (page);
3006  LEAVE (" ");
3007 }
3008 
3009 
3020 static void
3021 gnc_plugin_page_register_filter_gde_changed_cb (GtkWidget* unused,
3022  GncPluginPageRegister* page)
3023 {
3024  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3025 
3026  ENTER ("(widget %s(%p), page %p)",
3027  gtk_buildable_get_name (GTK_BUILDABLE (unused)), unused, page);
3028  get_filter_times (page);
3029  gnc_ppr_update_date_query (page);
3030  LEAVE (" ");
3031 }
3032 
3033 
3053 void
3055  GncPluginPageRegister* page)
3056 {
3058  const gchar* name;
3059  gboolean active;
3060 
3061  g_return_if_fail (GTK_IS_RADIO_BUTTON (radio));
3062  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3063 
3064  ENTER ("(radio %s(%p), page %p)",
3065  gtk_buildable_get_name (GTK_BUILDABLE (radio)), radio, page);
3066  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3067  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio)))
3068  {
3069  LEAVE ("1st callback of pair. Defer to 2nd callback.");
3070  return;
3071  }
3072 
3073  name = gtk_buildable_get_name (GTK_BUILDABLE (radio));
3074  active = !g_strcmp0 (name, "start_date_choose");
3075  gtk_widget_set_sensitive (priv->fd.start_date, active);
3076  get_filter_times (page);
3077  gnc_ppr_update_date_query (page);
3078  LEAVE (" ");
3079 }
3080 
3081 
3101 void
3103  GncPluginPageRegister* page)
3104 {
3106  const gchar* name;
3107  gboolean active;
3108 
3109  g_return_if_fail (GTK_IS_RADIO_BUTTON (radio));
3110  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3111 
3112  ENTER ("(radio %s(%p), page %p)",
3113  gtk_buildable_get_name (GTK_BUILDABLE (radio)), radio, page);
3114  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3115  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio)))
3116  {
3117  LEAVE ("1st callback of pair. Defer to 2nd callback.");
3118  return;
3119  }
3120 
3121  name = gtk_buildable_get_name (GTK_BUILDABLE (radio));
3122  active = !g_strcmp0 (name, "end_date_choose");
3123  gtk_widget_set_sensitive (priv->fd.end_date, active);
3124  get_filter_times (page);
3125  gnc_ppr_update_date_query (page);
3126  LEAVE (" ");
3127 }
3128 
3129 
3138 void
3140  GncPluginPageRegister* page)
3141 {
3143 
3144  g_return_if_fail (GTK_IS_CHECK_BUTTON (button));
3145  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3146 
3147  ENTER ("Save toggle button (%p), plugin_page %p", button, page);
3148 
3149  /* Compute the new save filter status */
3150  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3151  if (gtk_toggle_button_get_active (button))
3152  priv->fd.save_filter = TRUE;
3153  else
3154  priv->fd.save_filter = FALSE;
3155  LEAVE (" ");
3156 }
3157 
3158 
3170 void
3172  gint response,
3173  GncPluginPageRegister* page)
3174 {
3176  GncPluginPage* plugin_page;
3177 
3178  g_return_if_fail (GTK_IS_DIALOG (dialog));
3179  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3180 
3181  ENTER (" ");
3182  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3183  plugin_page = GNC_PLUGIN_PAGE (page);
3184 
3185  if (response != GTK_RESPONSE_OK)
3186  {
3187  /* Remove the old status match */
3188  priv->fd.cleared_match = priv->fd.original_cleared_match;
3189  priv->enable_refresh = FALSE;
3190  gnc_ppr_update_status_query (page);
3191  priv->enable_refresh = TRUE;
3192  priv->fd.start_time = priv->fd.original_start_time;
3193  priv->fd.end_time = priv->fd.original_end_time;
3194  priv->fd.days = priv->fd.original_days;
3195  priv->fd.save_filter = priv->fd.original_save_filter;
3196  gnc_ppr_update_date_query (page);
3197  }
3198  else
3199  {
3200  // clear the filter when unticking the save option
3201  if ((priv->fd.save_filter == FALSE) && (priv->fd.original_save_filter == TRUE))
3202  gnc_plugin_page_register_set_filter (plugin_page, NULL);
3203 
3204  priv->fd.original_save_filter = priv->fd.save_filter;
3205 
3206  if (priv->fd.save_filter)
3207  {
3208  gchar *filter;
3209  GList *flist = NULL;
3210 
3211  // cleared match
3212  flist = g_list_prepend
3213  (flist, g_strdup_printf ("0x%04x", priv->fd.cleared_match));
3214 
3215  // start time
3216  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->fd.start_date_choose)) && priv->fd.start_time != 0)
3217  flist = g_list_prepend (flist, gnc_plugin_page_register_filter_time2dmy (priv->fd.start_time));
3218  else
3219  flist = g_list_prepend (flist, g_strdup ("0"));
3220 
3221  // end time
3222  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->fd.end_date_choose))
3223  && priv->fd.end_time != 0)
3224  flist = g_list_prepend (flist, gnc_plugin_page_register_filter_time2dmy (priv->fd.end_time));
3225  else
3226  flist = g_list_prepend (flist, g_strdup ("0"));
3227 
3228  // number of days
3229  if (priv->fd.days > 0)
3230  flist = g_list_prepend (flist, g_strdup_printf ("%d", priv->fd.days));
3231  else
3232  flist = g_list_prepend (flist, g_strdup ("0"));
3233 
3234  flist = g_list_reverse (flist);
3235  filter = gnc_g_list_stringjoin (flist, ",");
3236  PINFO ("The filter to save is %s", filter);
3237  gnc_plugin_page_register_set_filter (plugin_page, filter);
3238  g_free (filter);
3239  g_list_free_full (flist, g_free);
3240  }
3241  }
3242  priv->fd.dialog = NULL;
3243  gtk_widget_destroy (GTK_WIDGET (dialog));
3244  LEAVE (" ");
3245 }
3246 
3247 static void
3248 gpp_update_match_filter_text (cleared_match_t match, const guint mask,
3249  const gchar* filter_name, GList **show, GList **hide)
3250 {
3251  if ((match & mask) == mask)
3252  *show = g_list_prepend (*show, g_strdup (filter_name));
3253  else
3254  *hide = g_list_prepend (*hide, g_strdup (filter_name));
3255 }
3256 
3257 static void
3258 gnc_plugin_page_register_set_filter_tooltip (GncPluginPageRegister* page)
3259 {
3261  GList *t_list = NULL;
3262 
3263  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3264 
3265  ENTER (" ");
3266  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3267 
3268  // filtered start time
3269  if (priv->fd.start_time != 0)
3270  {
3271  gchar* sdate = qof_print_date (priv->fd.start_time);
3272  t_list = g_list_prepend
3273  (t_list, g_strdup_printf ("%s %s", _("Start Date:"), sdate));
3274  g_free (sdate);
3275  }
3276 
3277  // filtered number of days
3278  if (priv->fd.days > 0)
3279  t_list = g_list_prepend
3280  (t_list, g_strdup_printf ("%s %d", _("Show previous number of days:"),
3281  priv->fd.days));
3282 
3283  // filtered end time
3284  if (priv->fd.end_time != 0)
3285  {
3286  gchar* edate = qof_print_date (priv->fd.end_time);
3287  t_list = g_list_prepend
3288  (t_list, g_strdup_printf ("%s %s", _("End Date:"), edate));
3289  g_free (edate);
3290  }
3291 
3292  // filtered match items
3293  if (priv->fd.cleared_match != CLEARED_ALL)
3294  {
3295  GList *show = NULL;
3296  GList *hide = NULL;
3297 
3298  gpp_update_match_filter_text (priv->fd.cleared_match, 0x01, _ ("Unreconciled"),
3299  &show, &hide);
3300  gpp_update_match_filter_text (priv->fd.cleared_match, 0x02, _ ("Cleared"),
3301  &show, &hide);
3302  gpp_update_match_filter_text (priv->fd.cleared_match, 0x04, _ ("Reconciled"),
3303  &show, &hide);
3304  gpp_update_match_filter_text (priv->fd.cleared_match, 0x08, _ ("Frozen"),
3305  &show, &hide);
3306  gpp_update_match_filter_text (priv->fd.cleared_match, 0x10, _ ("Voided"),
3307  &show, &hide);
3308 
3309  show = g_list_reverse (show);
3310  hide = g_list_reverse (hide);
3311 
3312  if (show)
3313  {
3314  char *str = gnc_list_formatter (show);
3315  t_list = g_list_prepend
3316  (t_list, g_strdup_printf ("%s %s", _("Show:"), str));
3317  g_free (str);
3318  }
3319 
3320  if (hide)
3321  {
3322  char *str = gnc_list_formatter (hide);
3323  t_list = g_list_prepend
3324  (t_list, g_strdup_printf ("%s %s", _("Hide:"), str));
3325  g_free (str);
3326  }
3327 
3328  g_list_free_full (show, g_free);
3329  g_list_free_full (hide, g_free);
3330  }
3331 
3332  t_list = g_list_reverse (t_list);
3333 
3334  if (t_list)
3335  t_list = g_list_prepend (t_list, g_strdup (_("Filter By:")));
3336 
3337  // free the existing text if present
3338  if (priv->gsr->filter_text != NULL)
3339  g_free (priv->gsr->filter_text);
3340 
3341  // set the tooltip text variable in the gsr
3342  priv->gsr->filter_text = gnc_g_list_stringjoin (t_list, "\n");
3343 
3344  g_list_free_full (t_list, g_free);
3345 
3346  LEAVE (" ");
3347 }
3348 
3349 
3350 static void
3351 gnc_plugin_page_register_update_page_icon (GncPluginPage* plugin_page)
3352 {
3354  gboolean read_only;
3355 
3356  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
3357 
3358  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
3359 
3360  if (qof_book_is_readonly (gnc_get_current_book()) ||
3361  gnc_split_reg_get_read_only (priv->gsr))
3362  read_only = TRUE;
3363  else
3364  read_only = FALSE;
3365 
3366  main_window_update_page_set_read_only_icon (GNC_PLUGIN_PAGE(plugin_page),
3367  read_only);
3368 }
3369 
3370 /************************************************************/
3371 /* Report Helper Functions */
3372 /************************************************************/
3373 
3374 static char*
3375 gnc_reg_get_name (GNCLedgerDisplay* ledger, gboolean for_window)
3376 {
3377  Account* leader;
3378  SplitRegister* reg;
3379  gchar* account_name;
3380  gchar* reg_name;
3381  gchar* name;
3382  GNCLedgerDisplayType ledger_type;
3383 
3384  if (ledger == NULL)
3385  return NULL;
3386 
3388  ledger_type = gnc_ledger_display_type (ledger);
3389 
3390  switch (reg->type)
3391  {
3392  case GENERAL_JOURNAL:
3393  case INCOME_LEDGER:
3394  if (for_window)
3395  reg_name = _ ("General Journal");
3396  else
3397  reg_name = _ ("Transaction Report");
3398  break;
3399  case PORTFOLIO_LEDGER:
3400  if (for_window)
3401  reg_name = _ ("Portfolio");
3402  else
3403  reg_name = _ ("Portfolio Report");
3404  break;
3405  case SEARCH_LEDGER:
3406  if (for_window)
3407  reg_name = _ ("Search Results");
3408  else
3409  reg_name = _ ("Search Results Report");
3410  break;
3411  default:
3412  if (for_window)
3413  reg_name = _ ("Register");
3414  else
3415  reg_name = _ ("Transaction Report");
3416  break;
3417  }
3418 
3419  leader = gnc_ledger_display_leader (ledger);
3420 
3421  if ((leader != NULL) && (ledger_type != LD_GL))
3422  {
3423  account_name = gnc_account_get_full_name (leader);
3424 
3425  if (ledger_type == LD_SINGLE)
3426  {
3427  name = g_strconcat (account_name, " - ", reg_name, NULL);
3428  }
3429  else
3430  {
3431  name = g_strconcat (account_name, " ", _ ("and subaccounts"), " - ", reg_name,
3432  NULL);
3433  }
3434  g_free (account_name);
3435  }
3436  else
3437  name = g_strdup (reg_name);
3438 
3439  return name;
3440 }
3441 
3442 static int
3443 report_helper (GNCLedgerDisplay* ledger, Split* split, Query* query)
3444 {
3445  SplitRegister* reg = gnc_ledger_display_get_split_register (ledger);
3446  Account* account;
3447  char* str;
3448  const char* tmp;
3449  swig_type_info* qtype;
3450  SCM args;
3451  SCM func;
3452  SCM arg;
3453 
3454  args = SCM_EOL;
3455 
3456  func = scm_c_eval_string ("gnc:register-report-create");
3457  g_return_val_if_fail (scm_is_procedure (func), -1);
3458 
3460  arg = scm_from_utf8_string (tmp ? tmp : _ ("Credit"));
3461  args = scm_cons (arg, args);
3462 
3464  arg = scm_from_utf8_string (tmp ? tmp : _ ("Debit"));
3465  args = scm_cons (arg, args);
3466 
3467  str = gnc_reg_get_name (ledger, FALSE);
3468  arg = scm_from_utf8_string (str ? str : "");
3469  args = scm_cons (arg, args);
3470  g_free (str);
3471 
3472  arg = SCM_BOOL (reg->use_double_line);
3473  args = scm_cons (arg, args);
3474 
3475  arg = SCM_BOOL (reg->type == GENERAL_JOURNAL || reg->type == INCOME_LEDGER
3476  || reg->type == SEARCH_LEDGER);
3477  args = scm_cons (arg, args);
3478 
3479  arg = SCM_BOOL (reg->style == REG_STYLE_JOURNAL);
3480  args = scm_cons (arg, args);
3481 
3482  if (!query)
3483  {
3484  query = gnc_ledger_display_get_query (ledger);
3485  g_return_val_if_fail (query != NULL, -1);
3486  }
3487 
3488  qtype = SWIG_TypeQuery ("_p__QofQuery");
3489  g_return_val_if_fail (qtype, -1);
3490 
3491  arg = SWIG_NewPointerObj (query, qtype, 0);
3492  args = scm_cons (arg, args);
3493  g_return_val_if_fail (arg != SCM_UNDEFINED, -1);
3494 
3495 
3496  if (split)
3497  {
3498  qtype = SWIG_TypeQuery ("_p_Split");
3499  g_return_val_if_fail (qtype, -1);
3500  arg = SWIG_NewPointerObj (split, qtype, 0);
3501  }
3502  else
3503  {
3504  arg = SCM_BOOL_F;
3505  }
3506  args = scm_cons (arg, args);
3507  g_return_val_if_fail (arg != SCM_UNDEFINED, -1);
3508 
3509 
3510  qtype = SWIG_TypeQuery ("_p_Account");
3511  g_return_val_if_fail (qtype, -1);
3512 
3513  account = gnc_ledger_display_leader (ledger);
3514  arg = SWIG_NewPointerObj (account, qtype, 0);
3515  args = scm_cons (arg, args);
3516  g_return_val_if_fail (arg != SCM_UNDEFINED, -1);
3517 
3518 
3519  /* Apply the function to the args */
3520  arg = scm_apply (func, args, SCM_EOL);
3521  g_return_val_if_fail (scm_is_exact (arg), -1);
3522 
3523  return scm_to_int (arg);
3524 }
3525 
3526 /************************************************************/
3527 /* Command callbacks */
3528 /************************************************************/
3529 
3530 static void
3531 gnc_plugin_page_register_cmd_print_check (GSimpleAction *simple,
3532  GVariant *paramter,
3533  gpointer user_data)
3534 {
3535  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3537  SplitRegister* reg;
3538  Split* split;
3539  Transaction* trans;
3540  GList* splits = NULL, *item;
3541  GNCLedgerDisplayType ledger_type;
3542  Account* account, *subaccount = NULL;
3543  GtkWidget* window;
3544 
3545  ENTER ("(action %p, page %p)", simple, page);
3546 
3547  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3548 
3549  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3550  reg = gnc_ledger_display_get_split_register (priv->ledger);
3551  ledger_type = gnc_ledger_display_type (priv->ledger);
3552  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
3553  if (ledger_type == LD_SINGLE || ledger_type == LD_SUBACCOUNT)
3554  {
3555  account = gnc_plugin_page_register_get_account (page);
3557  trans = xaccSplitGetParent (split);
3558  if (ledger_type == LD_SUBACCOUNT)
3559  {
3560  /* Set up subaccount printing, where the check amount matches the
3561  * value displayed in the register. */
3562  subaccount = account;
3563  }
3564 
3565  if (split && trans)
3566  {
3567  if (xaccSplitGetAccount (split) == account)
3568  {
3569  splits = g_list_prepend (splits, split);
3570  gnc_ui_print_check_dialog_create (window, splits, subaccount);
3571  g_list_free (splits);
3572  }
3573  else
3574  {
3575  /* This split is not for the account shown in this register. Get the
3576  split that anchors the transaction to the registor */
3577  split = gnc_split_register_get_current_trans_split (reg, NULL);
3578  if (split)
3579  {
3580  splits = g_list_prepend (splits, split);
3581  gnc_ui_print_check_dialog_create (window, splits, subaccount);
3582  g_list_free (splits);
3583  }
3584  }
3585  }
3586  }
3587  else if (ledger_type == LD_GL && reg->type == SEARCH_LEDGER)
3588  {
3589  Account* common_acct = NULL;
3590 
3591  /* the following GList* splits must not be freed */
3592  splits = qof_query_run (gnc_ledger_display_get_query (priv->ledger));
3593 
3594  /* Make sure each split is from the same account */
3595  for (item = splits; item; item = g_list_next (item))
3596  {
3597  split = (Split*) item->data;
3598  if (common_acct == NULL)
3599  {
3600  common_acct = xaccSplitGetAccount (split);
3601  }
3602  else
3603  {
3604  if (xaccSplitGetAccount (split) != common_acct)
3605  {
3606  GtkWidget* dialog;
3607  gint response;
3608  const gchar* title = _ ("Print checks from multiple accounts?");
3609  const gchar* message =
3610  _ ("This search result contains splits from more than one account. "
3611  "Do you want to print the checks even though they are not all "
3612  "from the same account?");
3613  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
3614  GTK_DIALOG_DESTROY_WITH_PARENT,
3615  GTK_MESSAGE_WARNING,
3616  GTK_BUTTONS_CANCEL,
3617  "%s", title);
3618  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
3619  "%s", message);
3620  gtk_dialog_add_button (GTK_DIALOG (dialog), _ ("_Print checks"),
3621  GTK_RESPONSE_YES);
3622  response = gnc_dialog_run (GTK_DIALOG (dialog),
3623  GNC_PREF_WARN_CHECKPRINTING_MULTI_ACCT);
3624  gtk_widget_destroy (dialog);
3625  if (response != GTK_RESPONSE_YES)
3626  {
3627  LEAVE ("Multiple accounts");
3628  return;
3629  }
3630  break;
3631  }
3632  }
3633  }
3634  gnc_ui_print_check_dialog_create (window, splits, NULL);
3635  }
3636  else
3637  {
3638  gnc_error_dialog (GTK_WINDOW (window), "%s",
3639  _ ("You can only print checks from a bank account register or search results."));
3640  LEAVE ("Unsupported ledger type");
3641  return;
3642  }
3643  LEAVE (" ");
3644 }
3645 
3646 
3647 static void
3648 gnc_plugin_page_register_cmd_cut (GSimpleAction *simple,
3649  GVariant *paramter,
3650  gpointer user_data)
3651 {
3652  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3654 
3655  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3656 
3657  ENTER ("(action %p, page %p)", simple, page);
3658  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3659 
3660  GtkWidget *widget = gtk_window_get_focus(GTK_WINDOW (priv->gsr->window));
3661  const char *name = gtk_widget_get_name(widget);
3662  if (strcmp(name, "GnucashSheet") != 0)
3663  {
3664  gtk_editable_cut_clipboard( GTK_EDITABLE(widget));
3665  LEAVE("Not cut from GnucashSheet");
3666 
3667  return;
3668  }
3669 
3670  gnucash_register_cut_clipboard (priv->gsr->reg);
3671  LEAVE ("");
3672 }
3673 
3674 
3675 static void
3676 gnc_plugin_page_register_cmd_copy (GSimpleAction *simple,
3677  GVariant *paramter,
3678  gpointer user_data)
3679 {
3680  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3682 
3683  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3684 
3685  ENTER ("(action %p, page %p)", simple, page);
3686  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3687 
3688  GtkWidget *widget = gtk_window_get_focus(GTK_WINDOW (priv->gsr->window));
3689  const char *name = gtk_widget_get_name(widget);
3690  if (strcmp(name, "GnucashSheet") != 0)
3691  {
3692  gtk_editable_copy_clipboard( GTK_EDITABLE(widget));
3693  LEAVE("Not copied from GnucashSheet");
3694 
3695  return;
3696  }
3697 
3698  gnucash_register_copy_clipboard (priv->gsr->reg);
3699  LEAVE ("");
3700 }
3701 
3702 
3703 static void
3704 gnc_plugin_page_register_cmd_paste (GSimpleAction *simple,
3705  GVariant *paramter,
3706  gpointer user_data)
3707 {
3708  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3710 
3711  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3712 
3713  ENTER ("(action %p, page %p)", simple, page);
3714  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3715 
3716  GtkWidget *widget = gtk_window_get_focus(GTK_WINDOW (priv->gsr->window));
3717  const char *name = gtk_widget_get_name(widget);
3718  if (strcmp(name, "GnucashSheet") != 0)
3719  {
3720  gtk_editable_paste_clipboard( GTK_EDITABLE(widget));
3721  LEAVE("Not pasted to GnucashSheet");
3722 
3723  return;
3724  }
3725 
3726  gnucash_register_paste_clipboard (priv->gsr->reg);
3727  LEAVE ("");
3728 }
3729 
3730 
3731 static void
3732 gnc_plugin_page_register_cmd_edit_account (GSimpleAction *simple,
3733  GVariant *paramter,
3734  gpointer user_data)
3735 {
3736  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3737  Account* account;
3738  GtkWindow* parent = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page)));
3739  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3740 
3741  ENTER ("(action %p, page %p)", simple, page);
3742  account = gnc_plugin_page_register_get_account (page);
3743  if (account)
3744  gnc_ui_edit_account_window (parent, account);
3745  LEAVE (" ");
3746 }
3747 
3748 
3749 static void
3750 gnc_plugin_page_register_cmd_find_account (GSimpleAction *simple,
3751  GVariant *paramter,
3752  gpointer user_data)
3753 {
3754  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3755  GtkWidget* window;
3756 
3757  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3758 
3759  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
3760  gnc_find_account_dialog (window, NULL);
3761 }
3762 
3763 
3764 static void
3765 gnc_plugin_page_register_cmd_find_transactions (GSimpleAction *simple,
3766  GVariant *paramter,
3767  gpointer user_data)
3768 {
3769  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3771  GtkWindow* window;
3772 
3773  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3774 
3775  ENTER ("(action %p, page %p)", simple, page);
3776  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3777  window = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
3778  gnc_ui_find_transactions_dialog_create (window, priv->ledger);
3779  LEAVE (" ");
3780 }
3781 
3782 
3783 static void
3784 gnc_plugin_page_register_cmd_edit_tax_options (GSimpleAction *simple,
3785  GVariant *paramter,
3786  gpointer user_data)
3787 {
3788  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3789  GtkWidget *window;
3790  Account* account;
3791 
3792  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3793 
3794  ENTER ("(action %p, page %p)", simple, page);
3795  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
3796  account = gnc_plugin_page_register_get_account (page);
3797  gnc_tax_info_dialog (window, account);
3798  LEAVE (" ");
3799 }
3800 
3801 static void
3802 gnc_plugin_page_register_cmd_cut_transaction (GSimpleAction *simple,
3803  GVariant *paramter,
3804  gpointer user_data)
3805 {
3806  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3808 
3809  ENTER ("(action %p, page %p)", simple, page);
3810 
3811  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3812 
3813  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3814  gsr_default_cut_txn_handler (priv->gsr, NULL);
3815 
3816  // Transaction/Split paste action
3817  GAction *action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
3818  "PasteTransactionAction");
3819  g_simple_action_set_enabled (G_SIMPLE_ACTION(action),
3821  LEAVE (" ");
3822 }
3823 
3824 
3825 static void
3826 gnc_plugin_page_register_cmd_copy_transaction (GSimpleAction *simple,
3827  GVariant *paramter,
3828  gpointer user_data)
3829 {
3830  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3832  SplitRegister* reg;
3833 
3834  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3835 
3836  ENTER ("(action %p, page %p)", simple, page);
3837  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3838  reg = gnc_ledger_display_get_split_register (priv->ledger);
3840 
3841  // Transaction/Split paste action
3842  GAction *action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
3843  "PasteTransactionAction");
3844  g_simple_action_set_enabled (G_SIMPLE_ACTION(action),
3846  LEAVE (" ");
3847 }
3848 
3849 
3850 static void
3851 gnc_plugin_page_register_cmd_paste_transaction (GSimpleAction *simple,
3852  GVariant *paramter,
3853  gpointer user_data)
3854 {
3855  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3857  SplitRegister* reg;
3858 
3859  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3860 
3861  ENTER ("(action %p, page %p)", simple, page);
3862  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3863  reg = gnc_ledger_display_get_split_register (priv->ledger);
3865  LEAVE (" ");
3866 }
3867 
3868 
3869 static void
3870 gnc_plugin_page_register_cmd_void_transaction (GSimpleAction *simple,
3871  GVariant *paramter,
3872  gpointer user_data)
3873 {
3874  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3876  GtkWidget* dialog, *entry;
3877  SplitRegister* reg;
3878  Transaction* trans;
3879  GtkBuilder* builder;
3880  const char* reason;
3881  gint result;
3882  GtkWindow* window;
3883 
3884  ENTER ("(action %p, page %p)", simple, page);
3885 
3886  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3887 
3888  window = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
3889  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3890  reg = gnc_ledger_display_get_split_register (priv->ledger);
3892  if (trans == NULL)
3893  return;
3894  if (xaccTransHasSplitsInState (trans, VREC))
3895  return;
3896  if (xaccTransHasReconciledSplits (trans) ||
3898  {
3899  gnc_error_dialog (window, "%s",
3900  _ ("You cannot void a transaction with reconciled or cleared splits."));
3901  return;
3902  }
3903  reason = xaccTransGetReadOnly (trans);
3904  if (reason)
3905  {
3906  gnc_error_dialog (window,
3907  _ ("This transaction is marked read-only with the comment: '%s'"), reason);
3908  return;
3909  }
3910 
3911  if (!gnc_plugin_page_register_finish_pending (GNC_PLUGIN_PAGE (page)))
3912  return;
3913 
3914  builder = gtk_builder_new();
3915  gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade",
3916  "void_transaction_dialog");
3917  dialog = GTK_WIDGET (gtk_builder_get_object (builder,
3918  "void_transaction_dialog"));
3919  entry = GTK_WIDGET (gtk_builder_get_object (builder, "reason"));
3920 
3921  gtk_window_set_transient_for (GTK_WINDOW (dialog), window);
3922 
3923  result = gtk_dialog_run (GTK_DIALOG (dialog));
3924  if (result == GTK_RESPONSE_OK)
3925  {
3926  reason = gtk_entry_get_text (GTK_ENTRY (entry));
3927  if (reason == NULL)
3928  reason = "";
3930  }
3931 
3932  /* All done. Get rid of it. */
3933  gtk_widget_destroy (dialog);
3934  g_object_unref (G_OBJECT (builder));
3935 }
3936 
3937 
3938 static void
3939 gnc_plugin_page_register_cmd_unvoid_transaction (GSimpleAction *simple,
3940  GVariant *paramter,
3941  gpointer user_data)
3942 {
3943  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3945  SplitRegister* reg;
3946  Transaction* trans;
3947 
3948  ENTER ("(action %p, page %p)", simple, page);
3949 
3950  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3951 
3952  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3953  reg = gnc_ledger_display_get_split_register (priv->ledger);
3955  if (!xaccTransHasSplitsInState (trans, VREC))
3956  return;
3958  LEAVE (" ");
3959 }
3960 
3961 static std::optional<time64>
3962 input_date (GtkWidget * parent, const char *window_title, const char* title)
3963 {
3964  time64 rv = gnc_time (nullptr);
3965  if (!gnc_dup_time64_dialog (parent, window_title, title, &rv))
3966  return {};
3967 
3968  return rv;
3969 }
3970 
3971 static void
3972 gnc_plugin_page_register_cmd_reverse_transaction (GSimpleAction *simple,
3973  GVariant *paramter,
3974  gpointer user_data)
3975 {
3976  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3978  SplitRegister* reg;
3979  GNCSplitReg* gsr;
3980  Transaction* trans, *new_trans;
3981  GtkWidget *window;
3982  Account *account;
3983  Split *split;
3984 
3985  ENTER ("(action %p, page %p)", simple, page);
3986 
3987  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3988 
3989  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3990  reg = gnc_ledger_display_get_split_register (priv->ledger);
3991  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
3993  if (trans == NULL)
3994  return;
3995 
3997  account = xaccSplitGetAccount (split);
3998 
3999  if (!account)
4000  {
4001  LEAVE ("shouldn't try to reverse the blank transaction...");
4002  return;
4003  }
4004 
4005  new_trans = xaccTransGetReversedBy (trans);
4006  if (new_trans)
4007  {
4008  const char *rev = _("A reversing entry has already been created for this transaction.");
4009  const char *jump = _("Jump to the transaction?");
4010  if (!gnc_verify_dialog (GTK_WINDOW (window), TRUE, "%s\n\n%s", rev, jump))
4011  {
4012  LEAVE ("reverse cancelled");
4013  return;
4014  }
4015  }
4016  else
4017  {
4018  auto date = input_date (window, _("Reverse Transaction"), _("New Transaction Information"));
4019  if (!date)
4020  {
4021  LEAVE ("reverse cancelled");
4022  return;
4023  }
4024 
4025  gnc_suspend_gui_refresh ();
4026  new_trans = xaccTransReverse (trans);
4027 
4028  /* Clear transaction level info */
4029  xaccTransSetDatePostedSecsNormalized (new_trans, date.value());
4030  xaccTransSetDateEnteredSecs (new_trans, gnc_time (NULL));
4031 
4032  gnc_resume_gui_refresh();
4033  }
4034 
4035  /* Now jump to new trans */
4036  gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE (page));
4037  split = xaccTransFindSplitByAccount(new_trans, account);
4038 
4039  /* Test for visibility of split */
4040  if (gnc_split_reg_clear_filter_for_split (gsr, split))
4041  gnc_plugin_page_register_clear_current_filter (GNC_PLUGIN_PAGE(page));
4042 
4043  gnc_split_reg_jump_to_split (gsr, split);
4044  LEAVE (" ");
4045 }
4046 
4047 static gboolean
4048 gnc_plugin_page_register_show_fs_save (GncPluginPageRegister* page)
4049 {
4050  GncPluginPageRegisterPrivate* priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4051  GNCLedgerDisplayType ledger_type = gnc_ledger_display_type (priv->ledger);
4052  SplitRegister* reg = gnc_ledger_display_get_split_register (priv->ledger);
4053 
4054  if (ledger_type == LD_SINGLE || ledger_type == LD_SUBACCOUNT)
4055  return TRUE;
4056  else
4057  {
4058  switch (reg->type)
4059  {
4060  case GENERAL_JOURNAL:
4061  return TRUE;
4062  break;
4063 
4064  case INCOME_LEDGER:
4065  case PORTFOLIO_LEDGER:
4066  case SEARCH_LEDGER:
4067  default:
4068  return FALSE;
4069  break;
4070  }
4071  }
4072 }
4073 
4074 static void
4075 gnc_plugin_page_register_cmd_view_sort_by (GSimpleAction *simple,
4076  GVariant *paramter,
4077  gpointer user_data)
4078 {
4079  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4081  SplitRegister* reg;
4082  GtkWidget* dialog, *button;
4083  GtkBuilder* builder;
4084  SortType sort;
4085  const gchar* name;
4086  gchar* title;
4087 
4088  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4089  ENTER ("(action %p, page %p)", simple, page);
4090 
4091  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4092  if (priv->sd.dialog)
4093  {
4094  gtk_window_present (GTK_WINDOW (priv->sd.dialog));
4095  LEAVE ("existing dialog");
4096  return;
4097  }
4098 
4099  /* Create the dialog */
4100 
4101  builder = gtk_builder_new();
4102  gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade",
4103  "sort_by_dialog");
4104  dialog = GTK_WIDGET (gtk_builder_get_object (builder, "sort_by_dialog"));
4105  priv->sd.dialog = dialog;
4106  gtk_window_set_transient_for (GTK_WINDOW (dialog),
4107  gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window)));
4108  /* Translators: The %s is the name of the plugin page */
4109  title = g_strdup_printf (_ ("Sort %s by…"),
4110  gnc_plugin_page_get_page_name (GNC_PLUGIN_PAGE (page)));
4111  gtk_window_set_title (GTK_WINDOW (dialog), title);
4112  g_free (title);
4113 
4114  /* Set the button for the current sort order */
4115  sort = gnc_split_reg_get_sort_type (priv->gsr);
4116  name = SortTypeasString (sort);
4117  button = GTK_WIDGET (gtk_builder_get_object (builder, name));
4118  DEBUG ("current sort %d, button %s(%p)", sort, name, button);
4119  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4120  priv->sd.original_sort_type = sort;
4121 
4122  button = GTK_WIDGET (gtk_builder_get_object (builder, "sort_save"));
4123  if (priv->sd.save_order == TRUE)
4124  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4125 
4126  // hide the save button if appropriate
4127  gtk_widget_set_visible (GTK_WIDGET (button),
4128  gnc_plugin_page_register_show_fs_save (page));
4129 
4130  /* Set the button for the current reverse_order order */
4131  button = GTK_WIDGET (gtk_builder_get_object (builder, "sort_reverse"));
4132  if (priv->sd.reverse_order == TRUE)
4133  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4134  priv->sd.original_reverse_order = priv->sd.reverse_order;
4135 
4136  priv->sd.num_radio = GTK_WIDGET (gtk_builder_get_object (builder, "BY_NUM"));
4137  priv->sd.act_radio = GTK_WIDGET (gtk_builder_get_object (builder,
4138  "BY_ACTION"));
4139  /* Adjust labels related to Num/Action radio buttons based on book option */
4140  reg = gnc_ledger_display_get_split_register (priv->ledger);
4141  if (reg && !reg->use_tran_num_for_num_field)
4142  {
4143  gtk_button_set_label (GTK_BUTTON (priv->sd.num_radio),
4144  _ ("Transaction Number"));
4145  gtk_button_set_label (GTK_BUTTON (priv->sd.act_radio), _ ("Number/Action"));
4146  }
4147  gnc_book_option_register_cb (OPTION_NAME_NUM_FIELD_SOURCE,
4148  (GncBOCb)gnc_plugin_page_register_sort_book_option_changed,
4149  page);
4150 
4151  /* Wire it up */
4152  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func,
4153  page);
4154 
4155  /* Show it */
4156  gtk_widget_show (dialog);
4157  g_object_unref (G_OBJECT (builder));
4158  LEAVE (" ");
4159 }
4160 
4161 static void
4162 gnc_plugin_page_register_cmd_view_filter_by (GSimpleAction *simple,
4163  GVariant *paramter,
4164  gpointer user_data)
4165 {
4166  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4168  GtkWidget* dialog, *toggle, *button, *table, *hbox;
4169  time64 start_time, end_time, time_val;
4170  GtkBuilder* builder;
4171  gboolean sensitive, value;
4172  Query* query;
4173  gchar* title;
4174  int i;
4175 
4176  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4177  ENTER ("(action %p, page %p)", simple, page);
4178 
4179  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4180  if (priv->fd.dialog)
4181  {
4182  gtk_window_present (GTK_WINDOW (priv->fd.dialog));
4183  LEAVE ("existing dialog");
4184  return;
4185  }
4186 
4187  /* Create the dialog */
4188  builder = gtk_builder_new();
4189  gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade",
4190  "days_adjustment");
4191  gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade",
4192  "filter_by_dialog");
4193  dialog = GTK_WIDGET (gtk_builder_get_object (builder, "filter_by_dialog"));
4194  priv->fd.dialog = dialog;
4195  gtk_window_set_transient_for (GTK_WINDOW (dialog),
4196  gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window)));
4197 
4198  /* Translators: The %s is the name of the plugin page */
4199  title = g_strdup_printf (_ ("Filter %s by…"),
4200  gnc_plugin_page_get_page_name (GNC_PLUGIN_PAGE (page)));
4201  gtk_window_set_title (GTK_WINDOW (dialog), title);
4202  g_free (title);
4203 
4204  /* Set the check buttons for the current status */
4205  for (i = 0; status_actions[i].action_name; i++)
4206  {
4207  toggle = GTK_WIDGET (gtk_builder_get_object (builder,
4208  status_actions[i].action_name));
4209  value = priv->fd.cleared_match & status_actions[i].value;
4210  status_actions[i].widget = toggle;
4211  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), value);
4212  }
4213  priv->fd.original_cleared_match = priv->fd.cleared_match;
4214 
4215  button = GTK_WIDGET (gtk_builder_get_object (builder, "filter_save"));
4216  if (priv->fd.save_filter == TRUE)
4217  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4218 
4219  // hide the save button if appropriate
4220  gtk_widget_set_visible (GTK_WIDGET (button),
4221  gnc_plugin_page_register_show_fs_save (page));
4222 
4223  /* Set up number of days */
4224  priv->fd.num_days = GTK_WIDGET (gtk_builder_get_object (builder,
4225  "filter_show_num_days"));
4226  button = GTK_WIDGET (gtk_builder_get_object (builder, "filter_show_days"));
4227 
4228  query = gnc_ledger_display_get_query (priv->ledger);
4229 
4230  if (priv->fd.days > 0) // using number of days
4231  {
4232  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4233  gtk_widget_set_sensitive (GTK_WIDGET (priv->fd.num_days), TRUE);
4234  gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->fd.num_days), priv->fd.days);
4235  priv->fd.original_days = priv->fd.days;
4236 
4237  /* Set the start_time and end_time to 0 */
4238  start_time = 0;
4239  end_time = 0;
4240  }
4241  else
4242  {
4243  gtk_widget_set_sensitive (GTK_WIDGET (priv->fd.num_days), FALSE);
4244  priv->fd.original_days = 0;
4245  priv->fd.days = 0;
4246 
4247  /* Get the start and end times */
4248  xaccQueryGetDateMatchTT (query, &start_time, &end_time);
4249  }
4250 
4251  /* Set the date info */
4252  priv->fd.original_start_time = start_time;
4253  priv->fd.start_time = start_time;
4254  priv->fd.original_end_time = end_time;
4255  priv->fd.end_time = end_time;
4256 
4257  button = GTK_WIDGET (gtk_builder_get_object (builder, "filter_show_range"));
4258  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), start_time ||
4259  end_time);
4260  table = GTK_WIDGET (gtk_builder_get_object (builder, "select_range_table"));
4261  priv->fd.table = table;
4262  gtk_widget_set_sensitive (GTK_WIDGET (table), start_time || end_time);
4263 
4264  priv->fd.start_date_choose = GTK_WIDGET (gtk_builder_get_object (builder,
4265  "start_date_choose"));
4266  priv->fd.start_date_today = GTK_WIDGET (gtk_builder_get_object (builder,
4267  "start_date_today"));
4268  priv->fd.end_date_choose = GTK_WIDGET (gtk_builder_get_object (builder,
4269  "end_date_choose"));
4270  priv->fd.end_date_today = GTK_WIDGET (gtk_builder_get_object (builder,
4271  "end_date_today"));
4272 
4273  {
4274  /* Start date info */
4275  if (start_time == 0)
4276  {
4277  button = GTK_WIDGET (gtk_builder_get_object (builder, "start_date_earliest"));
4278  time_val = xaccQueryGetEarliestDateFound (query);
4279  sensitive = FALSE;
4280  }
4281  else
4282  {
4283  time_val = start_time;
4284  if ((start_time >= gnc_time64_get_today_start()) &&
4285  (start_time <= gnc_time64_get_today_end()))
4286  {
4287  button = priv->fd.start_date_today;
4288  sensitive = FALSE;
4289  }
4290  else
4291  {
4292  button = priv->fd.start_date_choose;
4293  sensitive = TRUE;
4294  }
4295  }
4296  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4297  priv->fd.start_date = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE);
4298  hbox = GTK_WIDGET (gtk_builder_get_object (builder, "start_date_hbox"));
4299  gtk_box_pack_start (GTK_BOX (hbox), priv->fd.start_date, TRUE, TRUE, 0);
4300  gtk_widget_show (priv->fd.start_date);
4301  gtk_widget_set_sensitive (GTK_WIDGET (priv->fd.start_date), sensitive);
4302  gnc_date_edit_set_time (GNC_DATE_EDIT (priv->fd.start_date), time_val);
4303  g_signal_connect (G_OBJECT (priv->fd.start_date), "date-changed",
4304  G_CALLBACK (gnc_plugin_page_register_filter_gde_changed_cb),
4305  page);
4306  }
4307 
4308  {
4309  /* End date info */
4310  if (end_time == 0)
4311  {
4312  button = GTK_WIDGET (gtk_builder_get_object (builder, "end_date_latest"));
4313  time_val = xaccQueryGetLatestDateFound (query);
4314  sensitive = FALSE;
4315  }
4316  else
4317  {
4318  time_val = end_time;
4319  if ((end_time >= gnc_time64_get_today_start()) &&
4320  (end_time <= gnc_time64_get_today_end()))
4321  {
4322  button = priv->fd.end_date_today;
4323  sensitive = FALSE;
4324  }
4325  else
4326  {
4327  button = priv->fd.end_date_choose;
4328  sensitive = TRUE;
4329  }
4330  }
4331  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4332  priv->fd.end_date = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE);
4333  hbox = GTK_WIDGET (gtk_builder_get_object (builder, "end_date_hbox"));
4334  gtk_box_pack_start (GTK_BOX (hbox), priv->fd.end_date, TRUE, TRUE, 0);
4335  gtk_widget_show (priv->fd.end_date);
4336  gtk_widget_set_sensitive (GTK_WIDGET (priv->fd.end_date), sensitive);
4337  gnc_date_edit_set_time (GNC_DATE_EDIT (priv->fd.end_date), time_val);
4338  g_signal_connect (G_OBJECT (priv->fd.end_date), "date-changed",
4339  G_CALLBACK (gnc_plugin_page_register_filter_gde_changed_cb),
4340  page);
4341  }
4342 
4343  /* Wire it up */
4344  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func,
4345  page);
4346 
4347  /* Show it */
4348  gtk_widget_show (dialog);
4349  g_object_unref (G_OBJECT (builder));
4350  LEAVE (" ");
4351 }
4352 
4353 static void
4354 gnc_plugin_page_register_cmd_reload (GSimpleAction *simple,
4355  GVariant *paramter,
4356  gpointer user_data)
4357 {
4358  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4360  SplitRegister* reg;
4361 
4362  ENTER ("(action %p, page %p)", simple, page);
4363 
4364  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4365 
4366  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4367  reg = gnc_ledger_display_get_split_register (priv->ledger);
4368 
4369  /* Check for trans being edited */
4370  if (gnc_split_register_changed (reg))
4371  {
4372  LEAVE ("register has pending edits");
4373  return;
4374  }
4375  gnc_ledger_display_refresh (priv->ledger);
4376  LEAVE (" ");
4377 }
4378 
4379 static void
4380 gnc_plugin_page_register_cmd_style_changed (GSimpleAction *simple,
4381  GVariant *parameter,
4382  gpointer user_data)
4383 {
4384  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4386  SplitRegisterStyle value;
4387 
4388  ENTER ("(action %p, page %p)", simple, page);
4389 
4390  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4391 
4392  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4393 
4394  value = (SplitRegisterStyle)g_variant_get_int32 (parameter);
4395 
4396  g_action_change_state (G_ACTION(simple), parameter);
4397 
4398  gnc_split_reg_change_style (priv->gsr, value, priv->enable_refresh);
4399 
4400  gnc_plugin_page_register_ui_update (NULL, page);
4401  LEAVE (" ");
4402 }
4403 
4404 static void
4405 gnc_plugin_page_register_cmd_style_double_line (GSimpleAction *simple,
4406  GVariant *parameter,
4407  gpointer user_data)
4408 {
4409  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4411  SplitRegister* reg;
4412  gboolean use_double_line;
4413  GVariant *state;
4414 
4415  ENTER ("(action %p, page %p)", simple, page);
4416 
4417  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(page));
4418 
4419  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4420  reg = gnc_ledger_display_get_split_register (priv->ledger);
4421 
4422  state = g_action_get_state (G_ACTION(simple));
4423 
4424  g_action_change_state (G_ACTION(simple), g_variant_new_boolean (!g_variant_get_boolean (state)));
4425 
4426  use_double_line = !g_variant_get_boolean (state);
4427 
4428  if (use_double_line != reg->use_double_line)
4429  {
4430  gnc_split_register_config (reg, reg->type, reg->style, use_double_line);
4431  if (priv->enable_refresh)
4432  gnc_ledger_display_refresh (priv->ledger);
4433  }
4434  g_variant_unref (state);
4435  LEAVE (" ");
4436 }
4437 
4438 static void
4439 gnc_plugin_page_register_cmd_transfer (GSimpleAction *simple,
4440  GVariant *paramter,
4441  gpointer user_data)
4442 {
4443  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4444  Account* account;
4445  GncWindow* gnc_window;
4446  GtkWidget* window;
4447 
4448  ENTER ("(action %p, page %p)", simple, page);
4449 
4450  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4451 
4452  account = gnc_plugin_page_register_get_account (page);
4453  gnc_window = GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window);
4454  window = GTK_WIDGET (gnc_window_get_gtk_window (gnc_window));
4455  gnc_xfer_dialog (window, account);
4456  LEAVE (" ");
4457 }
4458 
4459 static void
4460 gnc_plugin_page_register_cmd_reconcile (GSimpleAction *simple,
4461  GVariant *paramter,
4462  gpointer user_data)
4463 {
4464  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4465  Account* account;
4466  GtkWindow* window;
4467  RecnWindow* recnData;
4468 
4469  ENTER ("(action %p, page %p)", simple, page);
4470 
4471  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4472 
4473  /* To prevent mistakes involving saving an edited transaction after
4474  * finishing a reconciliation (reverting the reconcile state), require
4475  * pending activity on the current register to be finished.
4476  *
4477  * The reconcile window isn't modal so it's still possible to start editing
4478  * a transaction after opening it, but at that point the user should know
4479  * what they're doing is unsafe.
4480  */
4481  if (!gnc_plugin_page_register_finish_pending (GNC_PLUGIN_PAGE (page)))
4482  return;
4483 
4484  account = gnc_plugin_page_register_get_account (page);
4485 
4486  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (
4487  page)->window));
4488  recnData = recnWindow (GTK_WIDGET (window), account);
4489  gnc_ui_reconcile_window_raise (recnData);
4490  LEAVE (" ");
4491 }
4492 
4493 static void
4494 gnc_plugin_page_register_cmd_stock_assistant (GSimpleAction *simple,
4495  GVariant *paramter,
4496  gpointer user_data)
4497 {
4498  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4499  Account *account;
4500  GtkWindow *window;
4501 
4502  ENTER ("(action %p, page %p)", simple, page);
4503 
4504  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4505  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window));
4506  account = gnc_plugin_page_register_get_account (page);
4507  gnc_stock_transaction_assistant (GTK_WIDGET (window), account);
4508 
4509  LEAVE (" ");
4510 }
4511 
4512 static void
4513 gnc_plugin_page_register_cmd_autoclear (GSimpleAction *simple,
4514  GVariant *paramter,
4515  gpointer user_data)
4516 {
4517  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4518  Account* account;
4519  GtkWindow* window;
4520  AutoClearWindow* autoClearData;
4521 
4522  ENTER ("(action %p, page %p)", simple, page);
4523 
4524  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4525 
4526  account = gnc_plugin_page_register_get_account (page);
4527 
4528  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (
4529  page)->window));
4530  autoClearData = autoClearWindow (GTK_WIDGET (window), account);
4531  gnc_ui_autoclear_window_raise (autoClearData);
4532  LEAVE (" ");
4533 }
4534 
4535 static void
4536 gnc_plugin_page_register_cmd_stock_split (GSimpleAction *simple,
4537  GVariant *paramter,
4538  gpointer user_data)
4539 {
4540  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4541  Account* account;
4542  GtkWindow* window;
4543 
4544  ENTER ("(action %p, page %p)", simple, page);
4545 
4546  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4547 
4548  account = gnc_plugin_page_register_get_account (page);
4549  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window));
4550  gnc_stock_split_dialog (GTK_WIDGET (window), account);
4551  LEAVE (" ");
4552 }
4553 
4554 static void
4555 gnc_plugin_page_register_cmd_lots (GSimpleAction *simple,
4556  GVariant *paramter,
4557  gpointer user_data)
4558 {
4559  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4560  GtkWindow* window;
4561  Account* account;
4562 
4563  ENTER ("(action %p, page %p)", simple, page);
4564 
4565  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4566 
4567  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (
4568  page)->window));
4569  account = gnc_plugin_page_register_get_account (page);
4570  gnc_lot_viewer_dialog (window, account);
4571  LEAVE (" ");
4572 }
4573 
4574 static void
4575 gnc_plugin_page_register_cmd_enter_transaction (GSimpleAction *simple,
4576  GVariant *paramter,
4577  gpointer user_data)
4578 {
4579  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4581 
4582  ENTER ("(action %p, page %p)", simple, page);
4583 
4584  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4585 
4586  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4587  gnc_split_reg_enter (priv->gsr, FALSE);
4588  LEAVE (" ");
4589 }
4590 
4591 static void
4592 gnc_plugin_page_register_cmd_cancel_transaction (GSimpleAction *simple,
4593  GVariant *paramter,
4594  gpointer user_data)
4595 {
4596  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4598 
4599  ENTER ("(action %p, page %p)", simple, page);
4600 
4601  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4602 
4603  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4605  (gnc_ledger_display_get_split_register (priv->ledger));
4606  LEAVE (" ");
4607 }
4608 
4609 static void
4610 gnc_plugin_page_register_cmd_delete_transaction (GSimpleAction *simple,
4611  GVariant *paramter,
4612  gpointer user_data)
4613 {
4614  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4616 
4617  ENTER ("(action %p, page %p)", simple, page);
4618 
4619  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4620 
4621  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4622  gsr_default_delete_handler (priv->gsr, NULL);
4623  LEAVE (" ");
4624 
4625 }
4626 
4627 static void
4628 gnc_plugin_page_register_cmd_linked_transaction (GSimpleAction *simple,
4629  GVariant *paramter,
4630  gpointer user_data)
4631 {
4632  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4634 
4635  ENTER ("(action %p, page %p)", simple, page);
4636 
4637  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4638 
4639  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4640  gsr_default_doclink_handler (priv->gsr);
4641  gnc_plugin_page_register_ui_update (NULL, page);
4642  LEAVE (" ");
4643 }
4644 
4645 static void
4646 gnc_plugin_page_register_cmd_linked_transaction_open (GSimpleAction *simple,
4647  GVariant *paramter,
4648  gpointer user_data)
4649 {
4650  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4652 
4653  ENTER ("(action %p, page %p)", simple, page);
4654 
4655  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4656 
4657  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4658  gsr_default_doclink_open_handler (priv->gsr);
4659  LEAVE (" ");
4660 }
4661 
4662 static GncInvoice* invoice_from_split (Split* split)
4663 {
4664  GncInvoice* invoice;
4665  GNCLot* lot;
4666 
4667  if (!split)
4668  return NULL;
4669 
4670  lot = xaccSplitGetLot (split);
4671  if (!lot)
4672  return NULL;
4673 
4674  invoice = gncInvoiceGetInvoiceFromLot (lot);
4675  if (!invoice)
4676  return NULL;
4677 
4678  return invoice;
4679 }
4680 
4681 
4682 static void
4683 gnc_plugin_page_register_cmd_jump_linked_invoice (GSimpleAction *simple,
4684  GVariant *paramter,
4685  gpointer user_data)
4686 {
4687  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4689  SplitRegister* reg;
4690  GncInvoice* invoice;
4691  Transaction *txn;
4692  GtkWidget *window;
4693 
4694  ENTER ("(action %p, page %p)", simple, page);
4695 
4696  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4697  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4698  reg = gnc_ledger_display_get_split_register (priv->gsr->ledger);
4700  invoice = invoice_from_split (gnc_split_register_get_current_split (reg));
4701  window = GNC_PLUGIN_PAGE(page)->window;
4702 
4703  if (!invoice)
4704  {
4705  auto invoices = invoices_from_transaction (txn);
4706  if (invoices.empty())
4707  PERR ("shouldn't happen: if no invoices, function is never called");
4708  else if (invoices.size() == 1)
4709  invoice = invoices[0];
4710  else
4711  {
4712  GList *details = NULL;
4713  gint choice;
4714  const gchar *amt;
4715  for (const auto& inv : invoices)
4716  {
4717  gchar *date = qof_print_date (gncInvoiceGetDatePosted (inv));
4718  amt = xaccPrintAmount
4719  (gncInvoiceGetTotal (inv),
4720  gnc_account_print_info (gncInvoiceGetPostedAcc (inv), TRUE));
4721  details = g_list_prepend
4722  (details,
4723  /* Translators: %s refer to the following in
4724  order: invoice type, invoice ID, owner name,
4725  posted date, amount */
4726  g_strdup_printf (_("%s %s from %s, posted %s, amount %s"),
4727  gncInvoiceGetTypeString (inv),
4728  gncInvoiceGetID (inv),
4729  gncOwnerGetName (gncInvoiceGetOwner (inv)),
4730  date, amt));
4731  g_free (date);
4732  }
4733  details = g_list_reverse (details);
4734  choice = gnc_choose_radio_option_dialog
4735  (window, _("Select Business Item"),
4736  _("Several business items are linked with this transaction. \
4737 Please choose one:"), _("Select"), 0, details);
4738  if ((choice >= 0) && ((size_t)choice < invoices.size()))
4739  invoice = invoices[choice];
4740  g_list_free_full (details, g_free);
4741  }
4742  }
4743 
4744  if (invoice)
4745  {
4746  GtkWindow *gtk_window = gnc_window_get_gtk_window (GNC_WINDOW (window));
4747  gnc_ui_invoice_edit (gtk_window, invoice);
4748  }
4749 
4750  LEAVE (" ");
4751 }
4752 
4753 static void
4754 gnc_plugin_page_register_cmd_blank_transaction (GSimpleAction *simple,
4755  GVariant *paramter,
4756  gpointer user_data)
4757 {
4758  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4760  SplitRegister* reg;
4761 
4762  ENTER ("(action %p, page %p)", simple, page);
4763 
4764  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4765 
4766  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4767  reg = gnc_ledger_display_get_split_register (priv->ledger);
4768 
4769  if (gnc_split_register_save (reg, TRUE))
4771 
4772  gnc_split_reg_jump_to_blank (priv->gsr);
4773  LEAVE (" ");
4774 }
4775 
4776 static bool
4777 find_after_date (Split *split, time64* find_date)
4778 {
4779  auto trans = xaccSplitGetParent (split);
4780  return !(xaccSplitGetAccount (split) != nullptr &&
4781  xaccTransGetDate (trans) >= *find_date &&
4782  xaccTransCountSplits (trans) != 1);
4783 }
4784 
4785 static void
4786 gnc_plugin_page_register_cmd_goto_date (GSimpleAction *simple,
4787  GVariant *paramter,
4788  gpointer user_data)
4789 {
4790  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4791  GNCSplitReg* gsr;
4792  Query* query;
4793  GList *splits;
4794  GtkWidget *window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
4795 
4796  ENTER ("(action %p, page %p)", simple, page);
4797  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4798 
4799  auto date = input_date (window, _("Go to Date"), _("Go to Date"));
4800 
4801  if (!date)
4802  {
4803  LEAVE ("goto_date cancelled");
4804  return;
4805  }
4806 
4807  gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE (page));
4808  query = gnc_plugin_page_register_get_query (GNC_PLUGIN_PAGE (page));
4809  splits = g_list_copy (qof_query_run (query));
4810  splits = g_list_sort (splits, (GCompareFunc)xaccSplitOrder);
4811 
4812  // if gl register, there could be blank splits from other open registers
4813  // included in split list so check for and ignore them
4814  auto it = g_list_find_custom (splits, &date.value(), (GCompareFunc)find_after_date);
4815 
4816  if (it)
4817  gnc_split_reg_jump_to_split (gsr, GNC_SPLIT(it->data));
4818  else
4819  gnc_split_reg_jump_to_blank (gsr);
4820 
4821  g_list_free (splits);
4822  LEAVE (" ");
4823 }
4824 
4825 static void
4826 gnc_plugin_page_register_cmd_duplicate_transaction (GSimpleAction *simple,
4827  GVariant *paramter,
4828  gpointer user_data)
4829 {
4830  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4832 
4833  ENTER ("(action %p, page %p)", simple, page);
4834 
4835  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4836 
4837  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4839  (gnc_ledger_display_get_split_register (priv->ledger));
4840  LEAVE (" ");
4841 }
4842 
4843 static void
4844 gnc_plugin_page_register_cmd_reinitialize_transaction (GSimpleAction *simple,
4845  GVariant *paramter,
4846  gpointer user_data)
4847 {
4848  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4850 
4851  ENTER ("(action %p, page %p)", simple, page);
4852 
4853  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4854 
4855  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4856  gsr_default_reinit_handler (priv->gsr, NULL);
4857  LEAVE (" ");
4858 }
4859 
4860 static void
4861 gnc_plugin_page_register_cmd_expand_transaction (GSimpleAction *simple,
4862  GVariant *parameter,
4863  gpointer user_data)
4864 {
4865  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4867  SplitRegister* reg;
4868  gboolean expand;
4869  GVariant *state;
4870 
4871  ENTER ("(action %p, page %p)", simple, page);
4872 
4873  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4874 
4875  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4876  reg = gnc_ledger_display_get_split_register (priv->ledger);
4877 
4878  state = g_action_get_state (G_ACTION(simple));
4879 
4880  g_action_change_state (G_ACTION(simple), g_variant_new_boolean (!g_variant_get_boolean (state)));
4881 
4882  expand = !g_variant_get_boolean (state);
4883 
4885  g_variant_unref (state);
4886  LEAVE (" ");
4887 }
4888 
4891 static void
4892 gnc_plugin_page_register_cmd_exchange_rate (GSimpleAction *simple,
4893  GVariant *paramter,
4894  gpointer user_data)
4895 {
4896  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4898  SplitRegister* reg;
4899 
4900  ENTER ("(action %p, page %p)", simple, page);
4901 
4902  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4903 
4904  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4905  reg = gnc_ledger_display_get_split_register (priv->ledger);
4906 
4907  /* XXX Ignore the return value -- we don't care if this succeeds */
4908  (void)gnc_split_register_handle_exchange (reg, TRUE);
4909  LEAVE (" ");
4910 }
4911 
4912 static Split*
4913 jump_multiple_splits_by_single_account (Account *account, Split *split)
4914 {
4915  Transaction *trans;
4916  SplitList *splits;
4917  Account *other_account = NULL;
4918  Split *other_split = NULL;
4919 
4920  trans = xaccSplitGetParent(split);
4921  if (!trans)
4922  return NULL;
4923 
4924  for (splits = xaccTransGetSplitList(trans); splits; splits = splits->next)
4925  {
4926  Split *s = (Split*)splits->data;
4927  Account *a = xaccSplitGetAccount(s);
4928 
4929  if (!xaccTransStillHasSplit(trans, s))
4930  continue;
4931 
4932  if (a == account)
4933  continue;
4934 
4935  if (other_split)
4936  {
4937  if (other_account != a)
4938  return NULL;
4939 
4940  continue;
4941  }
4942 
4943  other_account = a;
4944  other_split = s;
4945  }
4946 
4947  // Jump to the same account so that the right warning is triggered
4948  if (!other_split)
4949  other_split = split;
4950 
4951  return other_split;
4952 }
4953 
4954 static Split*
4955 jump_multiple_splits_by_value (Account *account, Split *split, gboolean largest)
4956 {
4957  Transaction *trans;
4958  SplitList *splits;
4959  Split *other_split = NULL;
4960  gnc_numeric best;
4961  int cmp = largest ? 1 : -1;
4962 
4963  trans = xaccSplitGetParent(split);
4964  if (!trans)
4965  return NULL;
4966 
4967  for (splits = xaccTransGetSplitList(trans); splits; splits = splits->next)
4968  {
4969  Split *s = (Split*)splits->data;
4970  gnc_numeric value;
4971 
4972  if (!xaccTransStillHasSplit(trans, s))
4973  continue;
4974 
4975  if (xaccSplitGetAccount(s) == account)
4976  continue;
4977 
4978  value = gnc_numeric_abs(xaccSplitGetValue(s));
4979  if (gnc_numeric_check(value))
4980  continue;
4981 
4982  /* For splits with the same value as the best, the first split
4983  * encountered is used.
4984  */
4985  if (other_split && gnc_numeric_compare(value, best) != cmp)
4986  continue;
4987 
4988  best = value;
4989  other_split = s;
4990  }
4991 
4992  // Jump to the same account so that the right warning is triggered
4993  if (!other_split)
4994  other_split = split;
4995 
4996  return other_split;
4997 }
4998 
4999 static Split*
5000 jump_multiple_splits (Account* account, Split *split)
5001 {
5002  GncPrefJumpMultSplits mode = (GncPrefJumpMultSplits)gnc_prefs_get_enum(GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_JUMP_MULT_SPLITS);
5003 
5004  switch (mode)
5005  {
5006  case JUMP_LARGEST_VALUE_FIRST_SPLIT:
5007  return jump_multiple_splits_by_value (account, split, TRUE);
5008 
5009  case JUMP_SMALLEST_VALUE_FIRST_SPLIT:
5010  return jump_multiple_splits_by_value (account, split, FALSE);
5011 
5012  case JUMP_DEFAULT:
5013  default:
5014  break;
5015  }
5016 
5017  // If there's only one other account, use that one
5018  return jump_multiple_splits_by_single_account (account, split);
5019 }
5020 
5021 static void
5022 gnc_plugin_page_register_cmd_jump (GSimpleAction *simple,
5023  GVariant *paramter,
5024  gpointer user_data)
5025 {
5026  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5028  GncPluginPage* new_page;
5029  GtkWidget* window;
5030  GNCSplitReg* gsr;
5031  SplitRegister* reg;
5032  Account* account;
5033  Account* leader;
5034  Split* split;
5035  Split* other_split;
5036  gboolean multiple_splits;
5037 
5038  ENTER ("(action %p, page %p)", simple, page);
5039 
5040  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5041 
5042  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5043  window = GNC_PLUGIN_PAGE (page)->window;
5044  if (window == NULL)
5045  {
5046  LEAVE ("no window");
5047  return;
5048  }
5049 
5050  reg = gnc_ledger_display_get_split_register (priv->ledger);
5052  if (split == NULL)
5053  {
5054  LEAVE ("no split (1)");
5055  return;
5056  }
5057 
5058  account = xaccSplitGetAccount (split);
5059  if (account == NULL)
5060  {
5061  LEAVE ("no account");
5062  return;
5063  }
5064 
5065  other_split = xaccSplitGetOtherSplit (split);
5066  multiple_splits = other_split == NULL;
5067 
5068  leader = gnc_ledger_display_leader (priv->ledger);
5069  if (account == leader)
5070  {
5072  if (cursor_class == CURSOR_CLASS_SPLIT)
5073  {
5074  /* If you've selected the transaction itself, we jump to the "other"
5075  * account corresponding to the anchoring split.
5076  *
5077  * If you've selected the split for another account, we jump to that
5078  * split's account (account != leader, so this block is never
5079  * reached).
5080  *
5081  * If you've selected a split for this account, for consistency with
5082  * selecting the split of another account we should do nothing.
5083  * You're already on the account for the split you selected. Jumping
5084  * to the "other" account now would make the "multiple split"
5085  * options confusing.
5086  *
5087  * We could jump to a different anchoring split but that'll be very
5088  * subtle and only cause problems because it'll have to save any
5089  * modifications to the current register.
5090  */
5091  LEAVE ("split for this account");
5092  return;
5093  }
5094 
5095  if (multiple_splits)
5096  {
5097  other_split = jump_multiple_splits (account, split);
5098  }
5099  if (other_split == NULL)
5100  {
5101  GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(window),
5102  (GtkDialogFlags)(GTK_DIALOG_MODAL
5103  | GTK_DIALOG_DESTROY_WITH_PARENT),
5104  GTK_MESSAGE_ERROR,
5105  GTK_BUTTONS_NONE,
5106  "%s",
5107  _("Unable to jump to other account"));
5108 
5109  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
5110  "%s", _("This transaction involves more than one other account. Select a specific split to jump to that account."));
5111  gtk_dialog_add_button (GTK_DIALOG(dialog), _("_OK"), GTK_RESPONSE_OK);
5112  gnc_dialog_run (GTK_DIALOG(dialog), GNC_PREF_WARN_REG_TRANS_JUMP_MULTIPLE_SPLITS);
5113  gtk_widget_destroy (dialog);
5114 
5115  LEAVE ("no split (2)");
5116  return;
5117  }
5118 
5119  split = other_split;
5120 
5121  account = xaccSplitGetAccount (split);
5122  if (account == NULL)
5123  {
5124  LEAVE ("no account (2)");
5125  return;
5126  }
5127 
5128  if (account == leader)
5129  {
5130  GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(window),
5131  (GtkDialogFlags)(GTK_DIALOG_MODAL
5132  | GTK_DIALOG_DESTROY_WITH_PARENT),
5133  GTK_MESSAGE_ERROR,
5134  GTK_BUTTONS_NONE,
5135  "%s",
5136  _("Unable to jump to other account"));
5137 
5138  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
5139  "%s", _("This transaction only involves the current account so there is no other account to jump to."));
5140  gtk_dialog_add_button (GTK_DIALOG(dialog), _("_OK"), GTK_RESPONSE_OK);
5141  gnc_dialog_run (GTK_DIALOG(dialog), GNC_PREF_WARN_REG_TRANS_JUMP_SINGLE_ACCOUNT);
5142  gtk_widget_destroy (dialog);
5143 
5144  LEAVE ("register open for account");
5145  return;
5146  }
5147  }
5148 
5149  new_page = gnc_plugin_page_register_new (account, FALSE);
5150  if (new_page == NULL)
5151  {
5152  LEAVE ("couldn't create new page");
5153  return;
5154  }
5155 
5156  gnc_main_window_open_page (GNC_MAIN_WINDOW (window), new_page);
5157  gsr = gnc_plugin_page_register_get_gsr (new_page);
5158 
5159  SplitRegister *new_page_reg = gnc_ledger_display_get_split_register (gsr->ledger);
5160  gboolean jump_twice = FALSE;
5161 
5162  /* Selecting the split (instead of just the transaction to open the "other"
5163  * account) requires jumping a second time after expanding the transaction,
5164  * in the basic and auto ledger modes.
5165  */
5166  if (new_page_reg->style != REG_STYLE_JOURNAL)
5167  jump_twice = TRUE;
5168 
5169  /* Test for visibility of split */
5170  if (gnc_split_reg_clear_filter_for_split (gsr, split))
5171  gnc_plugin_page_register_clear_current_filter (GNC_PLUGIN_PAGE(new_page));
5172 
5173  gnc_split_reg_jump_to_split (gsr, split);
5174 
5175  if (multiple_splits && jump_twice)
5176  {
5177  /* Expand the transaction for the basic and auto ledger to identify the
5178  * split in this register, but only if there are more than two splits.
5179  */
5180  gnc_split_register_expand_current_trans (new_page_reg, TRUE);
5181  gnc_split_reg_jump_to_split (gsr, split);
5182  }
5183  LEAVE (" ");
5184 }
5185 
5186 static void
5187 gnc_plugin_page_register_cmd_schedule (GSimpleAction *simple,
5188  GVariant *paramter,
5189  gpointer user_data)
5190 {
5191  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5193  GtkWindow* window;
5194 
5195  ENTER ("(action %p, page %p)", simple, page);
5196 
5197  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5198 
5199  window = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (
5200  page)));
5201  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5202  gsr_default_schedule_handler (priv->gsr, window);
5203  LEAVE (" ");
5204 }
5205 
5206 static void
5207 scrub_split (Split *split)
5208 {
5209  Account *acct;
5210  Transaction *trans;
5211  GNCLot *lot;
5212 
5213  g_return_if_fail (split);
5214  acct = xaccSplitGetAccount (split);
5215  trans = xaccSplitGetParent (split);
5216  lot = xaccSplitGetLot (split);
5217  g_return_if_fail (trans);
5218 
5219  xaccTransScrubOrphans (trans);
5220  xaccTransScrubImbalance (trans, gnc_get_current_root_account(), NULL);
5221  if (lot && xaccAccountIsAPARType (xaccAccountGetType (acct)))
5222  {
5223  gncScrubBusinessLot (lot);
5224  gncScrubBusinessSplit (split);
5225  }
5226 }
5227 
5228 static void
5229 gnc_plugin_page_register_cmd_scrub_current (GSimpleAction *simple,
5230  GVariant *paramter,
5231  gpointer user_data)
5232 {
5233  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5235  Query* query;
5236  SplitRegister* reg;
5237 
5238  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5239 
5240  ENTER ("(action %p, page %p)", simple, page);
5241 
5242  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5243  query = gnc_ledger_display_get_query (priv->ledger);
5244  if (query == NULL)
5245  {
5246  LEAVE ("no query found");
5247  return;
5248  }
5249 
5250  reg = gnc_ledger_display_get_split_register (priv->ledger);
5251 
5252  gnc_suspend_gui_refresh();
5253  scrub_split (gnc_split_register_get_current_split (reg));
5254  gnc_resume_gui_refresh();
5255  LEAVE (" ");
5256 }
5257 
5258 static gboolean
5259 scrub_kp_handler (GtkWidget *widget, GdkEventKey *event, gpointer data)
5260 {
5261  if (event->length == 0) return FALSE;
5262 
5263  switch (event->keyval)
5264  {
5265  case GDK_KEY_Escape:
5266  {
5267  auto abort_scrub = gnc_verify_dialog (GTK_WINDOW(widget), false,
5268  "%s", _(check_repair_abort_YN));
5269 
5270  if (abort_scrub)
5271  gnc_set_abort_scrub (TRUE);
5272 
5273  return TRUE;
5274  }
5275  default:
5276  break;
5277  }
5278  return FALSE;
5279 }
5280 
5281 static void
5282 gnc_plugin_page_register_cmd_scrub_all (GSimpleAction *simple,
5283  GVariant *paramter,
5284  gpointer user_data)
5285 {
5286  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5288  Query* query;
5289  GncWindow* window;
5290  GList* node, *splits;
5291  gint split_count = 0, curr_split_no = 0;
5292  gulong scrub_kp_handler_ID;
5293  const char* message = _ ("Checking splits in current register: %u of %u");
5294 
5295  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5296 
5297  ENTER ("(action %p, page %p)", simple, page);
5298 
5299  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5300  query = gnc_ledger_display_get_query (priv->ledger);
5301  if (!query)
5302  {
5303  LEAVE ("no query found");
5304  return;
5305  }
5306 
5307  gnc_suspend_gui_refresh();
5308  is_scrubbing = TRUE;
5309  gnc_set_abort_scrub (FALSE);
5310  window = GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window);
5311  scrub_kp_handler_ID = g_signal_connect (G_OBJECT (window), "key-press-event",
5312  G_CALLBACK (scrub_kp_handler), NULL);
5313  gnc_window_set_progressbar_window (window);
5314 
5315  splits = qof_query_run (query);
5316  split_count = g_list_length (splits);
5317  for (node = splits; node && !gnc_get_abort_scrub (); node = node->next, curr_split_no++)
5318  {
5319  auto split = GNC_SPLIT(node->data);
5320 
5321  if (!split) continue;
5322 
5323  PINFO ("Start processing split %d of %d",
5324  curr_split_no + 1, split_count);
5325 
5326  scrub_split (split);
5327 
5328  PINFO ("Finished processing split %d of %d",
5329  curr_split_no + 1, split_count);
5330 
5331  if (curr_split_no % 10 == 0)
5332  {
5333  char* progress_msg = g_strdup_printf (message, curr_split_no, split_count);
5334  gnc_window_show_progress (progress_msg, (100 * curr_split_no) / split_count);
5335  g_free (progress_msg);
5336  }
5337  }
5338 
5339  g_signal_handler_disconnect (G_OBJECT(window), scrub_kp_handler_ID);
5340  gnc_window_show_progress (NULL, -1.0);
5341  is_scrubbing = FALSE;
5342  show_abort_verify = TRUE;
5343  gnc_set_abort_scrub (FALSE);
5344 
5345  gnc_resume_gui_refresh();
5346  LEAVE (" ");
5347 }
5348 
5349 static void
5350 gnc_plugin_page_register_cmd_account_report (GSimpleAction *simple,
5351  GVariant *paramter,
5352  gpointer user_data)
5353 {
5354  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5356  GncMainWindow* window;
5357  int id;
5358 
5359  ENTER ("(action %p, page %p)", simple, page);
5360 
5361  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5362 
5363  window = GNC_MAIN_WINDOW (GNC_PLUGIN_PAGE (page)->window);
5364  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5365  id = report_helper (priv->ledger, NULL, NULL);
5366  if (id >= 0)
5367  gnc_main_window_open_report (id, window);
5368  LEAVE (" ");
5369 }
5370 
5371 static void
5372 gnc_plugin_page_register_cmd_transaction_report (GSimpleAction *simple,
5373  GVariant *paramter,
5374  gpointer user_data)
5375 {
5376  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5378  GncMainWindow* window;
5379  SplitRegister* reg;
5380  Split* split;
5381  Query* query;
5382  int id;
5383 
5384 
5385  ENTER ("(action %p, page %p)", simple, page);
5386 
5387  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5388 
5389  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5390  reg = gnc_ledger_display_get_split_register (priv->ledger);
5391 
5393  if (!split)
5394  return;
5395 
5396  query = qof_query_create_for (GNC_ID_SPLIT);
5397 
5398  qof_query_set_book (query, gnc_get_current_book());
5399 
5400  xaccQueryAddGUIDMatch (query, xaccSplitGetGUID (split),
5401  GNC_ID_SPLIT, QOF_QUERY_AND);
5402 
5403  window = GNC_MAIN_WINDOW (GNC_PLUGIN_PAGE (page)->window);
5404  id = report_helper (priv->ledger, split, query);
5405  if (id >= 0)
5406  gnc_main_window_open_report (id, window);
5407  LEAVE (" ");
5408 }
5409 
5410 /************************************************************/
5411 /* Auxiliary functions */
5412 /************************************************************/
5413 
5414 void
5416  gint lines_default,
5417  gboolean read_only)
5418 {
5419  GncPluginPageRegister* page;
5421 
5422  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
5423 
5424  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
5425  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5426  priv->lines_default = lines_default;
5427  priv->read_only = read_only;
5428 }
5429 
5430 GNCSplitReg*
5432 {
5433  GncPluginPageRegister* page;
5435 
5436  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page), NULL);
5437 
5438  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
5439  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5440 
5441  return priv->gsr;
5442 }
5443 
5444 static void
5445 gnc_plugin_page_help_changed_cb (GNCSplitReg* gsr,
5446  GncPluginPageRegister* register_page)
5447 {
5449  SplitRegister* reg;
5450  GncWindow* window;
5451  char* help;
5452 
5453  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (register_page));
5454 
5455  window = GNC_WINDOW (GNC_PLUGIN_PAGE (register_page)->window);
5456  if (!window)
5457  {
5458  // This routine can be called before the page is added to a
5459  // window.
5460  return;
5461  }
5462 
5463  // only update status text if on current page
5464  if (GNC_IS_MAIN_WINDOW(window) && (gnc_main_window_get_current_page
5465  (GNC_MAIN_WINDOW(window)) != GNC_PLUGIN_PAGE(register_page)))
5466  return;
5467 
5468  /* Get the text from the ledger */
5469  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (register_page);
5470  reg = gnc_ledger_display_get_split_register (priv->ledger);
5471  help = gnc_table_get_help (reg->table);
5472  gnc_window_set_status (window, GNC_PLUGIN_PAGE (register_page), help);
5473  g_free (help);
5474 }
5475 
5476 static void
5477 gnc_plugin_page_popup_menu_cb (GNCSplitReg* gsr,
5478  GncPluginPageRegister* page)
5479 {
5480  GncWindow* window;
5481 
5482  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5483 
5484  window = GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window);
5485  if (!window)
5486  {
5487  // This routine can be called before the page is added to a
5488  // window.
5489  return;
5490  }
5491  gnc_main_window_popup_menu_cb (GTK_WIDGET (window),
5492  GNC_PLUGIN_PAGE (page));
5493 }
5494 
5495 static void
5496 gnc_plugin_page_register_refresh_cb (GHashTable* changes, gpointer user_data)
5497 {
5498  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5500 
5501  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5502  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5503 
5504  if (changes)
5505  {
5506  const EventInfo* ei;
5507  ei = gnc_gui_get_entity_events (changes, &priv->key);
5508  if (ei)
5509  {
5510  if (ei->event_mask & QOF_EVENT_DESTROY)
5511  {
5512  gnc_main_window_close_page (GNC_PLUGIN_PAGE (page));
5513  return;
5514  }
5515  if (ei->event_mask & QOF_EVENT_MODIFY)
5516  {
5517  }
5518  }
5519  }
5520  else
5521  {
5522  /* forced updates */
5523  gnucash_register_refresh_from_prefs (priv->gsr->reg);
5524  gtk_widget_queue_draw (priv->widget);
5525  }
5526 
5527  gnc_plugin_page_register_ui_update (NULL, page);
5528 }
5529 
5530 static void
5531 gnc_plugin_page_register_close_cb (gpointer user_data)
5532 {
5533  GncPluginPage* plugin_page = GNC_PLUGIN_PAGE (user_data);
5534  gnc_main_window_close_page (plugin_page);
5535 }
5536 
5545 static void
5546 gppr_account_destroy_cb (Account* account)
5547 {
5548  GncPluginPageRegister* page;
5550  GNCLedgerDisplayType ledger_type;
5551  const GncGUID* acct_guid;
5552  const GList* citem;
5553  GList* item, *kill = NULL;
5554 
5555  acct_guid = xaccAccountGetGUID (account);
5556 
5557  /* Find all windows that need to be killed. Don't kill them yet, as
5558  * that would affect the list being walked.*/
5559  citem = gnc_gobject_tracking_get_list (GNC_PLUGIN_PAGE_REGISTER_NAME);
5560  for (; citem; citem = g_list_next (citem))
5561  {
5562  page = (GncPluginPageRegister*)citem->data;
5563  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5564  ledger_type = gnc_ledger_display_type (priv->ledger);
5565  if (ledger_type == LD_GL)
5566  {
5567  kill = g_list_prepend (kill, page);
5568  /* kill it */
5569  }
5570  else if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
5571  {
5572  if (guid_compare (acct_guid, &priv->key) == 0)
5573  {
5574  kill = g_list_prepend (kill, page);
5575  }
5576  }
5577  }
5578 
5579  kill = g_list_reverse (kill);
5580  /* Now kill them. */
5581  for (item = kill; item; item = g_list_next (item))
5582  {
5583  page = (GncPluginPageRegister*)item->data;
5584  gnc_main_window_close_page (GNC_PLUGIN_PAGE (page));
5585  }
5586  g_list_free (kill);
5587 }
5588 
5603 static void
5604 gnc_plugin_page_register_event_handler (QofInstance* entity,
5605  QofEventId event_type,
5606  GncPluginPageRegister* page,
5607  GncEventData* ed)
5608 {
5609  Transaction* trans;
5610  QofBook* book;
5611  GncPluginPage* visible_page;
5612  GtkWidget* window;
5613 
5614  g_return_if_fail (page); /* Required */
5615  if (!GNC_IS_TRANS (entity) && !GNC_IS_ACCOUNT (entity))
5616  return;
5617 
5618  ENTER ("entity %p of type %d, page %p, event data %p",
5619  entity, event_type, page, ed);
5620 
5621  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
5622 
5623  if (GNC_IS_ACCOUNT (entity))
5624  {
5625  if (GNC_IS_MAIN_WINDOW (window))
5626  {
5627  GncPluginPageRegisterPrivate *priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5628 
5629  if (!gnc_ledger_display_leader (priv->ledger))
5630  {
5631  LEAVE ("account is NULL");
5632  return;
5633  }
5634 
5635  gchar *name = gnc_plugin_page_register_get_tab_name (GNC_PLUGIN_PAGE (page));
5636  main_window_update_page_name (GNC_PLUGIN_PAGE (page), name);
5637 
5638  gchar *long_name = gnc_plugin_page_register_get_long_name (GNC_PLUGIN_PAGE (page));
5639  main_window_update_page_long_name (GNC_PLUGIN_PAGE (page), long_name);
5640 
5641  gchar *color = gnc_plugin_page_register_get_tab_color (GNC_PLUGIN_PAGE (page));
5642  main_window_update_page_color (GNC_PLUGIN_PAGE (page), color);
5643  // update page icon if read only registers
5644  gnc_plugin_page_register_update_page_icon (GNC_PLUGIN_PAGE (page));
5645 
5646  g_free (color);
5647  g_free (name);
5648  g_free (long_name);
5649  }
5650  LEAVE ("tab contents updated");
5651  return;
5652  }
5653 
5654  if (! (event_type & (QOF_EVENT_MODIFY | QOF_EVENT_DESTROY)))
5655  {
5656  LEAVE ("not a modify");
5657  return;
5658  }
5659  trans = GNC_TRANS (entity);
5660  book = qof_instance_get_book (QOF_INSTANCE (trans));
5661  if (!gnc_plugin_page_has_book (GNC_PLUGIN_PAGE (page), book))
5662  {
5663  LEAVE ("not in this book");
5664  return;
5665  }
5666 
5667  if (GNC_IS_MAIN_WINDOW (window))
5668  {
5669  visible_page = gnc_main_window_get_current_page (GNC_MAIN_WINDOW (window));
5670  if (visible_page != GNC_PLUGIN_PAGE (page))
5671  {
5672  LEAVE ("page not visible");
5673  return;
5674  }
5675  }
5676 
5677  gnc_plugin_page_register_ui_update (NULL, page);
5678  LEAVE (" ");
5679  return;
5680 }
5681 
5682 
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 gnc_ledger_display_close(GNCLedgerDisplay *ld)
close the window
GncPluginPage * gnc_plugin_page_register_new(Account *account, gboolean subaccounts)
Create a new "register" plugin page, given a pointer to an account.
void gnc_ledger_display_set_focus(GNCLedgerDisplay *ld, gboolean focus)
Mark the ledger as being in focus (refresh immediately) or not.
Functions to load, save and get gui state.
gint xaccSplitOrder(const Split *sa, const Split *sb)
The xaccSplitOrder(sa,sb) method is useful for sorting.
Definition: Split.cpp:1500
GtkWidget * gnc_plugin_page_get_window(GncPluginPage *page)
Retrieve a pointer to the GncMainWindow (GtkWindow) containing this page.
gboolean xaccTransHasReconciledSplits(const Transaction *trans)
FIXME: document me.
void gnc_ledger_display_refresh(GNCLedgerDisplay *ld)
redisplay/redraw only the indicated window.
const gchar * tab_icon
The relative name of the icon that should be shown on the tab for this page.
const char * gnc_split_register_get_credit_string(SplitRegister *reg)
Return the credit string used in the register.
gboolean(* focus_page_function)(GncPluginPage *plugin_page)
This function performs specific actions to set the focus on a specific widget.
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
void gnc_main_window_update_menu_and_toolbar(GncMainWindow *window, GncPluginPage *page, const gchar **ui_updates)
Update the main window menu with the placeholders listed in ui_updates and load the page specific too...
void(* focus_page)(GncPluginPage *plugin_page, gboolean on_current_page)
Perform plugin specific actions to set the focus.
void gnc_plugin_page_register_filter_save_cb(GtkToggleButton *button, GncPluginPageRegister *page)
This function is called whenever the save status is checked or unchecked.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
The instance data structure for a content plugin.
const GList * gnc_gobject_tracking_get_list(const gchar *name)
Get a list of all known objects of a specified type.
void gnc_plugin_page_register_filter_days_changed_cb(GtkSpinButton *button, GncPluginPageRegister *page)
This function is called when the "number of days" spin button is changed which is then saved and upda...
gboolean xaccTransIsReadonlyByPostedDate(const Transaction *trans)
Returns TRUE if this Transaction is read-only because its posted-date is older than the "auto-readonl...
Date and Time handling routines.
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.cpp:127
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...
gchar * gnc_g_list_stringjoin(GList *list_of_strings, const gchar *sep)
Return a string joining a GList whose elements are gchar* strings.
void gnc_split_register_unvoid_current_trans(SplitRegister *reg)
Unvoids the transaction associated with the current cursor, if non-NULL.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.cpp:4510
void(* QofEventHandler)(QofInstance *ent, QofEventId event_type, gpointer handler_data, gpointer event_data)
Handler invoked when an event is generated.
Definition: qofevent.h:89
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
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
void gnc_main_window_set_vis_of_items_by_action(GncMainWindow *window, const gchar **action_names, gboolean vis)
Show or hide menu and toolbar items based on a NULL terminated list of action names.
void qof_query_purge_terms(QofQuery *q, QofQueryParamList *param_list)
Remove query terms of a particular type from q.
Definition: qofquery.cpp:705
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3241
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...
gtk helper routines.
GncPluginPage *(* recreate_page)(GtkWidget *window, GKeyFile *file, const gchar *group)
Create a new page based on the information saved during a previous instantiation of gnucash...
gboolean gnc_menubar_model_find_item(GMenuModel *menu_model, GncMenuModelSearch *gsm)
Find a GtkMenu item from the action name.
STRUCTS.
gint gnc_state_drop_sections_for(const gchar *partial_name)
Drop all sections from the state file whose name contains partial_name.
Definition: gnc-state.c:260
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
const gchar * gnc_plugin_page_get_page_name(GncPluginPage *page)
Retrieve the name of this page.
gboolean string_to_guid(const gchar *string, GncGUID *guid)
Given a string, replace the given guid with the parsed one unless the given value is null...
Functions that are supported by all types of windows.
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
GSimpleActionGroup * gnc_plugin_page_get_action_group(GncPluginPage *page)
Retrieve the GSimpleActionGroup object associated with this page.
gpointer gnc_account_foreach_descendant_until(const Account *acc, AccountCb2 thunk, gpointer user_data)
This method will traverse all children of this accounts and their descendants, calling &#39;func&#39; on each...
Definition: Account.cpp:3218
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
void gnc_plugin_add_toolbar_tooltip_callbacks(GtkWidget *toolbar, GtkWidget *statusbar)
This function adds the tooltip callbacks to make the tooltips appear in the status bar...
Definition: gnc-plugin.c:299
void gnc_plugin_page_register_sort_response_cb(GtkDialog *dialog, gint response, GncPluginPageRegister *plugin_page)
This function is called when the "Sort By…" dialog is closed.
QofQuery * qof_query_copy(QofQuery *q)
Make a copy of the indicated query.
Definition: qofquery.cpp:1018
gboolean qof_query_equal(const QofQuery *q1, const QofQuery *q2)
Compare two queries for equality.
Definition: qofquery.cpp:1472
GtkWidget * window
The window that contains the display widget for this plugin.
Account * gnc_ledger_display_leader(GNCLedgerDisplay *ld)
Implementations.
void gnc_plugin_page_set_page_long_name(GncPluginPage *page, const char *name)
Set the long name of this page.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
void gnc_tm_get_today_start(struct tm *tm)
The gnc_tm_get_today_start() routine takes a pointer to a struct tm and fills it in with the first se...
Definition: gnc-date.cpp:1399
GSimpleActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GSimpleActionGroup object associated with this page.
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:208
void gnc_ledger_display_set_query(GNCLedgerDisplay *ledger_display, Query *q)
Set the query used for a register.
gint gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
Cleanup functions for business objects.
gnc_numeric gncInvoiceGetTotal(GncInvoice *invoice)
Return the "total" amount of the invoice as seen on the document (and shown to the user in the report...
Definition: gncInvoice.c:1008
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition: gnc-state.c:248
void gnc_ui_edit_account_window(GtkWindow *parent, Account *account)
Display a window for editing the attributes of an existing account.
gboolean gnc_split_register_current_trans_expanded(SplitRegister *reg)
Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER.
GncPluginPage * gnc_main_window_get_current_page(GncMainWindow *window)
Retrieve a pointer to the page that is currently at the front of the specified window.
const char * xaccTransGetDocLink(const Transaction *trans)
Gets the transaction Document Link.
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
Query * gnc_ledger_display_get_query(GNCLedgerDisplay *ld)
return the query associated with a ledger
Functions for adding content to a window.
void gnc_plugin_add_menu_tooltip_callbacks(GtkWidget *menubar, GMenuModel *menubar_model, GtkWidget *statusbar)
This function adds the tooltip callbacks to make the tooltips appear in the status bar...
Definition: gnc-plugin.c:268
GncPluginPage * gnc_plugin_page_register_new_ledger(GNCLedgerDisplay *ledger)
Create a new "register" plugin page, given a pointer to an already created ledger.
void(* update_edit_menu_actions)(GncPluginPage *plugin_page, gboolean hide)
This function vector allows page specific actions to override the generic code for setting the sensit...
#define VREC
split is void
Definition: Split.h:77
void(* destroy_widget)(GncPluginPage *plugin_page)
Function called to destroy the display widget for a particular type of plugin.
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition: qofevent.cpp:73
void main_window_update_page_long_name(GncPluginPage *page, const gchar *long_name_in)
Update the long name of the page in the main window.
void gnc_tm_free(struct tm *time)
free a struct tm* created with gnc_localtime() or gnc_gmtime()
Definition: gnc-date.cpp:97
const char * xaccAccountGetColor(const Account *acc)
Get the account&#39;s color.
Definition: Account.cpp:3324
void gnc_plugin_page_register_filter_select_range_cb(GtkRadioButton *button, GncPluginPageRegister *page)
This function is called when the radio buttons changes state.
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
GNCLedgerDisplay * gnc_ledger_display_subaccounts(Account *account, gboolean mismatched_commodities)
opens up a register window to display the parent account and all of its children. ...
#define xaccAccountGetGUID(X)
Definition: Account.h:252
void gnc_set_abort_scrub(gboolean abort)
The gnc_set_abort_scrub () method causes a currently running scrub operation to stop, if abort is TRUE; gnc_set_abort_scrub(FALSE) must be called before any scrubbing operation.
Definition: Scrub.cpp:75
void gnc_plugin_page_register_sort_button_cb(GtkToggleButton *button, GncPluginPageRegister *page)
This function is called when a radio button in the "Sort By…" dialog is clicked. ...
convert single-entry accounts to clean double-entry
char * qof_print_date(time64 secs)
Convenience; calls through to qof_print_date_dmy_buff().
Definition: gnc-date.cpp:610
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
gboolean xaccTransHasSplitsInState(const Transaction *trans, const char state)
FIXME: document me.
gboolean gnc_split_register_has_copied_item(void)
Return TRUE if copied_item holds a transaction or split.
QofBook * qof_session_get_book(const QofSession *session)
Returns the QofBook of this session.
Definition: qofsession.cpp:575
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3279
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
Functions providing a register page for the GnuCash UI.
const char * gnc_split_register_get_debit_string(SplitRegister *reg)
Return the debit string used in the register.
void main_window_update_page_color(GncPluginPage *page, const gchar *color_in)
Update the color on the page tabs in the main window.
The class data structure for a content plugin.
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
gint QofEventId
Define the type of events allowed.
Definition: qofevent.h:45
Gobject helper routines.
void gnc_plugin_page_register_filter_end_cb(GtkWidget *radio, GncPluginPageRegister *page)
This function is called when one of the end date radio buttons is selected.
void gnc_plugin_page_set_use_new_window(GncPluginPage *page, gboolean use_new)
Set the "use new window" setting associated with this page.
CursorClass
Types of cursors.
GAction * gnc_main_window_find_action(GncMainWindow *window, const gchar *action_name)
Find the GAction in the main window.
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition: guid.h:84
Transaction * gnc_plugin_page_register_get_current_txn(GncPluginPageRegister *page)
Get the currently selected transaction in this register page.
gboolean gnc_split_register_changed(SplitRegister *reg)
Returns TRUE if the register has changed cells.
void xaccTransScrubImbalance(Transaction *trans, Account *root, Account *account)
Correct transaction imbalances.
Definition: Scrub.cpp:845
void gnc_plugin_page_disconnect_page_changed(GncPluginPage *page)
Disconnect the page_changed_id signal callback.
gint gnc_prefs_get_enum(const gchar *group, const gchar *pref_name)
Get an enum value from the preferences backend.
gboolean gncScrubBusinessSplit(Split *split)
The gncScrubBusinessSplit() function will fix all issues found with the given split.
void gnc_plugin_page_register_filter_start_cb(GtkWidget *radio, GncPluginPageRegister *page)
This function is called when one of the start date radio buttons is selected.
Functions providing menu items from scheme code.
void qof_query_set_book(QofQuery *query, QofBook *book)
Set the book to be searched.
gboolean gnc_plugin_page_has_book(GncPluginPage *page, QofBook *book)
Query a page to see if it has a reference to a given book.
void(* window_changed)(GncPluginPage *plugin_page, GtkWidget *window)
Perform plugin specific actions when a page is added to a window (or has been removed from one window...
gboolean gnc_main_window_popup_menu_cb(GtkWidget *widget, GncPluginPage *page)
Callback function invoked when the user requests that Gnucash popup the contextual menu via the keybo...
time64 gnc_time64_get_day_start(time64 time_val)
The gnc_time64_get_day_start() routine will take the given time in seconds and adjust it to the first...
Definition: gnc-date.cpp:1366
void gnc_plugin_page_register_filter_response_cb(GtkDialog *dialog, gint response, GncPluginPageRegister *plugin_page)
This function is called when the "Filter By…" dialog is closed.
const gchar * plugin_name
The textual name of this plugin.
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.
gchar * gnc_list_formatter(GList *strings)
This function takes a GList of char*, and uses locale-sensitive list formatter.
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
Definition: qofevent.cpp:103
GtkWidget *(* create_widget)(GncPluginPage *plugin_page)
Function called to create the display widget for a particular type of plugin.
time64 gnc_time64_get_today_start(void)
The gnc_time64_get_today_start() routine returns a time64 value corresponding to the first second of ...
Definition: gnc-date.cpp:1417
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
The gnc_account_lookup_full_name() subroutine works like gnc_account_lookup_by_name, but uses fully-qualified names using the given separator.
Definition: Account.cpp:3137
void gnc_split_register_void_current_trans(SplitRegister *reg, const char *reason)
Voids the transaction associated with the current cursor, if non-NULL.
time64 gnc_mktime(struct tm *time)
calculate seconds from the epoch given a time struct
Definition: gnc-date.cpp:219
void xaccTransScrubOrphans(Transaction *trans)
The xaccTransScrubOrphans() method scrubs only the splits in the given transaction.
Definition: Scrub.cpp:179
void gnc_plugin_set_actions_enabled(GActionMap *action_map, const gchar **action_names, gboolean enable)
This function sets the sensitivity of a GAction in a specific group.
Definition: gnc-plugin.c:250
Gnome specific utility functions.
Public declarations of GnucashRegister class.
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition: Account.cpp:4486
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
Additional event handling code.
#define xaccSplitGetGUID(X)
Definition: Split.h:552
struct tm * gnc_localtime(const time64 *secs)
fill out a time struct from a 64-bit time value.
Definition: gnc-date.cpp:103
gboolean(* finish_pending)(GncPluginPage *plugin_page)
This function vector is called to finish any outstanding activities.
All type declarations for the whole Gnucash engine.
#define CREC
The Split has been cleared.
Definition: Split.h:73
void(* save_page)(GncPluginPage *page, GKeyFile *file, const gchar *group)
Save enough information about this page so that it can be recreated next time the user starts gnucash...
gnc_commodity * gnc_account_get_currency_or_parent(const Account *account)
Returns a gnc_commodity that is a currency, suitable for being a Transaction&#39;s currency.
Definition: Account.cpp:3382
void gnc_plugin_page_register_filter_status_one_cb(GtkToggleButton *button, GncPluginPageRegister *page)
This function is called whenever one of the status entries is checked or unchecked.
GLib helper routines.
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_plugin_page_register_filter_status_clear_all_cb(GtkButton *button, GncPluginPageRegister *plugin_page)
This function is called whenever the "clear all" status button is clicked.
void gnc_add_accelerator_keys_for_menu(GtkWidget *menu, GMenuModel *model, GtkAccelGroup *accel_group)
Add accelerator keys for menu item widgets.
Query * gnc_plugin_page_register_get_query(GncPluginPage *plugin_page)
This function is called to get the query associated with this plugin page.
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...
void gnc_plugin_init_short_names(GtkWidget *toolbar, GncToolBarShortNames *toolbar_labels)
Add "short" labels to existing actions.
Definition: gnc-plugin.c:229
GncInvoice * gncInvoiceGetInvoiceFromLot(GNCLot *lot)
Given a LOT, find and return the Invoice attached to the lot.
Definition: gncInvoice.c:1288
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...
GList * qof_query_run(QofQuery *query)
Perform the query, return the results.
void main_window_update_page_set_read_only_icon(GncPluginPage *page, gboolean read_only)
Update the icon on the page tabs in the main window.
gboolean qof_book_is_readonly(const QofBook *book)
Return whether the book is read only.
Definition: qofbook.cpp:497
A structure for defining alternate action names for use in the toolbar.
void gnc_plugin_page_set_page_color(GncPluginPage *page, const char *color)
Set the color of this page.
GncPluginPage * gnc_plugin_page_register_new_gl(void)
Create a new "register" plugin page containing a general journal.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
GNCLedgerDisplay * gnc_ledger_display_simple(Account *account)
opens up a register window to display a single account
gboolean gncScrubBusinessLot(GNCLot *lot)
The gncScrubBusinessLot() function makes sure that the indicated lot has all the correct properties r...
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3375
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:165
void gnc_plugin_page_register_filter_status_select_all_cb(GtkButton *button, GncPluginPageRegister *plugin_page)
This function is called whenever the "select all" status button is clicked.
time64 gnc_time64_get_today_end(void)
The gnc_time64_get_today_end() routine returns a time64 value corresponding to the last second of tod...
Definition: gnc-date.cpp:1426
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void gnc_plugin_page_set_menu_popup_qualifier(GncPluginPage *page, const char *menu_qualifier)
Set a qualifier string for this page.
void gnc_plugin_page_inserted_cb(GncPluginPage *page, gpointer user_data)
Set up the page_changed callback for when the current page is changed.
void gnc_main_window_close_page(GncPluginPage *page)
Remove a data plugin page from a window and display the previous page.
Transaction * xaccTransGetReversedBy(const Transaction *trans)
Returns the transaction that reversed the given transaction.
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
void gnc_plugin_page_set_page_name(GncPluginPage *page, const char *name)
Set the name of this page.
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:262
Account * gnc_plugin_page_register_get_account(GncPluginPageRegister *page)
Get the Account associated with this register page.
void gnc_plugin_page_add_book(GncPluginPage *page, QofBook *book)
Add a book reference to the specified page.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void gnc_plugin_page_register_sort_order_save_cb(GtkToggleButton *button, GncPluginPageRegister *page)
This function is called whenever the save sort order is checked or unchecked which allows saving of t...
gboolean gnc_split_register_handle_exchange(SplitRegister *reg, gboolean force_dialog)
If needed display the transfer dialog to get a price/exchange rate and adjust the price cell accordin...
void gnc_plugin_page_register_clear_current_filter(GncPluginPage *plugin_page)
This function clears the registers current filter.
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
GNCLedgerDisplay * gnc_ledger_display_gl(void)
opens up a general ledger window
time64 gnc_time64_get_day_end(time64 time_val)
The gnc_time64_get_day_end() routine will take the given time in seconds and adjust it to the last se...
Definition: gnc-date.cpp:1386
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:3263
The type used to store guids in C.
Definition: guid.h:75
GNCSplitReg * gnc_plugin_page_register_get_gsr(GncPluginPage *plugin_page)
Get the GNCSplitReg data structure associated with this register page.
void gnc_plugin_page_register_sort_order_reverse_cb(GtkToggleButton *button, GncPluginPageRegister *page)
This function is called whenever the reverse sort order is checked or unchecked which allows reversin...
void main_window_update_page_name(GncPluginPage *page, const gchar *name_in)
Update the name of the page in the main window.
A Query.
Definition: qofquery.cpp:74
gboolean gnc_menubar_model_update_item(GMenuModel *menu_model, const gchar *action_name, const gchar *target, const gchar *label, const gchar *accel_name, const gchar *tooltip)
Update the GMenuModel item based on the action name by copying existing item, removing it and inserti...
GAction * gnc_plugin_page_get_action(GncPluginPage *page, const gchar *name)
Retrieve a GAction object associated with this page.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.
void gnc_plugin_page_register_set_options(GncPluginPage *plugin_page, gint lines_default, gboolean read_only)
Set various register options on a newly created "register" plugin page.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
GtkWidget * summarybar
The summary bar widget (if any) that is associated with this plugin.
SplitRegisterStyle
Register styles.
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn&#39;t be...
Definition: Split.cpp:1884
GList * qof_query_get_books(QofQuery *q)
Return the list of books we&#39;re using.
Definition: qofquery.cpp:1341
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.cpp:142
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...
Utility functions for file access.
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2048