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