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