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