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