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 
1513  if (GTK_IS_WIDGET(priv->gsr))
1514  gtk_widget_destroy(GTK_WIDGET(priv->gsr));
1515 
1516  gnc_ledger_display_close (priv->ledger);
1517  priv->ledger = NULL;
1518  LEAVE (" ");
1519 }
1520 
1521 static void
1522 gnc_plugin_page_register_window_changed (GncPluginPage* plugin_page,
1523  GtkWidget* window)
1524 {
1525  GncPluginPageRegister* page;
1527 
1528  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
1529 
1530  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1531  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1532  priv->gsr->window =
1533  GTK_WIDGET (gnc_window_get_gtk_window (GNC_WINDOW (window)));
1534 }
1535 
1536 static const gchar* style_names[] =
1537 {
1538  "Ledger",
1539  "Auto Ledger",
1540  "Journal",
1541  NULL
1542 };
1543 
1544 #define KEY_REGISTER_TYPE "RegisterType"
1545 #define KEY_ACCOUNT_NAME "AccountName"
1546 #define KEY_ACCOUNT_GUID "AccountGuid"
1547 #define KEY_REGISTER_STYLE "RegisterStyle"
1548 #define KEY_DOUBLE_LINE "DoubleLineMode"
1549 
1550 #define LABEL_ACCOUNT "Account"
1551 #define LABEL_SUBACCOUNT "SubAccount"
1552 #define LABEL_GL "GL"
1553 #define LABEL_SEARCH "Search"
1554 
1555 
1565 static void
1566 gnc_plugin_page_register_save_page (GncPluginPage* plugin_page,
1567  GKeyFile* key_file,
1568  const gchar* group_name)
1569 {
1570  GncPluginPageRegister* page;
1572  GNCLedgerDisplayType ledger_type;
1573  SplitRegister* reg;
1574  Account* leader;
1575 
1576  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
1577  g_return_if_fail (key_file != NULL);
1578  g_return_if_fail (group_name != NULL);
1579 
1580  ENTER ("page %p, key_file %p, group_name %s", plugin_page, key_file,
1581  group_name);
1582 
1583  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1584  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1585 
1586  reg = gnc_ledger_display_get_split_register (priv->ledger);
1587  ledger_type = gnc_ledger_display_type (priv->ledger);
1588  if (ledger_type > LD_GL)
1589  {
1590  LEAVE ("Unsupported ledger type");
1591  return;
1592  }
1593  if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
1594  {
1595  const gchar* label;
1596  gchar* name;
1597  gchar acct_guid[GUID_ENCODING_LENGTH + 1];
1598  label = (ledger_type == LD_SINGLE) ? LABEL_ACCOUNT : LABEL_SUBACCOUNT;
1599  leader = gnc_ledger_display_leader (priv->ledger);
1600  g_key_file_set_string (key_file, group_name, KEY_REGISTER_TYPE, label);
1601  name = gnc_account_get_full_name (leader);
1602  g_key_file_set_string (key_file, group_name, KEY_ACCOUNT_NAME, name);
1603  g_free (name);
1604  guid_to_string_buff (xaccAccountGetGUID (leader), acct_guid);
1605  g_key_file_set_string (key_file, group_name, KEY_ACCOUNT_GUID, acct_guid);
1606  }
1607  else if (reg->type == GENERAL_JOURNAL)
1608  {
1609  g_key_file_set_string (key_file, group_name, KEY_REGISTER_TYPE,
1610  LABEL_GL);
1611  }
1612  else if (reg->type == SEARCH_LEDGER)
1613  {
1614  g_key_file_set_string (key_file, group_name, KEY_REGISTER_TYPE,
1615  LABEL_SEARCH);
1616  }
1617  else
1618  {
1619  LEAVE ("Unsupported register type");
1620  return;
1621  }
1622 
1623  g_key_file_set_string (key_file, group_name, KEY_REGISTER_STYLE,
1624  style_names[reg->style]);
1625  g_key_file_set_boolean (key_file, group_name, KEY_DOUBLE_LINE,
1626  reg->use_double_line);
1627 
1628  LEAVE(" ");
1629 }
1630 
1631 
1644 static void
1645 gnc_plugin_page_register_restore_edit_menu (GncPluginPage* page,
1646  GKeyFile* key_file,
1647  const gchar* group_name)
1648 {
1649  GAction* action;
1650  GVariant *state;
1651  GError* error = NULL;
1652  gchar* style_name;
1653  gint i;
1654  gboolean use_double_line;
1655 
1656  ENTER (" ");
1657 
1658  /* Convert the style name to an index */
1659  style_name = g_key_file_get_string (key_file, group_name,
1660  KEY_REGISTER_STYLE, &error);
1661  for (i = 0 ; style_names[i]; i++)
1662  {
1663  if (g_ascii_strcasecmp (style_name, style_names[i]) == 0)
1664  {
1665  DEBUG ("Found match for style name: %s", style_name);
1666  break;
1667  }
1668  }
1669  g_free (style_name);
1670 
1671  /* Update the style menu action for this page */
1672  if (i <= REG_STYLE_JOURNAL)
1673  {
1674  DEBUG ("Setting style: %d", i);
1675  action = gnc_plugin_page_get_action (page, "ViewStyleRadioAction");
1676  g_action_activate (G_ACTION(action), g_variant_new_int32 (i));
1677  }
1678 
1679  /* Update the double line action on this page */
1680  use_double_line = g_key_file_get_boolean (key_file, group_name,
1681  KEY_DOUBLE_LINE, &error);
1682  DEBUG ("Setting double_line_mode: %d", use_double_line);
1683  action = gnc_plugin_page_get_action (page, "ViewStyleDoubleLineAction");
1684 
1685  state = g_action_get_state (G_ACTION(action));
1686 
1687  if (use_double_line != g_variant_get_boolean (state))
1688  g_action_activate (G_ACTION(action), NULL);
1689 
1690  g_variant_unref (state);
1691 
1692  LEAVE (" ");
1693 }
1694 
1695 
1705 static GncPluginPage*
1706 gnc_plugin_page_register_recreate_page (GtkWidget* window,
1707  GKeyFile* key_file,
1708  const gchar* group_name)
1709 {
1711  GncPluginPage* page;
1712  GError* error = NULL;
1713  gchar* reg_type, *acct_guid;
1714  GncGUID guid;
1715  Account* account = NULL;
1716  QofBook* book;
1717  gboolean include_subs;
1718 
1719  g_return_val_if_fail (key_file, NULL);
1720  g_return_val_if_fail (group_name, NULL);
1721  ENTER ("key_file %p, group_name %s", key_file, group_name);
1722 
1723  /* Create the new page. */
1724  reg_type = g_key_file_get_string (key_file, group_name,
1725  KEY_REGISTER_TYPE, &error);
1726  DEBUG ("Page type: %s", reg_type);
1727  if ((g_ascii_strcasecmp (reg_type, LABEL_ACCOUNT) == 0) ||
1728  (g_ascii_strcasecmp (reg_type, LABEL_SUBACCOUNT) == 0))
1729  {
1730  include_subs = (g_ascii_strcasecmp (reg_type, LABEL_SUBACCOUNT) == 0);
1731  DEBUG ("Include subs: %d", include_subs);
1732  book = qof_session_get_book (gnc_get_current_session());
1733  if (!book)
1734  {
1735  LEAVE("Session has no book");
1736  return NULL;
1737  }
1738  acct_guid = g_key_file_get_string (key_file, group_name,
1739  KEY_ACCOUNT_GUID, &error);
1740  if (string_to_guid (acct_guid, &guid)) //find account by guid
1741  {
1742  account = xaccAccountLookup (&guid, book);
1743  g_free (acct_guid);
1744  }
1745  if (account == NULL) //find account by full name
1746  {
1747  gchar* acct_name = g_key_file_get_string (key_file, group_name,
1748  KEY_ACCOUNT_NAME, &error);
1749  account = gnc_account_lookup_by_full_name (gnc_book_get_root_account (book),
1750  acct_name);
1751  g_free (acct_name);
1752  }
1753  if (account == NULL)
1754  {
1755  LEAVE ("Bad account name");
1756  g_free (reg_type);
1757  return NULL;
1758  }
1759  page = gnc_plugin_page_register_new (account, include_subs);
1760  }
1761  else if (g_ascii_strcasecmp (reg_type, LABEL_GL) == 0)
1762  {
1764  }
1765  else
1766  {
1767  LEAVE ("Bad ledger type");
1768  g_free (reg_type);
1769  return NULL;
1770  }
1771  g_free (reg_type);
1772 
1773  /* disable the refresh of the display ledger, this is for
1774  * sort/filter updates and double line/style changes */
1775  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1776  priv->enable_refresh = FALSE;
1777 
1778  /* Recreate page in given window */
1779  gnc_plugin_page_set_use_new_window (page, FALSE);
1780 
1781  /* Install it now so we can them manipulate the created widget */
1782  gnc_main_window_open_page (GNC_MAIN_WINDOW (window), page);
1783 
1784  /* Now update the page to the last state it was in */
1785  gnc_plugin_page_register_restore_edit_menu (page, key_file, group_name);
1786 
1787  /* enable the refresh */
1788  priv->enable_refresh = TRUE;
1789  LEAVE (" ");
1790  return page;
1791 }
1792 
1793 
1794 /*
1795  * Based on code from Epiphany (src/ephy-window.c)
1796  */
1797 static void
1798 gnc_plugin_page_register_update_edit_menu (GncPluginPage* page, gboolean hide)
1799 {
1801  GncPluginPageRegister* reg_page;
1802  GAction* action;
1803  gboolean can_copy = FALSE, can_cut = FALSE, can_paste = FALSE;
1804  gboolean has_selection;
1805  gboolean is_readwrite = !qof_book_is_readonly (gnc_get_current_book());
1806 
1807  reg_page = GNC_PLUGIN_PAGE_REGISTER (page);
1808  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (reg_page);
1809  has_selection = gnucash_register_has_selection (priv->gsr->reg);
1810 
1811  can_copy = has_selection;
1812  can_cut = is_readwrite && has_selection;
1813  can_paste = is_readwrite;
1814 
1815  action = gnc_plugin_page_get_action (page, "EditCopyAction");
1816  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), can_copy);
1817  action = gnc_plugin_page_get_action (page, "EditCutAction");
1818  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), can_cut);
1819  action = gnc_plugin_page_get_action (page, "EditPasteAction");
1820  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), can_paste);
1821 }
1822 
1823 static gboolean is_scrubbing = FALSE;
1824 static gboolean show_abort_verify = TRUE;
1825 
1826 static const char*
1827 check_repair_abort_YN = N_("'Check & Repair' is currently running, do you want to abort it?");
1828 
1829 static gboolean
1830 finish_scrub (GncPluginPage* page)
1831 {
1832  gboolean ret = FALSE;
1833 
1834  if (is_scrubbing)
1835  {
1836  ret = gnc_verify_dialog (GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page))),
1837  false, "%s", _(check_repair_abort_YN));
1838 
1839  show_abort_verify = FALSE;
1840 
1841  if (ret)
1842  gnc_set_abort_scrub (TRUE);
1843  }
1844  return ret;
1845 }
1846 
1847 static gboolean
1848 gnc_plugin_page_register_finish_pending (GncPluginPage* page)
1849 {
1851  GncPluginPageRegister* reg_page;
1852  SplitRegister* reg;
1853  GtkWidget* dialog, *window;
1854  gchar* name;
1855  gint response;
1856 
1857  if (is_scrubbing && show_abort_verify)
1858  {
1859  if (!finish_scrub (page))
1860  return FALSE;
1861  }
1862 
1863  reg_page = GNC_PLUGIN_PAGE_REGISTER (page);
1864  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (reg_page);
1865  reg = gnc_ledger_display_get_split_register (priv->ledger);
1866 
1867  if (!reg || !gnc_split_register_changed (reg))
1868  return TRUE;
1869 
1870  name = gnc_plugin_page_register_get_tab_name (page);
1871  window = gnc_plugin_page_get_window (page);
1872  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1873  GTK_DIALOG_DESTROY_WITH_PARENT,
1874  GTK_MESSAGE_WARNING,
1875  GTK_BUTTONS_NONE,
1876  /* Translators: %s is the name
1877  of the tab page */
1878  _ ("Save changes to %s?"), name);
1879  g_free (name);
1880  gtk_message_dialog_format_secondary_text
1881  (GTK_MESSAGE_DIALOG (dialog),
1882  "%s",
1883  _ ("This register has pending changes to a transaction. "
1884  "Would you like to save the changes to this transaction, "
1885  "discard the transaction, or cancel the operation?"));
1886  gnc_gtk_dialog_add_button (dialog, _ ("_Discard Transaction"),
1887  "edit-delete", GTK_RESPONSE_REJECT);
1888  gtk_dialog_add_button (GTK_DIALOG (dialog),
1889  _ ("_Cancel"), GTK_RESPONSE_CANCEL);
1890  gnc_gtk_dialog_add_button (dialog, _ ("_Save Transaction"),
1891  "document-save", GTK_RESPONSE_ACCEPT);
1892 
1893  response = gtk_dialog_run (GTK_DIALOG (dialog));
1894  gtk_widget_destroy (dialog);
1895 
1896  switch (response)
1897  {
1898  case GTK_RESPONSE_ACCEPT:
1899  gnc_split_register_save (reg, TRUE);
1900  return TRUE;
1901 
1902  case GTK_RESPONSE_REJECT:
1904  gnc_split_register_save (reg, TRUE);
1905  return TRUE;
1906 
1907  default:
1908  return FALSE;
1909  }
1910 }
1911 
1912 
1913 static gchar*
1914 gnc_plugin_page_register_get_tab_name (GncPluginPage* plugin_page)
1915 {
1917  GNCLedgerDisplayType ledger_type;
1918  GNCLedgerDisplay* ld;
1919  SplitRegister* reg;
1920  Account* leader;
1921 
1922  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
1923  g_strdup (_("unknown")));
1924 
1925  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
1926  ld = priv->ledger;
1928  ledger_type = gnc_ledger_display_type (ld);
1929  leader = gnc_ledger_display_leader (ld);
1930 
1931  switch (ledger_type)
1932  {
1933  case LD_SINGLE:
1934  return g_strdup (xaccAccountGetName (leader));
1935 
1936  case LD_SUBACCOUNT:
1937  return g_strdup_printf ("%s+", xaccAccountGetName (leader));
1938 
1939  case LD_GL:
1940  switch (reg->type)
1941  {
1942  case GENERAL_JOURNAL:
1943  case INCOME_LEDGER:
1944  return g_strdup (_ ("General Journal"));
1945  case PORTFOLIO_LEDGER:
1946  return g_strdup (_ ("Portfolio"));
1947  case SEARCH_LEDGER:
1948  return g_strdup (_ ("Search Results"));
1949  default:
1950  break;
1951  }
1952  break;
1953 
1954  default:
1955  break;
1956  }
1957 
1958  return g_strdup (_ ("unknown"));
1959 }
1960 
1961 static gchar*
1962 gnc_plugin_page_register_get_tab_color (GncPluginPage* plugin_page)
1963 {
1965  GNCLedgerDisplayType ledger_type;
1966  GNCLedgerDisplay* ld;
1967  Account* leader;
1968  const char* color;
1969 
1970  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
1971  g_strdup (_("unknown")));
1972 
1973  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
1974  ld = priv->ledger;
1975  ledger_type = gnc_ledger_display_type (ld);
1976  leader = gnc_ledger_display_leader (ld);
1977  color = NULL;
1978 
1979  if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
1980  color = xaccAccountGetColor (leader);
1981 
1982  return g_strdup (color ? color : "Not Set");
1983 }
1984 
1985 static void
1986 gnc_plugin_page_register_check_for_empty_group (GKeyFile *state_file,
1987  const gchar *state_section)
1988 {
1989  gsize num_keys;
1990  gchar **keys = g_key_file_get_keys (state_file, state_section, &num_keys, NULL);
1991 
1992  if (num_keys == 0)
1993  gnc_state_drop_sections_for (state_section);
1994 
1995  g_strfreev (keys);
1996 }
1997 
1998 static gchar*
1999 gnc_plugin_page_register_get_filter_gcm (GNCSplitReg *gsr)
2000 {
2001  GKeyFile* state_file = gnc_state_get_current();
2002  gchar* state_section;
2003  GError* error = NULL;
2004  char* filter = NULL;
2005 
2006  // get the filter from the .gcm file
2007  state_section = gsr_get_register_state_section (gsr);
2008  filter = g_key_file_get_string (state_file, state_section,
2009  KEY_PAGE_FILTER, &error);
2010 
2011  if (error)
2012  g_clear_error (&error);
2013  else
2014  g_strdelimit (filter, ";", ',');
2015 
2016  g_free (state_section);
2017  return filter;
2018 }
2019 
2020 static gchar*
2021 gnc_plugin_page_register_get_filter (GncPluginPage* plugin_page)
2022 {
2024  GNCLedgerDisplayType ledger_type;
2025  char* filter = NULL;
2026 
2027  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
2028  g_strdup (_("unknown")));
2029 
2030  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2031 
2032  ledger_type = gnc_ledger_display_type (priv->ledger);
2033 
2034  // load from gcm file
2035  filter = gnc_plugin_page_register_get_filter_gcm (priv->gsr);
2036 
2037  if (filter)
2038  return filter;
2039 
2040  return g_strdup_printf ("%s,%s,%s,%s", DEFAULT_FILTER,
2041  "0", "0", get_filter_default_num_of_days (ledger_type));
2042 }
2043 
2044 static void
2045 gnc_plugin_page_register_set_filter_gcm (GNCSplitReg *gsr, const gchar* filter,
2046  gchar* default_filter)
2047 {
2048  GKeyFile* state_file = gnc_state_get_current();
2049  gchar* state_section;
2050  gchar* filter_text;
2051 
2052  // save the filter to the .gcm file also
2053  state_section = gsr_get_register_state_section (gsr);
2054  if (!filter || (g_strcmp0 (filter, default_filter) == 0))
2055  {
2056  if (g_key_file_has_key (state_file, state_section, KEY_PAGE_FILTER, NULL))
2057  g_key_file_remove_key (state_file, state_section, KEY_PAGE_FILTER, NULL);
2058 
2059  gnc_plugin_page_register_check_for_empty_group (state_file, state_section);
2060  }
2061  else
2062  {
2063  filter_text = g_strdup (filter);
2064  g_strdelimit (filter_text, ",", ';'); // make it conform to .gcm file list
2065  g_key_file_set_string (state_file, state_section, KEY_PAGE_FILTER,
2066  filter_text);
2067  g_free (filter_text);
2068  }
2069  g_free (state_section);
2070 }
2071 
2072 void
2073 gnc_plugin_page_register_set_filter (GncPluginPage* plugin_page,
2074  const gchar* filter)
2075 {
2077  GNCLedgerDisplayType ledger_type;
2078  gchar* default_filter;
2079 
2080  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2081 
2082  ledger_type = gnc_ledger_display_type (priv->ledger);
2083 
2084  default_filter = g_strdup_printf ("%s,%s,%s,%s", DEFAULT_FILTER,
2085  "0", "0", get_filter_default_num_of_days (ledger_type));
2086 
2087  // save to gcm file
2088  gnc_plugin_page_register_set_filter_gcm (priv->gsr, filter, default_filter);
2089 
2090  g_free (default_filter);
2091  return;
2092 }
2093 
2094 static gchar*
2095 gnc_plugin_page_register_get_sort_order_gcm (GNCSplitReg *gsr)
2096 {
2097  GKeyFile* state_file = gnc_state_get_current();
2098  gchar* state_section;
2099  gchar* sort_text;
2100  GError* error = NULL;
2101  char* sort_order = NULL;
2102 
2103  // get the sort_order from the .gcm file
2104  state_section = gsr_get_register_state_section (gsr);
2105  sort_text = g_key_file_get_string (state_file, state_section, KEY_PAGE_SORT,
2106  &error);
2107 
2108  if (error)
2109  g_clear_error (&error);
2110  else
2111  {
2112  sort_order = g_strdup (sort_text);
2113  g_free (sort_text);
2114  }
2115  g_free (state_section);
2116  return sort_order;
2117 }
2118 
2119 static gchar*
2120 gnc_plugin_page_register_get_sort_order (GncPluginPage* plugin_page)
2121 {
2123  char* sort_order = NULL;
2124 
2125  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
2126  _ ("unknown"));
2127 
2128  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2129 
2130  // load from gcm file
2131  sort_order = gnc_plugin_page_register_get_sort_order_gcm (priv->gsr);
2132 
2133  return sort_order ? sort_order : g_strdup (DEFAULT_SORT_ORDER);
2134 }
2135 
2136 static void
2137 gnc_plugin_page_register_set_sort_order_gcm (GNCSplitReg *gsr,
2138  const gchar* sort_order)
2139 {
2140  GKeyFile* state_file = gnc_state_get_current();
2141  gchar* state_section;
2142 
2143  // save sort_order to the .gcm file also
2144  state_section = gsr_get_register_state_section (gsr);
2145  if (!sort_order || (g_strcmp0 (sort_order, DEFAULT_SORT_ORDER) == 0))
2146  {
2147  if (g_key_file_has_key (state_file, state_section, KEY_PAGE_SORT, NULL))
2148  g_key_file_remove_key (state_file, state_section, KEY_PAGE_SORT, NULL);
2149 
2150  gnc_plugin_page_register_check_for_empty_group (state_file, state_section);
2151  }
2152  else
2153  g_key_file_set_string (state_file, state_section, KEY_PAGE_SORT, sort_order);
2154 
2155  g_free (state_section);
2156 }
2157 void
2158 gnc_plugin_page_register_set_sort_order (GncPluginPage* plugin_page,
2159  const gchar* sort_order)
2160 {
2162 
2163  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2164 
2165  // save to gcm file
2166  gnc_plugin_page_register_set_sort_order_gcm (priv->gsr, sort_order);
2167 }
2168 
2169 static gboolean
2170 gnc_plugin_page_register_get_sort_reversed_gcm (GNCSplitReg *gsr)
2171 {
2172  GKeyFile* state_file = gnc_state_get_current();
2173  gchar* state_section;
2174  GError* error = NULL;
2175  gboolean sort_reversed = FALSE;
2176 
2177  // get the sort_reversed from the .gcm file
2178  state_section = gsr_get_register_state_section (gsr);
2179  sort_reversed = g_key_file_get_boolean (state_file, state_section,
2180  KEY_PAGE_SORT_REV, &error);
2181 
2182  if (error)
2183  g_clear_error (&error);
2184 
2185  g_free (state_section);
2186  return sort_reversed;
2187 }
2188 
2189 static gboolean
2190 gnc_plugin_page_register_get_sort_reversed (GncPluginPage* plugin_page)
2191 {
2193  gboolean sort_reversed = FALSE;
2194 
2195  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page), FALSE);
2196 
2197  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2198 
2199  // load from gcm file
2200  sort_reversed = gnc_plugin_page_register_get_sort_reversed_gcm (priv->gsr);
2201  return sort_reversed;
2202 }
2203 
2204 static void
2205 gnc_plugin_page_register_set_sort_reversed_gcm (GNCSplitReg *gsr,
2206  gboolean reverse_order)
2207 {
2208  GKeyFile* state_file = gnc_state_get_current();
2209  gchar* state_section;
2210 
2211  // save reverse_order to the .gcm file also
2212  state_section = gsr_get_register_state_section (gsr);
2213 
2214  if (!reverse_order)
2215  {
2216  if (g_key_file_has_key (state_file, state_section, KEY_PAGE_SORT_REV, NULL))
2217  g_key_file_remove_key (state_file, state_section, KEY_PAGE_SORT_REV, NULL);
2218 
2219  gnc_plugin_page_register_check_for_empty_group (state_file, state_section);
2220  }
2221  else
2222  g_key_file_set_boolean (state_file, state_section, KEY_PAGE_SORT_REV,
2223  reverse_order);
2224 
2225  g_free (state_section);
2226 }
2227 
2228 void
2229 gnc_plugin_page_register_set_sort_reversed (GncPluginPage* plugin_page,
2230  gboolean reverse_order)
2231 {
2233 
2234  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2235 
2236  // save to gcm file
2237  gnc_plugin_page_register_set_sort_reversed_gcm (priv->gsr, reverse_order);
2238 }
2239 
2240 static gchar*
2241 gnc_plugin_page_register_get_long_name (GncPluginPage* plugin_page)
2242 {
2244  GNCLedgerDisplayType ledger_type;
2245  GNCLedgerDisplay* ld;
2246  Account* leader;
2247 
2248  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
2249  _ ("unknown"));
2250 
2251  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2252  ld = priv->ledger;
2253  ledger_type = gnc_ledger_display_type (ld);
2254  leader = gnc_ledger_display_leader (ld);
2255 
2256  switch (ledger_type)
2257  {
2258  case LD_SINGLE:
2259  return gnc_account_get_full_name (leader);
2260 
2261  case LD_SUBACCOUNT:
2262  {
2263  gchar* account_full_name = gnc_account_get_full_name (leader);
2264  gchar* return_string = g_strdup_printf ("%s+", account_full_name);
2265  g_free ((gpointer*) account_full_name);
2266  return return_string;
2267  }
2268 
2269  default:
2270  break;
2271  }
2272 
2273  return NULL;
2274 }
2275 
2276 static void
2277 gnc_plugin_page_register_summarybar_position_changed (gpointer prefs,
2278  gchar* pref,
2279  gpointer user_data)
2280 {
2281  GncPluginPage* plugin_page;
2282  GncPluginPageRegister* page;
2284  GtkPositionType position = GTK_POS_BOTTOM;
2285 
2286  g_return_if_fail (user_data != NULL);
2287 
2288  if (!GNC_IS_PLUGIN_PAGE (user_data))
2289  return;
2290 
2291  plugin_page = GNC_PLUGIN_PAGE (user_data);
2292  page = GNC_PLUGIN_PAGE_REGISTER (user_data);
2293  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2294 
2295  if (priv == NULL)
2296  return;
2297 
2298  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL,
2299  GNC_PREF_SUMMARYBAR_POSITION_TOP))
2300  position = GTK_POS_TOP;
2301 
2302  gtk_box_reorder_child (GTK_BOX (priv->widget),
2303  plugin_page->summarybar,
2304  (position == GTK_POS_TOP ? 0 : -1));
2305 }
2306 
2312 Query*
2314 {
2315  GncPluginPageRegister* page;
2317 
2318  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page), NULL);
2319 
2320  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
2321  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2322  return gnc_ledger_display_get_query (priv->ledger);
2323 }
2324 
2325 /************************************************************/
2326 /* "Sort By" Dialog */
2327 /************************************************************/
2328 
2339 static void
2340 gnc_plugin_page_register_sort_book_option_changed (gpointer new_val,
2341  gpointer user_data)
2342 {
2344  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2345  gboolean* new_data = (gboolean*)new_val;
2346 
2347  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2348 
2349  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2350  if (*new_data)
2351  {
2352  gtk_button_set_label (GTK_BUTTON (priv->sd.num_radio),
2353  _ ("Transaction Number"));
2354  gtk_button_set_label (GTK_BUTTON (priv->sd.act_radio), _ ("Number/Action"));
2355  }
2356  else
2357  {
2358  gtk_button_set_label (GTK_BUTTON (priv->sd.num_radio), _ ("Number"));
2359  gtk_button_set_label (GTK_BUTTON (priv->sd.act_radio), _ ("Action"));
2360  }
2361  gnc_split_reg_set_sort_type_force (priv->gsr, (SortType)priv->gsr->sort_type, TRUE);
2362 }
2363 
2375 void
2377  gint response,
2378  GncPluginPageRegister* page)
2379 {
2381  GncPluginPage* plugin_page;
2382  SortType type;
2383  const gchar* order;
2384 
2385  g_return_if_fail (GTK_IS_DIALOG (dialog));
2386  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2387 
2388  ENTER (" ");
2389  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2390  plugin_page = GNC_PLUGIN_PAGE (page);
2391 
2392  if (response != GTK_RESPONSE_OK)
2393  {
2394  /* Restore the original sort order */
2395  gnc_split_reg_set_sort_reversed (priv->gsr, priv->sd.original_reverse_order,
2396  TRUE);
2397  priv->sd.reverse_order = priv->sd.original_reverse_order;
2398  gnc_split_reg_set_sort_type (priv->gsr, priv->sd.original_sort_type);
2399  priv->sd.save_order = priv->sd.original_save_order;
2400  }
2401  else
2402  {
2403  // clear the sort when unticking the save option
2404  if ((!priv->sd.save_order) && ((priv->sd.original_save_order) || (priv->sd.original_reverse_order)))
2405  {
2406  gnc_plugin_page_register_set_sort_order (plugin_page, DEFAULT_SORT_ORDER);
2407  gnc_plugin_page_register_set_sort_reversed (plugin_page, FALSE);
2408  }
2409  priv->sd.original_save_order = priv->sd.save_order;
2410 
2411  if (priv->sd.save_order)
2412  {
2413  type = gnc_split_reg_get_sort_type (priv->gsr);
2414  order = SortTypeasString (type);
2415  gnc_plugin_page_register_set_sort_order (plugin_page, order);
2416  gnc_plugin_page_register_set_sort_reversed (plugin_page,
2417  priv->sd.reverse_order);
2418  }
2419  }
2420  gnc_book_option_remove_cb (OPTION_NAME_NUM_FIELD_SOURCE,
2421  gnc_plugin_page_register_sort_book_option_changed,
2422  page);
2423  priv->sd.dialog = NULL;
2424  priv->sd.num_radio = NULL;
2425  priv->sd.act_radio = NULL;
2426  gtk_widget_destroy (GTK_WIDGET (dialog));
2427  LEAVE (" ");
2428 }
2429 
2430 
2439 void
2441  GncPluginPageRegister* page)
2442 {
2444  const gchar* name;
2445  SortType type;
2446 
2447  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
2448  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2449 
2450  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2451  name = gtk_buildable_get_name (GTK_BUILDABLE (button));
2452  ENTER ("button %s(%p), page %p", name, button, page);
2453  type = SortTypefromString (name);
2454  gnc_split_reg_set_sort_type (priv->gsr, type);
2455  LEAVE (" ");
2456 }
2457 
2458 
2467 void
2469  GncPluginPageRegister* page)
2470 {
2472 
2473  g_return_if_fail (GTK_IS_CHECK_BUTTON (button));
2474  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2475 
2476  ENTER ("Save toggle button (%p), plugin_page %p", button, page);
2477 
2478  /* Compute the new save sort order */
2479  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2480 
2481  if (gtk_toggle_button_get_active (button))
2482  priv->sd.save_order = TRUE;
2483  else
2484  priv->sd.save_order = FALSE;
2485  LEAVE (" ");
2486 }
2487 
2496 void
2498  GncPluginPageRegister* page)
2499 
2500 {
2502 
2503  g_return_if_fail (GTK_IS_CHECK_BUTTON (button));
2504  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2505 
2506  ENTER ("Reverse toggle button (%p), plugin_page %p", button, page);
2507 
2508  /* Compute the new save sort order */
2509  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2510 
2511  priv->sd.reverse_order = gtk_toggle_button_get_active (button);
2512  gnc_split_reg_set_sort_reversed (priv->gsr, priv->sd.reverse_order, TRUE);
2513  LEAVE (" ");
2514 }
2515 
2516 /************************************************************/
2517 /* "Filter By" Dialog */
2518 /************************************************************/
2519 
2520 static void
2521 gnc_ppr_update_for_search_query (GncPluginPageRegister* page)
2522 {
2524  SplitRegister* reg;
2525 
2526  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2527  reg = gnc_ledger_display_get_split_register (priv->ledger);
2528 
2529  if (reg->type == SEARCH_LEDGER)
2530  {
2531  Query* query_tmp = gnc_ledger_display_get_query (priv->ledger);
2532 
2533  // if filter_query is NULL, then the dialogue find has been run
2534  // before coming here. if query_tmp does not equal filter_query
2535  // then the dialogue find has been run again before coming here
2536  if ((priv->filter_query == NULL) ||
2537  (!qof_query_equal (query_tmp, priv->filter_query)))
2538  {
2539  qof_query_destroy (priv->search_query);
2540  priv->search_query = qof_query_copy (query_tmp);
2541  }
2542  gnc_ledger_display_set_query (priv->ledger, priv->search_query);
2543  }
2544 }
2545 
2546 
2559 static void
2560 gnc_ppr_update_status_query (GncPluginPageRegister* page)
2561 {
2563  Query* query;
2564  SplitRegister* reg;
2565 
2566  ENTER (" ");
2567  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2568  if (!priv->ledger)
2569  {
2570  LEAVE ("no ledger");
2571  return;
2572  }
2573  // check if this a search register and save query
2574  gnc_ppr_update_for_search_query (page);
2575 
2576  query = gnc_ledger_display_get_query (priv->ledger);
2577  if (!query)
2578  {
2579  LEAVE ("no query found");
2580  return;
2581  }
2582 
2583  reg = gnc_ledger_display_get_split_register (priv->ledger);
2584 
2585  /* Remove the old status match */
2586  if (reg->type != SEARCH_LEDGER)
2587  {
2588  GSList *param_list = qof_query_build_param_list (SPLIT_RECONCILE, NULL);
2589  qof_query_purge_terms (query, param_list);
2590  g_slist_free (param_list);
2591  }
2592 
2593  /* Install the new status match */
2594  if (priv->fd.cleared_match != CLEARED_ALL)
2595  xaccQueryAddClearedMatch (query, priv->fd.cleared_match, QOF_QUERY_AND);
2596 
2597  // Set filter tooltip for summary bar
2598  gnc_plugin_page_register_set_filter_tooltip (page);
2599 
2600  // clear previous filter query and save current
2601  qof_query_destroy (priv->filter_query);
2602  priv->filter_query = qof_query_copy (query);
2603 
2604  if (priv->enable_refresh)
2605  gnc_ledger_display_refresh (priv->ledger);
2606  LEAVE (" ");
2607 }
2608 
2609 
2622 static void
2623 gnc_ppr_update_date_query (GncPluginPageRegister* page)
2624 {
2626  Query* query;
2627  SplitRegister* reg;
2628 
2629  ENTER (" ");
2630  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2631  if (!priv->ledger)
2632  {
2633  LEAVE ("no ledger");
2634  return;
2635  }
2636  // check if this a search register and save query
2637  gnc_ppr_update_for_search_query (page);
2638 
2639  query = gnc_ledger_display_get_query (priv->ledger);
2640 
2641  if (!query)
2642  {
2643  LEAVE ("no query");
2644  return;
2645  }
2646 
2647  reg = gnc_ledger_display_get_split_register (priv->ledger);
2648 
2649  /* Delete any existing old date spec. */
2650  if (reg->type != SEARCH_LEDGER)
2651  {
2652  GSList *param_list = qof_query_build_param_list (SPLIT_TRANS,
2653  TRANS_DATE_POSTED, NULL);
2654  qof_query_purge_terms (query, param_list);
2655  g_slist_free (param_list);
2656  }
2657 
2658  if (priv->fd.start_time || priv->fd.end_time)
2659  {
2660  /* Build a new spec */
2661  xaccQueryAddDateMatchTT (query,
2662  priv->fd.start_time != 0, priv->fd.start_time,
2663  priv->fd.end_time != 0, priv->fd.end_time,
2664  QOF_QUERY_AND);
2665  }
2666 
2667  if (priv->fd.days > 0)
2668  {
2669  time64 start;
2670  struct tm tm;
2671 
2672  gnc_tm_get_today_start (&tm);
2673 
2674  tm.tm_mday = tm.tm_mday - priv->fd.days;
2675  start = gnc_mktime (&tm);
2676  xaccQueryAddDateMatchTT (query, TRUE, start, FALSE, 0, QOF_QUERY_AND);
2677  }
2678 
2679  // Set filter tooltip for summary bar
2680  gnc_plugin_page_register_set_filter_tooltip (page);
2681 
2682  // clear previous filter query and save current
2683  qof_query_destroy (priv->filter_query);
2684  priv->filter_query = qof_query_copy (query);
2685 
2686  if (priv->enable_refresh)
2687  gnc_ledger_display_refresh (priv->ledger);
2688  LEAVE (" ");
2689 }
2690 
2691 
2692 /* This function converts a time64 value date to a string */
2693 static gchar*
2694 gnc_plugin_page_register_filter_time2dmy (time64 raw_time)
2695 {
2696  struct tm* timeinfo;
2697  gchar date_string[11];
2698 
2699  timeinfo = gnc_localtime (&raw_time);
2700  strftime (date_string, 11, "%d-%m-%Y", timeinfo);
2701  PINFO ("Date string is %s", date_string);
2702  gnc_tm_free (timeinfo);
2703 
2704  return g_strdup (date_string);
2705 }
2706 
2707 
2708 /* This function converts a string date to a time64 value */
2709 static time64
2710 gnc_plugin_page_register_filter_dmy2time (char* date_string)
2711 {
2712  struct tm when;
2713 
2714  PINFO ("Date string is %s", date_string);
2715  memset (&when, 0, sizeof (when));
2716 
2717  sscanf (date_string, "%d-%d-%d", &when.tm_mday,
2718  &when.tm_mon, &when.tm_year);
2719 
2720  when.tm_mon -= 1;
2721  when.tm_year -= 1900;
2722 
2723  return gnc_mktime (&when);
2724 }
2725 
2726 
2737 void
2739  GncPluginPageRegister* page)
2740 {
2742  const gchar* name;
2743  gint i, value;
2744 
2745  g_return_if_fail (GTK_IS_CHECK_BUTTON (button));
2746  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2747 
2748  name = gtk_buildable_get_name (GTK_BUILDABLE (button));
2749  ENTER ("toggle button %s (%p), plugin_page %p", name, button, page);
2750 
2751  /* Determine what status bit to change */
2752  value = CLEARED_NONE;
2753  for (i = 0; status_actions[i].action_name; i++)
2754  {
2755  if (g_strcmp0 (name, status_actions[i].action_name) == 0)
2756  {
2757  value = status_actions[i].value;
2758  break;
2759  }
2760  }
2761 
2762  /* Compute the new match status */
2763  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2764  if (gtk_toggle_button_get_active (button))
2765  priv->fd.cleared_match = (cleared_match_t)(priv->fd.cleared_match | value);
2766  else
2767  priv->fd.cleared_match = (cleared_match_t)(priv->fd.cleared_match & ~value);
2768  gnc_ppr_update_status_query (page);
2769  LEAVE (" ");
2770 }
2771 
2772 
2782 void
2784  GncPluginPageRegister* page)
2785 {
2787  GtkWidget* widget;
2788  gint i;
2789 
2790  g_return_if_fail (GTK_IS_BUTTON (button));
2791  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2792 
2793  ENTER ("(button %p, page %p)", button, page);
2794 
2795  /* Turn on all the check menu items */
2796  for (i = 0; status_actions[i].action_name; i++)
2797  {
2798  widget = status_actions[i].widget;
2799  g_signal_handlers_block_by_func (widget,
2801  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
2802  g_signal_handlers_unblock_by_func (widget,
2804  }
2805 
2806  /* Set the requested status */
2807  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2808  priv->fd.cleared_match = CLEARED_ALL;
2809  gnc_ppr_update_status_query (page);
2810  LEAVE (" ");
2811 }
2812 
2813 
2814 
2824 void
2826  GncPluginPageRegister* page)
2827 {
2829  GtkWidget* widget;
2830  gint i;
2831 
2832  g_return_if_fail (GTK_IS_BUTTON (button));
2833  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2834 
2835  ENTER ("(button %p, page %p)", button, page);
2836 
2837  /* Turn off all the check menu items */
2838  for (i = 0; status_actions[i].action_name; i++)
2839  {
2840  widget = status_actions[i].widget;
2841  g_signal_handlers_block_by_func (widget,
2843  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
2844  g_signal_handlers_unblock_by_func (widget,
2846  }
2847 
2848  /* Set the requested status */
2849  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2850  priv->fd.cleared_match = CLEARED_NONE;
2851  gnc_ppr_update_status_query (page);
2852  LEAVE (" ");
2853 }
2854 
2855 
2867 static void
2868 get_filter_times (GncPluginPageRegister* page)
2869 {
2871  time64 time_val;
2872 
2873  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2874  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
2875  priv->fd.start_date_choose)))
2876  {
2877  time_val = gnc_date_edit_get_date (GNC_DATE_EDIT (priv->fd.start_date));
2878  time_val = gnc_time64_get_day_start (time_val);
2879  priv->fd.start_time = time_val;
2880  }
2881  else
2882  {
2883  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
2884  priv->fd.start_date_today)))
2885  {
2886  priv->fd.start_time = gnc_time64_get_today_start();
2887  }
2888  else
2889  {
2890  priv->fd.start_time = 0;
2891  }
2892  }
2893 
2894  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
2895  priv->fd.end_date_choose)))
2896  {
2897  time_val = gnc_date_edit_get_date (GNC_DATE_EDIT (priv->fd.end_date));
2898  time_val = gnc_time64_get_day_end (time_val);
2899  priv->fd.end_time = time_val;
2900  }
2901  else
2902  {
2903  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
2904  priv->fd.end_date_today)))
2905  {
2906  priv->fd.end_time = gnc_time64_get_today_end();
2907  }
2908  else
2909  {
2910  priv->fd.end_time = 0;
2911  }
2912  }
2913 }
2914 
2915 
2927 void
2929  GncPluginPageRegister* page)
2930 {
2932  gboolean active;
2933  const gchar* name;
2934 
2935  g_return_if_fail (GTK_IS_RADIO_BUTTON (button));
2936  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2937 
2938  ENTER ("(button %p, page %p)", button, page);
2939  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2940  name = gtk_buildable_get_name (GTK_BUILDABLE (button));
2941  active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
2942 
2943  if (active && g_strcmp0 (name, "filter_show_range") == 0)
2944  {
2945  gtk_widget_set_sensitive (priv->fd.table, active);
2946  gtk_widget_set_sensitive (priv->fd.num_days, !active);
2947  get_filter_times (page);
2948  }
2949  else if (active && g_strcmp0 (name, "filter_show_days") == 0)
2950  {
2951  gtk_widget_set_sensitive (priv->fd.table, !active);
2952  gtk_widget_set_sensitive (priv->fd.num_days, active);
2953  gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->fd.num_days), priv->fd.days);
2954  }
2955  else
2956  {
2957  gtk_widget_set_sensitive (priv->fd.table, FALSE);
2958  gtk_widget_set_sensitive (priv->fd.num_days, FALSE);
2959  priv->fd.days = 0;
2960  priv->fd.start_time = 0;
2961  priv->fd.end_time = 0;
2962  }
2963  gnc_ppr_update_date_query (page);
2964  LEAVE (" ");
2965 }
2966 
2967 void
2969 {
2971 
2972  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
2973 
2974  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
2975 
2976  priv->fd.days = 0;
2977  priv->fd.start_time = 0;
2978  priv->fd.end_time = 0;
2979  priv->fd.cleared_match = (cleared_match_t)g_ascii_strtoll (DEFAULT_FILTER, NULL, 16);
2980 
2981  gnc_ppr_update_date_query (GNC_PLUGIN_PAGE_REGISTER(plugin_page));
2982 }
2983 
2994 void
2996  GncPluginPageRegister* page)
2997 {
2999 
3000  g_return_if_fail (GTK_IS_SPIN_BUTTON (button));
3001  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3002 
3003  ENTER ("(button %p, page %p)", button, page);
3004  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3005 
3006  priv->fd.days = gtk_spin_button_get_value (GTK_SPIN_BUTTON (button));
3007  gnc_ppr_update_date_query (page);
3008  LEAVE (" ");
3009 }
3010 
3011 
3022 static void
3023 gnc_plugin_page_register_filter_gde_changed_cb (GtkWidget* unused,
3024  GncPluginPageRegister* page)
3025 {
3026  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3027 
3028  ENTER ("(widget %s(%p), page %p)",
3029  gtk_buildable_get_name (GTK_BUILDABLE (unused)), unused, page);
3030  get_filter_times (page);
3031  gnc_ppr_update_date_query (page);
3032  LEAVE (" ");
3033 }
3034 
3035 
3055 void
3057  GncPluginPageRegister* page)
3058 {
3060  const gchar* name;
3061  gboolean active;
3062 
3063  g_return_if_fail (GTK_IS_RADIO_BUTTON (radio));
3064  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3065 
3066  ENTER ("(radio %s(%p), page %p)",
3067  gtk_buildable_get_name (GTK_BUILDABLE (radio)), radio, page);
3068  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3069  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio)))
3070  {
3071  LEAVE ("1st callback of pair. Defer to 2nd callback.");
3072  return;
3073  }
3074 
3075  name = gtk_buildable_get_name (GTK_BUILDABLE (radio));
3076  active = !g_strcmp0 (name, "start_date_choose");
3077  gtk_widget_set_sensitive (priv->fd.start_date, active);
3078  get_filter_times (page);
3079  gnc_ppr_update_date_query (page);
3080  LEAVE (" ");
3081 }
3082 
3083 
3103 void
3105  GncPluginPageRegister* page)
3106 {
3108  const gchar* name;
3109  gboolean active;
3110 
3111  g_return_if_fail (GTK_IS_RADIO_BUTTON (radio));
3112  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3113 
3114  ENTER ("(radio %s(%p), page %p)",
3115  gtk_buildable_get_name (GTK_BUILDABLE (radio)), radio, page);
3116  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3117  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio)))
3118  {
3119  LEAVE ("1st callback of pair. Defer to 2nd callback.");
3120  return;
3121  }
3122 
3123  name = gtk_buildable_get_name (GTK_BUILDABLE (radio));
3124  active = !g_strcmp0 (name, "end_date_choose");
3125  gtk_widget_set_sensitive (priv->fd.end_date, active);
3126  get_filter_times (page);
3127  gnc_ppr_update_date_query (page);
3128  LEAVE (" ");
3129 }
3130 
3131 
3140 void
3142  GncPluginPageRegister* page)
3143 {
3145 
3146  g_return_if_fail (GTK_IS_CHECK_BUTTON (button));
3147  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3148 
3149  ENTER ("Save toggle button (%p), plugin_page %p", button, page);
3150 
3151  /* Compute the new save filter status */
3152  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3153  if (gtk_toggle_button_get_active (button))
3154  priv->fd.save_filter = TRUE;
3155  else
3156  priv->fd.save_filter = FALSE;
3157  LEAVE (" ");
3158 }
3159 
3160 
3172 void
3174  gint response,
3175  GncPluginPageRegister* page)
3176 {
3178  GncPluginPage* plugin_page;
3179 
3180  g_return_if_fail (GTK_IS_DIALOG (dialog));
3181  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3182 
3183  ENTER (" ");
3184  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3185  plugin_page = GNC_PLUGIN_PAGE (page);
3186 
3187  if (response != GTK_RESPONSE_OK)
3188  {
3189  /* Remove the old status match */
3190  priv->fd.cleared_match = priv->fd.original_cleared_match;
3191  priv->enable_refresh = FALSE;
3192  gnc_ppr_update_status_query (page);
3193  priv->enable_refresh = TRUE;
3194  priv->fd.start_time = priv->fd.original_start_time;
3195  priv->fd.end_time = priv->fd.original_end_time;
3196  priv->fd.days = priv->fd.original_days;
3197  priv->fd.save_filter = priv->fd.original_save_filter;
3198  gnc_ppr_update_date_query (page);
3199  }
3200  else
3201  {
3202  // clear the filter when unticking the save option
3203  if ((priv->fd.save_filter == FALSE) && (priv->fd.original_save_filter == TRUE))
3204  gnc_plugin_page_register_set_filter (plugin_page, NULL);
3205 
3206  priv->fd.original_save_filter = priv->fd.save_filter;
3207 
3208  if (priv->fd.save_filter)
3209  {
3210  gchar *filter;
3211  GList *flist = NULL;
3212 
3213  // cleared match
3214  flist = g_list_prepend
3215  (flist, g_strdup_printf ("0x%04x", priv->fd.cleared_match));
3216 
3217  // start time
3218  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->fd.start_date_choose)) && priv->fd.start_time != 0)
3219  flist = g_list_prepend (flist, gnc_plugin_page_register_filter_time2dmy (priv->fd.start_time));
3220  else
3221  flist = g_list_prepend (flist, g_strdup ("0"));
3222 
3223  // end time
3224  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->fd.end_date_choose))
3225  && priv->fd.end_time != 0)
3226  flist = g_list_prepend (flist, gnc_plugin_page_register_filter_time2dmy (priv->fd.end_time));
3227  else
3228  flist = g_list_prepend (flist, g_strdup ("0"));
3229 
3230  // number of days
3231  if (priv->fd.days > 0)
3232  flist = g_list_prepend (flist, g_strdup_printf ("%d", priv->fd.days));
3233  else
3234  flist = g_list_prepend (flist, g_strdup ("0"));
3235 
3236  flist = g_list_reverse (flist);
3237  filter = gnc_g_list_stringjoin (flist, ",");
3238  PINFO ("The filter to save is %s", filter);
3239  gnc_plugin_page_register_set_filter (plugin_page, filter);
3240  g_free (filter);
3241  g_list_free_full (flist, g_free);
3242  }
3243  }
3244  priv->fd.dialog = NULL;
3245  gtk_widget_destroy (GTK_WIDGET (dialog));
3246  LEAVE (" ");
3247 }
3248 
3249 static void
3250 gpp_update_match_filter_text (cleared_match_t match, const guint mask,
3251  const gchar* filter_name, GList **show, GList **hide)
3252 {
3253  if ((match & mask) == mask)
3254  *show = g_list_prepend (*show, g_strdup (filter_name));
3255  else
3256  *hide = g_list_prepend (*hide, g_strdup (filter_name));
3257 }
3258 
3259 static void
3260 gnc_plugin_page_register_set_filter_tooltip (GncPluginPageRegister* page)
3261 {
3263  GList *t_list = NULL;
3264 
3265  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3266 
3267  ENTER (" ");
3268  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3269 
3270  // filtered start time
3271  if (priv->fd.start_time != 0)
3272  {
3273  gchar* sdate = qof_print_date (priv->fd.start_time);
3274  t_list = g_list_prepend
3275  (t_list, g_strdup_printf ("%s %s", _("Start Date:"), sdate));
3276  g_free (sdate);
3277  }
3278 
3279  // filtered number of days
3280  if (priv->fd.days > 0)
3281  t_list = g_list_prepend
3282  (t_list, g_strdup_printf ("%s %d", _("Show previous number of days:"),
3283  priv->fd.days));
3284 
3285  // filtered end time
3286  if (priv->fd.end_time != 0)
3287  {
3288  gchar* edate = qof_print_date (priv->fd.end_time);
3289  t_list = g_list_prepend
3290  (t_list, g_strdup_printf ("%s %s", _("End Date:"), edate));
3291  g_free (edate);
3292  }
3293 
3294  // filtered match items
3295  if (priv->fd.cleared_match != CLEARED_ALL)
3296  {
3297  GList *show = NULL;
3298  GList *hide = NULL;
3299 
3300  gpp_update_match_filter_text (priv->fd.cleared_match, 0x01, _ ("Unreconciled"),
3301  &show, &hide);
3302  gpp_update_match_filter_text (priv->fd.cleared_match, 0x02, _ ("Cleared"),
3303  &show, &hide);
3304  gpp_update_match_filter_text (priv->fd.cleared_match, 0x04, _ ("Reconciled"),
3305  &show, &hide);
3306  gpp_update_match_filter_text (priv->fd.cleared_match, 0x08, _ ("Frozen"),
3307  &show, &hide);
3308  gpp_update_match_filter_text (priv->fd.cleared_match, 0x10, _ ("Voided"),
3309  &show, &hide);
3310 
3311  show = g_list_reverse (show);
3312  hide = g_list_reverse (hide);
3313 
3314  if (show)
3315  {
3316  char *str = gnc_list_formatter (show);
3317  t_list = g_list_prepend
3318  (t_list, g_strdup_printf ("%s %s", _("Show:"), str));
3319  g_free (str);
3320  }
3321 
3322  if (hide)
3323  {
3324  char *str = gnc_list_formatter (hide);
3325  t_list = g_list_prepend
3326  (t_list, g_strdup_printf ("%s %s", _("Hide:"), str));
3327  g_free (str);
3328  }
3329 
3330  g_list_free_full (show, g_free);
3331  g_list_free_full (hide, g_free);
3332  }
3333 
3334  t_list = g_list_reverse (t_list);
3335 
3336  if (t_list)
3337  t_list = g_list_prepend (t_list, g_strdup (_("Filter By:")));
3338 
3339  // free the existing text if present
3340  if (priv->gsr->filter_text != NULL)
3341  g_free (priv->gsr->filter_text);
3342 
3343  // set the tooltip text variable in the gsr
3344  priv->gsr->filter_text = gnc_g_list_stringjoin (t_list, "\n");
3345 
3346  g_list_free_full (t_list, g_free);
3347 
3348  LEAVE (" ");
3349 }
3350 
3351 
3352 static void
3353 gnc_plugin_page_register_update_page_icon (GncPluginPage* plugin_page)
3354 {
3356  gboolean read_only;
3357 
3358  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
3359 
3360  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
3361 
3362  if (qof_book_is_readonly (gnc_get_current_book()) ||
3363  gnc_split_reg_get_read_only (priv->gsr))
3364  read_only = TRUE;
3365  else
3366  read_only = FALSE;
3367 
3368  main_window_update_page_set_read_only_icon (GNC_PLUGIN_PAGE(plugin_page),
3369  read_only);
3370 }
3371 
3372 /************************************************************/
3373 /* Report Helper Functions */
3374 /************************************************************/
3375 
3376 static char*
3377 gnc_reg_get_name (GNCLedgerDisplay* ledger, gboolean for_window)
3378 {
3379  Account* leader;
3380  SplitRegister* reg;
3381  gchar* account_name;
3382  gchar* reg_name;
3383  gchar* name;
3384  GNCLedgerDisplayType ledger_type;
3385 
3386  if (ledger == NULL)
3387  return NULL;
3388 
3390  ledger_type = gnc_ledger_display_type (ledger);
3391 
3392  switch (reg->type)
3393  {
3394  case GENERAL_JOURNAL:
3395  case INCOME_LEDGER:
3396  if (for_window)
3397  reg_name = _ ("General Journal");
3398  else
3399  reg_name = _ ("Transaction Report");
3400  break;
3401  case PORTFOLIO_LEDGER:
3402  if (for_window)
3403  reg_name = _ ("Portfolio");
3404  else
3405  reg_name = _ ("Portfolio Report");
3406  break;
3407  case SEARCH_LEDGER:
3408  if (for_window)
3409  reg_name = _ ("Search Results");
3410  else
3411  reg_name = _ ("Search Results Report");
3412  break;
3413  default:
3414  if (for_window)
3415  reg_name = _ ("Register");
3416  else
3417  reg_name = _ ("Transaction Report");
3418  break;
3419  }
3420 
3421  leader = gnc_ledger_display_leader (ledger);
3422 
3423  if ((leader != NULL) && (ledger_type != LD_GL))
3424  {
3425  account_name = gnc_account_get_full_name (leader);
3426 
3427  if (ledger_type == LD_SINGLE)
3428  {
3429  name = g_strconcat (account_name, " - ", reg_name, NULL);
3430  }
3431  else
3432  {
3433  name = g_strconcat (account_name, " ", _ ("and subaccounts"), " - ", reg_name,
3434  NULL);
3435  }
3436  g_free (account_name);
3437  }
3438  else
3439  name = g_strdup (reg_name);
3440 
3441  return name;
3442 }
3443 
3444 static int
3445 report_helper (GNCLedgerDisplay* ledger, Split* split, Query* query)
3446 {
3447  SplitRegister* reg = gnc_ledger_display_get_split_register (ledger);
3448  Account* account;
3449  char* str;
3450  const char* tmp;
3451  swig_type_info* qtype;
3452  SCM args;
3453  SCM func;
3454  SCM arg;
3455 
3456  args = SCM_EOL;
3457 
3458  func = scm_c_eval_string ("gnc:register-report-create");
3459  g_return_val_if_fail (scm_is_procedure (func), -1);
3460 
3462  arg = scm_from_utf8_string (tmp ? tmp : _ ("Credit"));
3463  args = scm_cons (arg, args);
3464 
3466  arg = scm_from_utf8_string (tmp ? tmp : _ ("Debit"));
3467  args = scm_cons (arg, args);
3468 
3469  str = gnc_reg_get_name (ledger, FALSE);
3470  arg = scm_from_utf8_string (str ? str : "");
3471  args = scm_cons (arg, args);
3472  g_free (str);
3473 
3474  arg = SCM_BOOL (reg->use_double_line);
3475  args = scm_cons (arg, args);
3476 
3477  arg = SCM_BOOL (reg->type == GENERAL_JOURNAL || reg->type == INCOME_LEDGER
3478  || reg->type == SEARCH_LEDGER);
3479  args = scm_cons (arg, args);
3480 
3481  arg = SCM_BOOL (reg->style == REG_STYLE_JOURNAL);
3482  args = scm_cons (arg, args);
3483 
3484  if (!query)
3485  {
3486  query = gnc_ledger_display_get_query (ledger);
3487  g_return_val_if_fail (query != NULL, -1);
3488  }
3489 
3490  qtype = SWIG_TypeQuery ("_p__QofQuery");
3491  g_return_val_if_fail (qtype, -1);
3492 
3493  arg = SWIG_NewPointerObj (query, qtype, 0);
3494  args = scm_cons (arg, args);
3495  g_return_val_if_fail (arg != SCM_UNDEFINED, -1);
3496 
3497 
3498  if (split)
3499  {
3500  qtype = SWIG_TypeQuery ("_p_Split");
3501  g_return_val_if_fail (qtype, -1);
3502  arg = SWIG_NewPointerObj (split, qtype, 0);
3503  }
3504  else
3505  {
3506  arg = SCM_BOOL_F;
3507  }
3508  args = scm_cons (arg, args);
3509  g_return_val_if_fail (arg != SCM_UNDEFINED, -1);
3510 
3511 
3512  qtype = SWIG_TypeQuery ("_p_Account");
3513  g_return_val_if_fail (qtype, -1);
3514 
3515  account = gnc_ledger_display_leader (ledger);
3516  arg = SWIG_NewPointerObj (account, qtype, 0);
3517  args = scm_cons (arg, args);
3518  g_return_val_if_fail (arg != SCM_UNDEFINED, -1);
3519 
3520 
3521  /* Apply the function to the args */
3522  arg = scm_apply (func, args, SCM_EOL);
3523  g_return_val_if_fail (scm_is_exact (arg), -1);
3524 
3525  return scm_to_int (arg);
3526 }
3527 
3528 /************************************************************/
3529 /* Command callbacks */
3530 /************************************************************/
3531 
3532 static void
3533 gnc_plugin_page_register_cmd_print_check (GSimpleAction *simple,
3534  GVariant *paramter,
3535  gpointer user_data)
3536 {
3537  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3539  SplitRegister* reg;
3540  Split* split;
3541  Transaction* trans;
3542  GList* splits = NULL, *item;
3543  GNCLedgerDisplayType ledger_type;
3544  Account* account, *subaccount = NULL;
3545  GtkWidget* window;
3546 
3547  ENTER ("(action %p, page %p)", simple, page);
3548 
3549  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3550 
3551  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3552  reg = gnc_ledger_display_get_split_register (priv->ledger);
3553  ledger_type = gnc_ledger_display_type (priv->ledger);
3554  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
3555  if (ledger_type == LD_SINGLE || ledger_type == LD_SUBACCOUNT)
3556  {
3557  account = gnc_plugin_page_register_get_account (page);
3559  trans = xaccSplitGetParent (split);
3560  if (ledger_type == LD_SUBACCOUNT)
3561  {
3562  /* Set up subaccount printing, where the check amount matches the
3563  * value displayed in the register. */
3564  subaccount = account;
3565  }
3566 
3567  if (split && trans)
3568  {
3569  if (xaccSplitGetAccount (split) == account)
3570  {
3571  splits = g_list_prepend (splits, split);
3572  gnc_ui_print_check_dialog_create (window, splits, subaccount);
3573  g_list_free (splits);
3574  }
3575  else
3576  {
3577  /* This split is not for the account shown in this register. Get the
3578  split that anchors the transaction to the registor */
3579  split = gnc_split_register_get_current_trans_split (reg, NULL);
3580  if (split)
3581  {
3582  splits = g_list_prepend (splits, split);
3583  gnc_ui_print_check_dialog_create (window, splits, subaccount);
3584  g_list_free (splits);
3585  }
3586  }
3587  }
3588  }
3589  else if (ledger_type == LD_GL && reg->type == SEARCH_LEDGER)
3590  {
3591  Account* common_acct = NULL;
3592 
3593  /* the following GList* splits must not be freed */
3594  splits = qof_query_run (gnc_ledger_display_get_query (priv->ledger));
3595 
3596  /* Make sure each split is from the same account */
3597  for (item = splits; item; item = g_list_next (item))
3598  {
3599  split = (Split*) item->data;
3600  if (common_acct == NULL)
3601  {
3602  common_acct = xaccSplitGetAccount (split);
3603  }
3604  else
3605  {
3606  if (xaccSplitGetAccount (split) != common_acct)
3607  {
3608  GtkWidget* dialog;
3609  gint response;
3610  const gchar* title = _ ("Print checks from multiple accounts?");
3611  const gchar* message =
3612  _ ("This search result contains splits from more than one account. "
3613  "Do you want to print the checks even though they are not all "
3614  "from the same account?");
3615  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
3616  GTK_DIALOG_DESTROY_WITH_PARENT,
3617  GTK_MESSAGE_WARNING,
3618  GTK_BUTTONS_CANCEL,
3619  "%s", title);
3620  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
3621  "%s", message);
3622  gtk_dialog_add_button (GTK_DIALOG (dialog), _ ("_Print checks"),
3623  GTK_RESPONSE_YES);
3624  response = gnc_dialog_run (GTK_DIALOG (dialog),
3625  GNC_PREF_WARN_CHECKPRINTING_MULTI_ACCT);
3626  gtk_widget_destroy (dialog);
3627  if (response != GTK_RESPONSE_YES)
3628  {
3629  LEAVE ("Multiple accounts");
3630  return;
3631  }
3632  break;
3633  }
3634  }
3635  }
3636  gnc_ui_print_check_dialog_create (window, splits, NULL);
3637  }
3638  else
3639  {
3640  gnc_error_dialog (GTK_WINDOW (window), "%s",
3641  _ ("You can only print checks from a bank account register or search results."));
3642  LEAVE ("Unsupported ledger type");
3643  return;
3644  }
3645  LEAVE (" ");
3646 }
3647 
3648 
3649 static void
3650 gnc_plugin_page_register_cmd_cut (GSimpleAction *simple,
3651  GVariant *paramter,
3652  gpointer user_data)
3653 {
3654  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3656 
3657  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3658 
3659  ENTER ("(action %p, page %p)", simple, page);
3660  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3661 
3662  GtkWidget *widget = gtk_window_get_focus(GTK_WINDOW (priv->gsr->window));
3663  const char *name = gtk_widget_get_name(widget);
3664  if (strcmp(name, "GnucashSheet") != 0)
3665  {
3666  gtk_editable_cut_clipboard( GTK_EDITABLE(widget));
3667  LEAVE("Not cut from GnucashSheet");
3668 
3669  return;
3670  }
3671 
3672  gnucash_register_cut_clipboard (priv->gsr->reg);
3673  LEAVE ("");
3674 }
3675 
3676 
3677 static void
3678 gnc_plugin_page_register_cmd_copy (GSimpleAction *simple,
3679  GVariant *paramter,
3680  gpointer user_data)
3681 {
3682  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3684 
3685  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3686 
3687  ENTER ("(action %p, page %p)", simple, page);
3688  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3689 
3690  GtkWidget *widget = gtk_window_get_focus(GTK_WINDOW (priv->gsr->window));
3691  const char *name = gtk_widget_get_name(widget);
3692  if (strcmp(name, "GnucashSheet") != 0)
3693  {
3694  gtk_editable_copy_clipboard( GTK_EDITABLE(widget));
3695  LEAVE("Not copied from GnucashSheet");
3696 
3697  return;
3698  }
3699 
3700  gnucash_register_copy_clipboard (priv->gsr->reg);
3701  LEAVE ("");
3702 }
3703 
3704 
3705 static void
3706 gnc_plugin_page_register_cmd_paste (GSimpleAction *simple,
3707  GVariant *paramter,
3708  gpointer user_data)
3709 {
3710  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3712 
3713  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3714 
3715  ENTER ("(action %p, page %p)", simple, page);
3716  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3717 
3718  GtkWidget *widget = gtk_window_get_focus(GTK_WINDOW (priv->gsr->window));
3719  const char *name = gtk_widget_get_name(widget);
3720  if (strcmp(name, "GnucashSheet") != 0)
3721  {
3722  gtk_editable_paste_clipboard( GTK_EDITABLE(widget));
3723  LEAVE("Not pasted to GnucashSheet");
3724 
3725  return;
3726  }
3727 
3728  gnucash_register_paste_clipboard (priv->gsr->reg);
3729  LEAVE ("");
3730 }
3731 
3732 
3733 static void
3734 gnc_plugin_page_register_cmd_edit_account (GSimpleAction *simple,
3735  GVariant *paramter,
3736  gpointer user_data)
3737 {
3738  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3739  Account* account;
3740  GtkWindow* parent = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page)));
3741  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3742 
3743  ENTER ("(action %p, page %p)", simple, page);
3744  account = gnc_plugin_page_register_get_account (page);
3745  if (account)
3746  gnc_ui_edit_account_window (parent, account);
3747  LEAVE (" ");
3748 }
3749 
3750 
3751 static void
3752 gnc_plugin_page_register_cmd_find_account (GSimpleAction *simple,
3753  GVariant *paramter,
3754  gpointer user_data)
3755 {
3756  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3757  GtkWidget* window;
3758 
3759  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3760 
3761  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
3762  gnc_find_account_dialog (window, NULL);
3763 }
3764 
3765 
3766 static void
3767 gnc_plugin_page_register_cmd_find_transactions (GSimpleAction *simple,
3768  GVariant *paramter,
3769  gpointer user_data)
3770 {
3771  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3773  GtkWindow* window;
3774 
3775  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3776 
3777  ENTER ("(action %p, page %p)", simple, page);
3778  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3779  window = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
3780  gnc_ui_find_transactions_dialog_create (window, priv->ledger);
3781  LEAVE (" ");
3782 }
3783 
3784 
3785 static void
3786 gnc_plugin_page_register_cmd_edit_tax_options (GSimpleAction *simple,
3787  GVariant *paramter,
3788  gpointer user_data)
3789 {
3790  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3791  GtkWidget *window;
3792  Account* account;
3793 
3794  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3795 
3796  ENTER ("(action %p, page %p)", simple, page);
3797  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
3798  account = gnc_plugin_page_register_get_account (page);
3799  gnc_tax_info_dialog (window, account);
3800  LEAVE (" ");
3801 }
3802 
3803 static void
3804 gnc_plugin_page_register_cmd_cut_transaction (GSimpleAction *simple,
3805  GVariant *paramter,
3806  gpointer user_data)
3807 {
3808  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3810 
3811  ENTER ("(action %p, page %p)", simple, page);
3812 
3813  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3814 
3815  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3816  gsr_default_cut_txn_handler (priv->gsr, NULL);
3817  LEAVE (" ");
3818 }
3819 
3820 
3821 static void
3822 gnc_plugin_page_register_cmd_copy_transaction (GSimpleAction *simple,
3823  GVariant *paramter,
3824  gpointer user_data)
3825 {
3826  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3828  SplitRegister* reg;
3829 
3830  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3831 
3832  ENTER ("(action %p, page %p)", simple, page);
3833  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3834  reg = gnc_ledger_display_get_split_register (priv->ledger);
3836  LEAVE (" ");
3837 }
3838 
3839 
3840 static void
3841 gnc_plugin_page_register_cmd_paste_transaction (GSimpleAction *simple,
3842  GVariant *paramter,
3843  gpointer user_data)
3844 {
3845  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3847  SplitRegister* reg;
3848 
3849  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3850 
3851  ENTER ("(action %p, page %p)", simple, page);
3852  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3853  reg = gnc_ledger_display_get_split_register (priv->ledger);
3855  LEAVE (" ");
3856 }
3857 
3858 
3859 static void
3860 gnc_plugin_page_register_cmd_void_transaction (GSimpleAction *simple,
3861  GVariant *paramter,
3862  gpointer user_data)
3863 {
3864  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3866  GtkWidget* dialog, *entry;
3867  SplitRegister* reg;
3868  Transaction* trans;
3869  GtkBuilder* builder;
3870  const char* reason;
3871  gint result;
3872  GtkWindow* window;
3873 
3874  ENTER ("(action %p, page %p)", simple, page);
3875 
3876  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3877 
3878  window = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
3879  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3880  reg = gnc_ledger_display_get_split_register (priv->ledger);
3882  if (trans == NULL)
3883  return;
3884  if (xaccTransHasSplitsInState (trans, VREC))
3885  return;
3886  if (xaccTransHasReconciledSplits (trans) ||
3888  {
3889  gnc_error_dialog (window, "%s",
3890  _ ("You cannot void a transaction with reconciled or cleared splits."));
3891  return;
3892  }
3893  reason = xaccTransGetReadOnly (trans);
3894  if (reason)
3895  {
3896  gnc_error_dialog (window,
3897  _ ("This transaction is marked read-only with the comment: '%s'"), reason);
3898  return;
3899  }
3900 
3901  if (!gnc_plugin_page_register_finish_pending (GNC_PLUGIN_PAGE (page)))
3902  return;
3903 
3904  builder = gtk_builder_new();
3905  gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade",
3906  "void_transaction_dialog");
3907  dialog = GTK_WIDGET (gtk_builder_get_object (builder,
3908  "void_transaction_dialog"));
3909  entry = GTK_WIDGET (gtk_builder_get_object (builder, "reason"));
3910 
3911  gtk_window_set_transient_for (GTK_WINDOW (dialog), window);
3912 
3913  result = gtk_dialog_run (GTK_DIALOG (dialog));
3914  if (result == GTK_RESPONSE_OK)
3915  {
3916  reason = gtk_entry_get_text (GTK_ENTRY (entry));
3917  if (reason == NULL)
3918  reason = "";
3920  }
3921 
3922  /* All done. Get rid of it. */
3923  gtk_widget_destroy (dialog);
3924  g_object_unref (G_OBJECT (builder));
3925 }
3926 
3927 
3928 static void
3929 gnc_plugin_page_register_cmd_unvoid_transaction (GSimpleAction *simple,
3930  GVariant *paramter,
3931  gpointer user_data)
3932 {
3933  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3935  SplitRegister* reg;
3936  Transaction* trans;
3937 
3938  ENTER ("(action %p, page %p)", simple, page);
3939 
3940  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3941 
3942  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3943  reg = gnc_ledger_display_get_split_register (priv->ledger);
3945  if (!xaccTransHasSplitsInState (trans, VREC))
3946  return;
3948  LEAVE (" ");
3949 }
3950 
3951 static std::optional<time64>
3952 input_date (GtkWidget * parent, const char *window_title, const char* title)
3953 {
3954  time64 rv = gnc_time (nullptr);
3955  if (!gnc_dup_time64_dialog (parent, window_title, title, &rv))
3956  return {};
3957 
3958  return rv;
3959 }
3960 
3961 static void
3962 gnc_plugin_page_register_cmd_reverse_transaction (GSimpleAction *simple,
3963  GVariant *paramter,
3964  gpointer user_data)
3965 {
3966  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3968  SplitRegister* reg;
3969  GNCSplitReg* gsr;
3970  Transaction* trans, *new_trans;
3971  GtkWidget *window;
3972  Account *account;
3973  Split *split;
3974 
3975  ENTER ("(action %p, page %p)", simple, page);
3976 
3977  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3978 
3979  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3980  reg = gnc_ledger_display_get_split_register (priv->ledger);
3981  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
3983  if (trans == NULL)
3984  return;
3985 
3987  account = xaccSplitGetAccount (split);
3988 
3989  if (!account)
3990  {
3991  LEAVE ("shouldn't try to reverse the blank transaction...");
3992  return;
3993  }
3994 
3995  new_trans = xaccTransGetReversedBy (trans);
3996  if (new_trans)
3997  {
3998  const char *rev = _("A reversing entry has already been created for this transaction.");
3999  const char *jump = _("Jump to the transaction?");
4000  if (!gnc_verify_dialog (GTK_WINDOW (window), TRUE, "%s\n\n%s", rev, jump))
4001  {
4002  LEAVE ("reverse cancelled");
4003  return;
4004  }
4005  }
4006  else
4007  {
4008  auto date = input_date (window, _("Reverse Transaction"), _("New Transaction Information"));
4009  if (!date)
4010  {
4011  LEAVE ("reverse cancelled");
4012  return;
4013  }
4014 
4015  gnc_suspend_gui_refresh ();
4016  new_trans = xaccTransReverse (trans);
4017 
4018  /* Clear transaction level info */
4019  xaccTransSetDatePostedSecsNormalized (new_trans, date.value());
4020  xaccTransSetDateEnteredSecs (new_trans, gnc_time (NULL));
4021 
4022  gnc_resume_gui_refresh();
4023  }
4024 
4025  /* Now jump to new trans */
4026  gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE (page));
4027  split = xaccTransFindSplitByAccount(new_trans, account);
4028 
4029  /* Test for visibility of split */
4030  if (gnc_split_reg_clear_filter_for_split (gsr, split))
4031  gnc_plugin_page_register_clear_current_filter (GNC_PLUGIN_PAGE(page));
4032 
4033  gnc_split_reg_jump_to_split (gsr, split);
4034  LEAVE (" ");
4035 }
4036 
4037 static gboolean
4038 gnc_plugin_page_register_show_fs_save (GncPluginPageRegister* page)
4039 {
4040  GncPluginPageRegisterPrivate* priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4041  GNCLedgerDisplayType ledger_type = gnc_ledger_display_type (priv->ledger);
4042  SplitRegister* reg = gnc_ledger_display_get_split_register (priv->ledger);
4043 
4044  if (ledger_type == LD_SINGLE || ledger_type == LD_SUBACCOUNT)
4045  return TRUE;
4046  else
4047  {
4048  switch (reg->type)
4049  {
4050  case GENERAL_JOURNAL:
4051  return TRUE;
4052  break;
4053 
4054  case INCOME_LEDGER:
4055  case PORTFOLIO_LEDGER:
4056  case SEARCH_LEDGER:
4057  default:
4058  return FALSE;
4059  break;
4060  }
4061  }
4062 }
4063 
4064 static void
4065 gnc_plugin_page_register_cmd_view_sort_by (GSimpleAction *simple,
4066  GVariant *paramter,
4067  gpointer user_data)
4068 {
4069  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4071  SplitRegister* reg;
4072  GtkWidget* dialog, *button;
4073  GtkBuilder* builder;
4074  SortType sort;
4075  const gchar* name;
4076  gchar* title;
4077 
4078  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4079  ENTER ("(action %p, page %p)", simple, page);
4080 
4081  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4082  if (priv->sd.dialog)
4083  {
4084  gtk_window_present (GTK_WINDOW (priv->sd.dialog));
4085  LEAVE ("existing dialog");
4086  return;
4087  }
4088 
4089  /* Create the dialog */
4090 
4091  builder = gtk_builder_new();
4092  gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade",
4093  "sort_by_dialog");
4094  dialog = GTK_WIDGET (gtk_builder_get_object (builder, "sort_by_dialog"));
4095  priv->sd.dialog = dialog;
4096  gtk_window_set_transient_for (GTK_WINDOW (dialog),
4097  gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window)));
4098  /* Translators: The %s is the name of the plugin page */
4099  title = g_strdup_printf (_ ("Sort %s by…"),
4100  gnc_plugin_page_get_page_name (GNC_PLUGIN_PAGE (page)));
4101  gtk_window_set_title (GTK_WINDOW (dialog), title);
4102  g_free (title);
4103 
4104  /* Set the button for the current sort order */
4105  sort = gnc_split_reg_get_sort_type (priv->gsr);
4106  name = SortTypeasString (sort);
4107  button = GTK_WIDGET (gtk_builder_get_object (builder, name));
4108  DEBUG ("current sort %d, button %s(%p)", sort, name, button);
4109  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4110  priv->sd.original_sort_type = sort;
4111 
4112  button = GTK_WIDGET (gtk_builder_get_object (builder, "sort_save"));
4113  if (priv->sd.save_order == TRUE)
4114  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4115 
4116  // hide the save button if appropriate
4117  gtk_widget_set_visible (GTK_WIDGET (button),
4118  gnc_plugin_page_register_show_fs_save (page));
4119 
4120  /* Set the button for the current reverse_order order */
4121  button = GTK_WIDGET (gtk_builder_get_object (builder, "sort_reverse"));
4122  if (priv->sd.reverse_order == TRUE)
4123  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4124  priv->sd.original_reverse_order = priv->sd.reverse_order;
4125 
4126  priv->sd.num_radio = GTK_WIDGET (gtk_builder_get_object (builder, "BY_NUM"));
4127  priv->sd.act_radio = GTK_WIDGET (gtk_builder_get_object (builder,
4128  "BY_ACTION"));
4129  /* Adjust labels related to Num/Action radio buttons based on book option */
4130  reg = gnc_ledger_display_get_split_register (priv->ledger);
4131  if (reg && !reg->use_tran_num_for_num_field)
4132  {
4133  gtk_button_set_label (GTK_BUTTON (priv->sd.num_radio),
4134  _ ("Transaction Number"));
4135  gtk_button_set_label (GTK_BUTTON (priv->sd.act_radio), _ ("Number/Action"));
4136  }
4137  gnc_book_option_register_cb (OPTION_NAME_NUM_FIELD_SOURCE,
4138  (GncBOCb)gnc_plugin_page_register_sort_book_option_changed,
4139  page);
4140 
4141  /* Wire it up */
4142  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func,
4143  page);
4144 
4145  /* Show it */
4146  gtk_widget_show (dialog);
4147  g_object_unref (G_OBJECT (builder));
4148  LEAVE (" ");
4149 }
4150 
4151 static void
4152 gnc_plugin_page_register_cmd_view_filter_by (GSimpleAction *simple,
4153  GVariant *paramter,
4154  gpointer user_data)
4155 {
4156  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4158  GtkWidget* dialog, *toggle, *button, *table, *hbox;
4159  time64 start_time, end_time, time_val;
4160  GtkBuilder* builder;
4161  gboolean sensitive, value;
4162  Query* query;
4163  gchar* title;
4164  int i;
4165 
4166  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4167  ENTER ("(action %p, page %p)", simple, page);
4168 
4169  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4170  if (priv->fd.dialog)
4171  {
4172  gtk_window_present (GTK_WINDOW (priv->fd.dialog));
4173  LEAVE ("existing dialog");
4174  return;
4175  }
4176 
4177  /* Create the dialog */
4178  builder = gtk_builder_new();
4179  gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade",
4180  "days_adjustment");
4181  gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade",
4182  "filter_by_dialog");
4183  dialog = GTK_WIDGET (gtk_builder_get_object (builder, "filter_by_dialog"));
4184  priv->fd.dialog = dialog;
4185  gtk_window_set_transient_for (GTK_WINDOW (dialog),
4186  gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window)));
4187 
4188  /* Translators: The %s is the name of the plugin page */
4189  title = g_strdup_printf (_ ("Filter %s by…"),
4190  gnc_plugin_page_get_page_name (GNC_PLUGIN_PAGE (page)));
4191  gtk_window_set_title (GTK_WINDOW (dialog), title);
4192  g_free (title);
4193 
4194  /* Set the check buttons for the current status */
4195  for (i = 0; status_actions[i].action_name; i++)
4196  {
4197  toggle = GTK_WIDGET (gtk_builder_get_object (builder,
4198  status_actions[i].action_name));
4199  value = priv->fd.cleared_match & status_actions[i].value;
4200  status_actions[i].widget = toggle;
4201  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), value);
4202  }
4203  priv->fd.original_cleared_match = priv->fd.cleared_match;
4204 
4205  button = GTK_WIDGET (gtk_builder_get_object (builder, "filter_save"));
4206  if (priv->fd.save_filter == TRUE)
4207  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4208 
4209  // hide the save button if appropriate
4210  gtk_widget_set_visible (GTK_WIDGET (button),
4211  gnc_plugin_page_register_show_fs_save (page));
4212 
4213  /* Set up number of days */
4214  priv->fd.num_days = GTK_WIDGET (gtk_builder_get_object (builder,
4215  "filter_show_num_days"));
4216  button = GTK_WIDGET (gtk_builder_get_object (builder, "filter_show_days"));
4217 
4218  query = gnc_ledger_display_get_query (priv->ledger);
4219 
4220  if (priv->fd.days > 0) // using number of days
4221  {
4222  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4223  gtk_widget_set_sensitive (GTK_WIDGET (priv->fd.num_days), TRUE);
4224  gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->fd.num_days), priv->fd.days);
4225  priv->fd.original_days = priv->fd.days;
4226 
4227  /* Set the start_time and end_time to 0 */
4228  start_time = 0;
4229  end_time = 0;
4230  }
4231  else
4232  {
4233  gtk_widget_set_sensitive (GTK_WIDGET (priv->fd.num_days), FALSE);
4234  priv->fd.original_days = 0;
4235  priv->fd.days = 0;
4236 
4237  /* Get the start and end times */
4238  xaccQueryGetDateMatchTT (query, &start_time, &end_time);
4239  }
4240 
4241  /* Set the date info */
4242  priv->fd.original_start_time = start_time;
4243  priv->fd.start_time = start_time;
4244  priv->fd.original_end_time = end_time;
4245  priv->fd.end_time = end_time;
4246 
4247  button = GTK_WIDGET (gtk_builder_get_object (builder, "filter_show_range"));
4248  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), start_time ||
4249  end_time);
4250  table = GTK_WIDGET (gtk_builder_get_object (builder, "select_range_table"));
4251  priv->fd.table = table;
4252  gtk_widget_set_sensitive (GTK_WIDGET (table), start_time || end_time);
4253 
4254  priv->fd.start_date_choose = GTK_WIDGET (gtk_builder_get_object (builder,
4255  "start_date_choose"));
4256  priv->fd.start_date_today = GTK_WIDGET (gtk_builder_get_object (builder,
4257  "start_date_today"));
4258  priv->fd.end_date_choose = GTK_WIDGET (gtk_builder_get_object (builder,
4259  "end_date_choose"));
4260  priv->fd.end_date_today = GTK_WIDGET (gtk_builder_get_object (builder,
4261  "end_date_today"));
4262 
4263  {
4264  /* Start date info */
4265  if (start_time == 0)
4266  {
4267  button = GTK_WIDGET (gtk_builder_get_object (builder, "start_date_earliest"));
4268  time_val = xaccQueryGetEarliestDateFound (query);
4269  sensitive = FALSE;
4270  }
4271  else
4272  {
4273  time_val = start_time;
4274  if ((start_time >= gnc_time64_get_today_start()) &&
4275  (start_time <= gnc_time64_get_today_end()))
4276  {
4277  button = priv->fd.start_date_today;
4278  sensitive = FALSE;
4279  }
4280  else
4281  {
4282  button = priv->fd.start_date_choose;
4283  sensitive = TRUE;
4284  }
4285  }
4286  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4287  priv->fd.start_date = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE);
4288  hbox = GTK_WIDGET (gtk_builder_get_object (builder, "start_date_hbox"));
4289  gtk_box_pack_start (GTK_BOX (hbox), priv->fd.start_date, TRUE, TRUE, 0);
4290  gtk_widget_show (priv->fd.start_date);
4291  gtk_widget_set_sensitive (GTK_WIDGET (priv->fd.start_date), sensitive);
4292  gnc_date_edit_set_time (GNC_DATE_EDIT (priv->fd.start_date), time_val);
4293  g_signal_connect (G_OBJECT (priv->fd.start_date), "date-changed",
4294  G_CALLBACK (gnc_plugin_page_register_filter_gde_changed_cb),
4295  page);
4296  }
4297 
4298  {
4299  /* End date info */
4300  if (end_time == 0)
4301  {
4302  button = GTK_WIDGET (gtk_builder_get_object (builder, "end_date_latest"));
4303  time_val = xaccQueryGetLatestDateFound (query);
4304  sensitive = FALSE;
4305  }
4306  else
4307  {
4308  time_val = end_time;
4309  if ((end_time >= gnc_time64_get_today_start()) &&
4310  (end_time <= gnc_time64_get_today_end()))
4311  {
4312  button = priv->fd.end_date_today;
4313  sensitive = FALSE;
4314  }
4315  else
4316  {
4317  button = priv->fd.end_date_choose;
4318  sensitive = TRUE;
4319  }
4320  }
4321  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4322  priv->fd.end_date = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE);
4323  hbox = GTK_WIDGET (gtk_builder_get_object (builder, "end_date_hbox"));
4324  gtk_box_pack_start (GTK_BOX (hbox), priv->fd.end_date, TRUE, TRUE, 0);
4325  gtk_widget_show (priv->fd.end_date);
4326  gtk_widget_set_sensitive (GTK_WIDGET (priv->fd.end_date), sensitive);
4327  gnc_date_edit_set_time (GNC_DATE_EDIT (priv->fd.end_date), time_val);
4328  g_signal_connect (G_OBJECT (priv->fd.end_date), "date-changed",
4329  G_CALLBACK (gnc_plugin_page_register_filter_gde_changed_cb),
4330  page);
4331  }
4332 
4333  /* Wire it up */
4334  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func,
4335  page);
4336 
4337  /* Show it */
4338  gtk_widget_show (dialog);
4339  g_object_unref (G_OBJECT (builder));
4340  LEAVE (" ");
4341 }
4342 
4343 static void
4344 gnc_plugin_page_register_cmd_reload (GSimpleAction *simple,
4345  GVariant *paramter,
4346  gpointer user_data)
4347 {
4348  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4350  SplitRegister* reg;
4351 
4352  ENTER ("(action %p, page %p)", simple, page);
4353 
4354  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4355 
4356  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4357  reg = gnc_ledger_display_get_split_register (priv->ledger);
4358 
4359  /* Check for trans being edited */
4360  if (gnc_split_register_changed (reg))
4361  {
4362  LEAVE ("register has pending edits");
4363  return;
4364  }
4365  gnc_ledger_display_refresh (priv->ledger);
4366  LEAVE (" ");
4367 }
4368 
4369 static void
4370 gnc_plugin_page_register_cmd_style_changed (GSimpleAction *simple,
4371  GVariant *parameter,
4372  gpointer user_data)
4373 {
4374  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4376  SplitRegisterStyle value;
4377 
4378  ENTER ("(action %p, page %p)", simple, page);
4379 
4380  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4381 
4382  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4383 
4384  value = (SplitRegisterStyle)g_variant_get_int32 (parameter);
4385 
4386  g_action_change_state (G_ACTION(simple), parameter);
4387 
4388  gnc_split_reg_change_style (priv->gsr, value, priv->enable_refresh);
4389 
4390  gnc_plugin_page_register_ui_update (NULL, page);
4391  LEAVE (" ");
4392 }
4393 
4394 static void
4395 gnc_plugin_page_register_cmd_style_double_line (GSimpleAction *simple,
4396  GVariant *parameter,
4397  gpointer user_data)
4398 {
4399  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4401  SplitRegister* reg;
4402  gboolean use_double_line;
4403  GVariant *state;
4404 
4405  ENTER ("(action %p, page %p)", simple, page);
4406 
4407  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(page));
4408 
4409  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4410  reg = gnc_ledger_display_get_split_register (priv->ledger);
4411 
4412  state = g_action_get_state (G_ACTION(simple));
4413 
4414  g_action_change_state (G_ACTION(simple), g_variant_new_boolean (!g_variant_get_boolean (state)));
4415 
4416  use_double_line = !g_variant_get_boolean (state);
4417 
4418  if (use_double_line != reg->use_double_line)
4419  {
4420  gnc_split_register_config (reg, reg->type, reg->style, use_double_line);
4421  if (priv->enable_refresh)
4422  gnc_ledger_display_refresh (priv->ledger);
4423  }
4424  g_variant_unref (state);
4425  LEAVE (" ");
4426 }
4427 
4428 static void
4429 gnc_plugin_page_register_cmd_transfer (GSimpleAction *simple,
4430  GVariant *paramter,
4431  gpointer user_data)
4432 {
4433  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4434  Account* account;
4435  GncWindow* gnc_window;
4436  GtkWidget* window;
4437 
4438  ENTER ("(action %p, page %p)", simple, page);
4439 
4440  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4441 
4442  account = gnc_plugin_page_register_get_account (page);
4443  gnc_window = GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window);
4444  window = GTK_WIDGET (gnc_window_get_gtk_window (gnc_window));
4445  gnc_xfer_dialog (window, account);
4446  LEAVE (" ");
4447 }
4448 
4449 static void
4450 gnc_plugin_page_register_cmd_reconcile (GSimpleAction *simple,
4451  GVariant *paramter,
4452  gpointer user_data)
4453 {
4454  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4455  Account* account;
4456  GtkWindow* window;
4457  RecnWindow* recnData;
4458 
4459  ENTER ("(action %p, page %p)", simple, page);
4460 
4461  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4462 
4463  /* To prevent mistakes involving saving an edited transaction after
4464  * finishing a reconciliation (reverting the reconcile state), require
4465  * pending activity on the current register to be finished.
4466  *
4467  * The reconcile window isn't modal so it's still possible to start editing
4468  * a transaction after opening it, but at that point the user should know
4469  * what they're doing is unsafe.
4470  */
4471  if (!gnc_plugin_page_register_finish_pending (GNC_PLUGIN_PAGE (page)))
4472  return;
4473 
4474  account = gnc_plugin_page_register_get_account (page);
4475 
4476  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (
4477  page)->window));
4478  recnData = recnWindow (GTK_WIDGET (window), account);
4479  gnc_ui_reconcile_window_raise (recnData);
4480  LEAVE (" ");
4481 }
4482 
4483 static void
4484 gnc_plugin_page_register_cmd_stock_assistant (GSimpleAction *simple,
4485  GVariant *paramter,
4486  gpointer user_data)
4487 {
4488  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4489  Account *account;
4490  GtkWindow *window;
4491 
4492  ENTER ("(action %p, page %p)", simple, page);
4493 
4494  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4495  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window));
4496  account = gnc_plugin_page_register_get_account (page);
4497  gnc_stock_transaction_assistant (GTK_WIDGET (window), account);
4498 
4499  LEAVE (" ");
4500 }
4501 
4502 static void
4503 gnc_plugin_page_register_cmd_autoclear (GSimpleAction *simple,
4504  GVariant *paramter,
4505  gpointer user_data)
4506 {
4507  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4508  Account* account;
4509  GtkWindow* window;
4510  AutoClearWindow* autoClearData;
4511 
4512  ENTER ("(action %p, page %p)", simple, page);
4513 
4514  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4515 
4516  account = gnc_plugin_page_register_get_account (page);
4517 
4518  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (
4519  page)->window));
4520  autoClearData = autoClearWindow (GTK_WIDGET (window), account);
4521  gnc_ui_autoclear_window_raise (autoClearData);
4522  LEAVE (" ");
4523 }
4524 
4525 static void
4526 gnc_plugin_page_register_cmd_stock_split (GSimpleAction *simple,
4527  GVariant *paramter,
4528  gpointer user_data)
4529 {
4530  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4531  Account* account;
4532  GtkWindow* window;
4533 
4534  ENTER ("(action %p, page %p)", simple, page);
4535 
4536  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4537 
4538  account = gnc_plugin_page_register_get_account (page);
4539  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window));
4540  gnc_stock_split_dialog (GTK_WIDGET (window), account);
4541  LEAVE (" ");
4542 }
4543 
4544 static void
4545 gnc_plugin_page_register_cmd_lots (GSimpleAction *simple,
4546  GVariant *paramter,
4547  gpointer user_data)
4548 {
4549  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4550  GtkWindow* window;
4551  Account* account;
4552 
4553  ENTER ("(action %p, page %p)", simple, page);
4554 
4555  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4556 
4557  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (
4558  page)->window));
4559  account = gnc_plugin_page_register_get_account (page);
4560  gnc_lot_viewer_dialog (window, account);
4561  LEAVE (" ");
4562 }
4563 
4564 static void
4565 gnc_plugin_page_register_cmd_enter_transaction (GSimpleAction *simple,
4566  GVariant *paramter,
4567  gpointer user_data)
4568 {
4569  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4571 
4572  ENTER ("(action %p, page %p)", simple, page);
4573 
4574  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4575 
4576  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4577  gnc_split_reg_enter (priv->gsr, FALSE);
4578  LEAVE (" ");
4579 }
4580 
4581 static void
4582 gnc_plugin_page_register_cmd_cancel_transaction (GSimpleAction *simple,
4583  GVariant *paramter,
4584  gpointer user_data)
4585 {
4586  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4588 
4589  ENTER ("(action %p, page %p)", simple, page);
4590 
4591  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4592 
4593  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4595  (gnc_ledger_display_get_split_register (priv->ledger));
4596  LEAVE (" ");
4597 }
4598 
4599 static void
4600 gnc_plugin_page_register_cmd_delete_transaction (GSimpleAction *simple,
4601  GVariant *paramter,
4602  gpointer user_data)
4603 {
4604  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4606 
4607  ENTER ("(action %p, page %p)", simple, page);
4608 
4609  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4610 
4611  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4612  gsr_default_delete_handler (priv->gsr, NULL);
4613  LEAVE (" ");
4614 
4615 }
4616 
4617 static void
4618 gnc_plugin_page_register_cmd_linked_transaction (GSimpleAction *simple,
4619  GVariant *paramter,
4620  gpointer user_data)
4621 {
4622  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4624 
4625  ENTER ("(action %p, page %p)", simple, page);
4626 
4627  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4628 
4629  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4630  gsr_default_doclink_handler (priv->gsr);
4631  gnc_plugin_page_register_ui_update (NULL, page);
4632  LEAVE (" ");
4633 }
4634 
4635 static void
4636 gnc_plugin_page_register_cmd_linked_transaction_open (GSimpleAction *simple,
4637  GVariant *paramter,
4638  gpointer user_data)
4639 {
4640  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4642 
4643  ENTER ("(action %p, page %p)", simple, page);
4644 
4645  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4646 
4647  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4648  gsr_default_doclink_open_handler (priv->gsr);
4649  LEAVE (" ");
4650 }
4651 
4652 static GncInvoice* invoice_from_split (Split* split)
4653 {
4654  GncInvoice* invoice;
4655  GNCLot* lot;
4656 
4657  if (!split)
4658  return NULL;
4659 
4660  lot = xaccSplitGetLot (split);
4661  if (!lot)
4662  return NULL;
4663 
4664  invoice = gncInvoiceGetInvoiceFromLot (lot);
4665  if (!invoice)
4666  return NULL;
4667 
4668  return invoice;
4669 }
4670 
4671 
4672 static void
4673 gnc_plugin_page_register_cmd_jump_linked_invoice (GSimpleAction *simple,
4674  GVariant *paramter,
4675  gpointer user_data)
4676 {
4677  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4679  SplitRegister* reg;
4680  GncInvoice* invoice;
4681  Transaction *txn;
4682  GtkWidget *window;
4683 
4684  ENTER ("(action %p, page %p)", simple, page);
4685 
4686  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4687  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4688  reg = gnc_ledger_display_get_split_register (priv->gsr->ledger);
4690  invoice = invoice_from_split (gnc_split_register_get_current_split (reg));
4691  window = GNC_PLUGIN_PAGE(page)->window;
4692 
4693  if (!invoice)
4694  {
4695  auto invoices = invoices_from_transaction (txn);
4696  if (invoices.empty())
4697  PERR ("shouldn't happen: if no invoices, function is never called");
4698  else if (invoices.size() == 1)
4699  invoice = invoices[0];
4700  else
4701  {
4702  GList *details = NULL;
4703  gint choice;
4704  const gchar *amt;
4705  for (const auto& inv : invoices)
4706  {
4707  gchar *date = qof_print_date (gncInvoiceGetDatePosted (inv));
4708  amt = xaccPrintAmount
4709  (gncInvoiceGetTotal (inv),
4710  gnc_account_print_info (gncInvoiceGetPostedAcc (inv), TRUE));
4711  details = g_list_prepend
4712  (details,
4713  /* Translators: %s refer to the following in
4714  order: invoice type, invoice ID, owner name,
4715  posted date, amount */
4716  g_strdup_printf (_("%s %s from %s, posted %s, amount %s"),
4717  gncInvoiceGetTypeString (inv),
4718  gncInvoiceGetID (inv),
4719  gncOwnerGetName (gncInvoiceGetOwner (inv)),
4720  date, amt));
4721  g_free (date);
4722  }
4723  details = g_list_reverse (details);
4724  choice = gnc_choose_radio_option_dialog
4725  (window, _("Select document"),
4726  _("Several documents are linked with this transaction. \
4727 Please choose one:"), _("Select"), 0, details);
4728  if ((choice >= 0) && ((size_t)choice < invoices.size()))
4729  invoice = invoices[choice];
4730  g_list_free_full (details, g_free);
4731  }
4732  }
4733 
4734  if (invoice)
4735  {
4736  GtkWindow *gtk_window = gnc_window_get_gtk_window (GNC_WINDOW (window));
4737  gnc_ui_invoice_edit (gtk_window, invoice);
4738  }
4739 
4740  LEAVE (" ");
4741 }
4742 
4743 static void
4744 gnc_plugin_page_register_cmd_blank_transaction (GSimpleAction *simple,
4745  GVariant *paramter,
4746  gpointer user_data)
4747 {
4748  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4750  SplitRegister* reg;
4751 
4752  ENTER ("(action %p, page %p)", simple, page);
4753 
4754  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4755 
4756  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4757  reg = gnc_ledger_display_get_split_register (priv->ledger);
4758 
4759  if (gnc_split_register_save (reg, TRUE))
4761 
4762  gnc_split_reg_jump_to_blank (priv->gsr);
4763  LEAVE (" ");
4764 }
4765 
4766 static bool
4767 find_after_date (Split *split, time64* find_date)
4768 {
4769  auto trans = xaccSplitGetParent (split);
4770  return !(xaccSplitGetAccount (split) != nullptr &&
4771  xaccTransGetDate (trans) >= *find_date &&
4772  xaccTransCountSplits (trans) != 1);
4773 }
4774 
4775 static void
4776 gnc_plugin_page_register_cmd_goto_date (GSimpleAction *simple,
4777  GVariant *paramter,
4778  gpointer user_data)
4779 {
4780  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4781  GNCSplitReg* gsr;
4782  Query* query;
4783  GList *splits;
4784  GtkWidget *window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
4785 
4786  ENTER ("(action %p, page %p)", simple, page);
4787  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4788 
4789  auto date = input_date (window, _("Go to Date"), _("Go to Date"));
4790 
4791  if (!date)
4792  {
4793  LEAVE ("goto_date cancelled");
4794  return;
4795  }
4796 
4797  gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE (page));
4798  query = gnc_plugin_page_register_get_query (GNC_PLUGIN_PAGE (page));
4799  splits = g_list_copy (qof_query_run (query));
4800  splits = g_list_sort (splits, (GCompareFunc)xaccSplitOrder);
4801 
4802  // if gl register, there could be blank splits from other open registers
4803  // included in split list so check for and ignore them
4804  auto it = g_list_find_custom (splits, &date.value(), (GCompareFunc)find_after_date);
4805 
4806  if (it)
4807  gnc_split_reg_jump_to_split (gsr, GNC_SPLIT(it->data));
4808  else
4809  gnc_split_reg_jump_to_blank (gsr);
4810 
4811  g_list_free (splits);
4812  LEAVE (" ");
4813 }
4814 
4815 static void
4816 gnc_plugin_page_register_cmd_duplicate_transaction (GSimpleAction *simple,
4817  GVariant *paramter,
4818  gpointer user_data)
4819 {
4820  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4822 
4823  ENTER ("(action %p, page %p)", simple, page);
4824 
4825  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4826 
4827  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4829  (gnc_ledger_display_get_split_register (priv->ledger));
4830  LEAVE (" ");
4831 }
4832 
4833 static void
4834 gnc_plugin_page_register_cmd_reinitialize_transaction (GSimpleAction *simple,
4835  GVariant *paramter,
4836  gpointer user_data)
4837 {
4838  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4840 
4841  ENTER ("(action %p, page %p)", simple, page);
4842 
4843  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4844 
4845  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4846  gsr_default_reinit_handler (priv->gsr, NULL);
4847  LEAVE (" ");
4848 }
4849 
4850 static void
4851 gnc_plugin_page_register_cmd_expand_transaction (GSimpleAction *simple,
4852  GVariant *parameter,
4853  gpointer user_data)
4854 {
4855  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4857  SplitRegister* reg;
4858  gboolean expand;
4859  GVariant *state;
4860 
4861  ENTER ("(action %p, page %p)", simple, page);
4862 
4863  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4864 
4865  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4866  reg = gnc_ledger_display_get_split_register (priv->ledger);
4867 
4868  state = g_action_get_state (G_ACTION(simple));
4869 
4870  g_action_change_state (G_ACTION(simple), g_variant_new_boolean (!g_variant_get_boolean (state)));
4871 
4872  expand = !g_variant_get_boolean (state);
4873 
4875  g_variant_unref (state);
4876  LEAVE (" ");
4877 }
4878 
4881 static void
4882 gnc_plugin_page_register_cmd_exchange_rate (GSimpleAction *simple,
4883  GVariant *paramter,
4884  gpointer user_data)
4885 {
4886  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
4888  SplitRegister* reg;
4889 
4890  ENTER ("(action %p, page %p)", simple, page);
4891 
4892  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
4893 
4894  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
4895  reg = gnc_ledger_display_get_split_register (priv->ledger);
4896 
4897  /* XXX Ignore the return value -- we don't care if this succeeds */
4898  (void)gnc_split_register_handle_exchange (reg, TRUE);
4899  LEAVE (" ");
4900 }
4901 
4902 static Split*
4903 jump_multiple_splits_by_single_account (Account *account, Split *split)
4904 {
4905  Transaction *trans;
4906  SplitList *splits;
4907  Account *other_account = NULL;
4908  Split *other_split = NULL;
4909 
4910  trans = xaccSplitGetParent(split);
4911  if (!trans)
4912  return NULL;
4913 
4914  for (splits = xaccTransGetSplitList(trans); splits; splits = splits->next)
4915  {
4916  Split *s = (Split*)splits->data;
4917  Account *a = xaccSplitGetAccount(s);
4918 
4919  if (!xaccTransStillHasSplit(trans, s))
4920  continue;
4921 
4922  if (a == account)
4923  continue;
4924 
4925  if (other_split)
4926  {
4927  if (other_account != a)
4928  return NULL;
4929 
4930  continue;
4931  }
4932 
4933  other_account = a;
4934  other_split = s;
4935  }
4936 
4937  // Jump to the same account so that the right warning is triggered
4938  if (!other_split)
4939  other_split = split;
4940 
4941  return other_split;
4942 }
4943 
4944 static Split*
4945 jump_multiple_splits_by_value (Account *account, Split *split, gboolean largest)
4946 {
4947  Transaction *trans;
4948  SplitList *splits;
4949  Split *other_split = NULL;
4950  gnc_numeric best;
4951  int cmp = largest ? 1 : -1;
4952 
4953  trans = xaccSplitGetParent(split);
4954  if (!trans)
4955  return NULL;
4956 
4957  for (splits = xaccTransGetSplitList(trans); splits; splits = splits->next)
4958  {
4959  Split *s = (Split*)splits->data;
4960  gnc_numeric value;
4961 
4962  if (!xaccTransStillHasSplit(trans, s))
4963  continue;
4964 
4965  if (xaccSplitGetAccount(s) == account)
4966  continue;
4967 
4968  value = gnc_numeric_abs(xaccSplitGetValue(s));
4969  if (gnc_numeric_check(value))
4970  continue;
4971 
4972  /* For splits with the same value as the best, the first split
4973  * encountered is used.
4974  */
4975  if (other_split && gnc_numeric_compare(value, best) != cmp)
4976  continue;
4977 
4978  best = value;
4979  other_split = s;
4980  }
4981 
4982  // Jump to the same account so that the right warning is triggered
4983  if (!other_split)
4984  other_split = split;
4985 
4986  return other_split;
4987 }
4988 
4989 static Split*
4990 jump_multiple_splits (Account* account, Split *split)
4991 {
4992  GncPrefJumpMultSplits mode = (GncPrefJumpMultSplits)gnc_prefs_get_enum(GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_JUMP_MULT_SPLITS);
4993 
4994  switch (mode)
4995  {
4996  case JUMP_LARGEST_VALUE_FIRST_SPLIT:
4997  return jump_multiple_splits_by_value (account, split, TRUE);
4998 
4999  case JUMP_SMALLEST_VALUE_FIRST_SPLIT:
5000  return jump_multiple_splits_by_value (account, split, FALSE);
5001 
5002  case JUMP_DEFAULT:
5003  default:
5004  break;
5005  }
5006 
5007  // If there's only one other account, use that one
5008  return jump_multiple_splits_by_single_account (account, split);
5009 }
5010 
5011 static void
5012 gnc_plugin_page_register_cmd_jump (GSimpleAction *simple,
5013  GVariant *paramter,
5014  gpointer user_data)
5015 {
5016  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5018  GncPluginPage* new_page;
5019  GtkWidget* window;
5020  GNCSplitReg* gsr;
5021  SplitRegister* reg;
5022  Account* account;
5023  Account* leader;
5024  Split* split;
5025  Split* other_split;
5026  gboolean multiple_splits;
5027 
5028  ENTER ("(action %p, page %p)", simple, page);
5029 
5030  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5031 
5032  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5033  window = GNC_PLUGIN_PAGE (page)->window;
5034  if (window == NULL)
5035  {
5036  LEAVE ("no window");
5037  return;
5038  }
5039 
5040  reg = gnc_ledger_display_get_split_register (priv->ledger);
5042  if (split == NULL)
5043  {
5044  LEAVE ("no split (1)");
5045  return;
5046  }
5047 
5048  account = xaccSplitGetAccount (split);
5049  if (account == NULL)
5050  {
5051  LEAVE ("no account");
5052  return;
5053  }
5054 
5055  other_split = xaccSplitGetOtherSplit (split);
5056  multiple_splits = other_split == NULL;
5057 
5058  leader = gnc_ledger_display_leader (priv->ledger);
5059  if (account == leader)
5060  {
5062  if (cursor_class == CURSOR_CLASS_SPLIT)
5063  {
5064  /* If you've selected the transaction itself, we jump to the "other"
5065  * account corresponding to the anchoring split.
5066  *
5067  * If you've selected the split for another account, we jump to that
5068  * split's account (account != leader, so this block is never
5069  * reached).
5070  *
5071  * If you've selected a split for this account, for consistency with
5072  * selecting the split of another account we should do nothing.
5073  * You're already on the account for the split you selected. Jumping
5074  * to the "other" account now would make the "multiple split"
5075  * options confusing.
5076  *
5077  * We could jump to a different anchoring split but that'll be very
5078  * subtle and only cause problems because it'll have to save any
5079  * modifications to the current register.
5080  */
5081  LEAVE ("split for this account");
5082  return;
5083  }
5084 
5085  if (multiple_splits)
5086  {
5087  other_split = jump_multiple_splits (account, split);
5088  }
5089  if (other_split == NULL)
5090  {
5091  GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(window),
5092  (GtkDialogFlags)(GTK_DIALOG_MODAL
5093  | GTK_DIALOG_DESTROY_WITH_PARENT),
5094  GTK_MESSAGE_ERROR,
5095  GTK_BUTTONS_NONE,
5096  "%s",
5097  _("Unable to jump to other account"));
5098 
5099  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
5100  "%s", _("This transaction involves more than one other account. Select a specific split to jump to that account."));
5101  gtk_dialog_add_button (GTK_DIALOG(dialog), _("_OK"), GTK_RESPONSE_OK);
5102  gnc_dialog_run (GTK_DIALOG(dialog), GNC_PREF_WARN_REG_TRANS_JUMP_MULTIPLE_SPLITS);
5103  gtk_widget_destroy (dialog);
5104 
5105  LEAVE ("no split (2)");
5106  return;
5107  }
5108 
5109  split = other_split;
5110 
5111  account = xaccSplitGetAccount (split);
5112  if (account == NULL)
5113  {
5114  LEAVE ("no account (2)");
5115  return;
5116  }
5117 
5118  if (account == leader)
5119  {
5120  GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(window),
5121  (GtkDialogFlags)(GTK_DIALOG_MODAL
5122  | GTK_DIALOG_DESTROY_WITH_PARENT),
5123  GTK_MESSAGE_ERROR,
5124  GTK_BUTTONS_NONE,
5125  "%s",
5126  _("Unable to jump to other account"));
5127 
5128  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
5129  "%s", _("This transaction only involves the current account so there is no other account to jump to."));
5130  gtk_dialog_add_button (GTK_DIALOG(dialog), _("_OK"), GTK_RESPONSE_OK);
5131  gnc_dialog_run (GTK_DIALOG(dialog), GNC_PREF_WARN_REG_TRANS_JUMP_SINGLE_ACCOUNT);
5132  gtk_widget_destroy (dialog);
5133 
5134  LEAVE ("register open for account");
5135  return;
5136  }
5137  }
5138 
5139  new_page = gnc_plugin_page_register_new (account, FALSE);
5140  if (new_page == NULL)
5141  {
5142  LEAVE ("couldn't create new page");
5143  return;
5144  }
5145 
5146  gnc_main_window_open_page (GNC_MAIN_WINDOW (window), new_page);
5147  gsr = gnc_plugin_page_register_get_gsr (new_page);
5148 
5149  SplitRegister *new_page_reg = gnc_ledger_display_get_split_register (gsr->ledger);
5150  gboolean jump_twice = FALSE;
5151 
5152  /* Selecting the split (instead of just the transaction to open the "other"
5153  * account) requires jumping a second time after expanding the transaction,
5154  * in the basic and auto ledger modes.
5155  */
5156  if (new_page_reg->style != REG_STYLE_JOURNAL)
5157  jump_twice = TRUE;
5158 
5159  /* Test for visibility of split */
5160  if (gnc_split_reg_clear_filter_for_split (gsr, split))
5161  gnc_plugin_page_register_clear_current_filter (GNC_PLUGIN_PAGE(new_page));
5162 
5163  gnc_split_reg_jump_to_split (gsr, split);
5164 
5165  if (multiple_splits && jump_twice)
5166  {
5167  /* Expand the transaction for the basic and auto ledger to identify the
5168  * split in this register, but only if there are more than two splits.
5169  */
5170  gnc_split_register_expand_current_trans (new_page_reg, TRUE);
5171  gnc_split_reg_jump_to_split (gsr, split);
5172  }
5173  LEAVE (" ");
5174 }
5175 
5176 static void
5177 gnc_plugin_page_register_cmd_schedule (GSimpleAction *simple,
5178  GVariant *paramter,
5179  gpointer user_data)
5180 {
5181  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5183  GtkWindow* window;
5184 
5185  ENTER ("(action %p, page %p)", simple, page);
5186 
5187  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5188 
5189  window = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (
5190  page)));
5191  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5192  gsr_default_schedule_handler (priv->gsr, window);
5193  LEAVE (" ");
5194 }
5195 
5196 static void
5197 scrub_split (Split *split)
5198 {
5199  Account *acct;
5200  Transaction *trans;
5201  GNCLot *lot;
5202 
5203  g_return_if_fail (split);
5204  acct = xaccSplitGetAccount (split);
5205  trans = xaccSplitGetParent (split);
5206  lot = xaccSplitGetLot (split);
5207  g_return_if_fail (trans);
5208 
5209  xaccTransScrubOrphans (trans);
5210  xaccTransScrubImbalance (trans, gnc_get_current_root_account(), NULL);
5211  if (lot && xaccAccountIsAPARType (xaccAccountGetType (acct)))
5212  {
5213  gncScrubBusinessLot (lot);
5214  gncScrubBusinessSplit (split);
5215  }
5216 }
5217 
5218 static void
5219 gnc_plugin_page_register_cmd_scrub_current (GSimpleAction *simple,
5220  GVariant *paramter,
5221  gpointer user_data)
5222 {
5223  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5225  Query* query;
5226  SplitRegister* reg;
5227 
5228  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5229 
5230  ENTER ("(action %p, page %p)", simple, page);
5231 
5232  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5233  query = gnc_ledger_display_get_query (priv->ledger);
5234  if (query == NULL)
5235  {
5236  LEAVE ("no query found");
5237  return;
5238  }
5239 
5240  reg = gnc_ledger_display_get_split_register (priv->ledger);
5241 
5242  gnc_suspend_gui_refresh();
5243  scrub_split (gnc_split_register_get_current_split (reg));
5244  gnc_resume_gui_refresh();
5245  LEAVE (" ");
5246 }
5247 
5248 static gboolean
5249 scrub_kp_handler (GtkWidget *widget, GdkEventKey *event, gpointer data)
5250 {
5251  if (event->length == 0) return FALSE;
5252 
5253  switch (event->keyval)
5254  {
5255  case GDK_KEY_Escape:
5256  {
5257  auto abort_scrub = gnc_verify_dialog (GTK_WINDOW(widget), false,
5258  "%s", _(check_repair_abort_YN));
5259 
5260  if (abort_scrub)
5261  gnc_set_abort_scrub (TRUE);
5262 
5263  return TRUE;
5264  }
5265  default:
5266  break;
5267  }
5268  return FALSE;
5269 }
5270 
5271 static void
5272 gnc_plugin_page_register_cmd_scrub_all (GSimpleAction *simple,
5273  GVariant *paramter,
5274  gpointer user_data)
5275 {
5276  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5278  Query* query;
5279  GncWindow* window;
5280  GList* node, *splits;
5281  gint split_count = 0, curr_split_no = 0;
5282  gulong scrub_kp_handler_ID;
5283  const char* message = _ ("Checking splits in current register: %u of %u");
5284 
5285  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5286 
5287  ENTER ("(action %p, page %p)", simple, page);
5288 
5289  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5290  query = gnc_ledger_display_get_query (priv->ledger);
5291  if (!query)
5292  {
5293  LEAVE ("no query found");
5294  return;
5295  }
5296 
5297  gnc_suspend_gui_refresh();
5298  is_scrubbing = TRUE;
5299  gnc_set_abort_scrub (FALSE);
5300  window = GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window);
5301  scrub_kp_handler_ID = g_signal_connect (G_OBJECT (window), "key-press-event",
5302  G_CALLBACK (scrub_kp_handler), NULL);
5303  gnc_window_set_progressbar_window (window);
5304 
5305  splits = qof_query_run (query);
5306  split_count = g_list_length (splits);
5307  for (node = splits; node && !gnc_get_abort_scrub (); node = node->next, curr_split_no++)
5308  {
5309  auto split = GNC_SPLIT(node->data);
5310 
5311  if (!split) continue;
5312 
5313  PINFO ("Start processing split %d of %d",
5314  curr_split_no + 1, split_count);
5315 
5316  scrub_split (split);
5317 
5318  PINFO ("Finished processing split %d of %d",
5319  curr_split_no + 1, split_count);
5320 
5321  if (curr_split_no % 10 == 0)
5322  {
5323  char* progress_msg = g_strdup_printf (message, curr_split_no, split_count);
5324  gnc_window_show_progress (progress_msg, (100 * curr_split_no) / split_count);
5325  g_free (progress_msg);
5326  }
5327  }
5328 
5329  g_signal_handler_disconnect (G_OBJECT(window), scrub_kp_handler_ID);
5330  gnc_window_show_progress (NULL, -1.0);
5331  is_scrubbing = FALSE;
5332  show_abort_verify = TRUE;
5333  gnc_set_abort_scrub (FALSE);
5334 
5335  gnc_resume_gui_refresh();
5336  LEAVE (" ");
5337 }
5338 
5339 static void
5340 gnc_plugin_page_register_cmd_account_report (GSimpleAction *simple,
5341  GVariant *paramter,
5342  gpointer user_data)
5343 {
5344  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5346  GncMainWindow* window;
5347  int id;
5348 
5349  ENTER ("(action %p, page %p)", simple, page);
5350 
5351  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5352 
5353  window = GNC_MAIN_WINDOW (GNC_PLUGIN_PAGE (page)->window);
5354  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5355  id = report_helper (priv->ledger, NULL, NULL);
5356  if (id >= 0)
5357  gnc_main_window_open_report (id, window);
5358  LEAVE (" ");
5359 }
5360 
5361 static void
5362 gnc_plugin_page_register_cmd_transaction_report (GSimpleAction *simple,
5363  GVariant *paramter,
5364  gpointer user_data)
5365 {
5366  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5368  GncMainWindow* window;
5369  SplitRegister* reg;
5370  Split* split;
5371  Query* query;
5372  int id;
5373 
5374 
5375  ENTER ("(action %p, page %p)", simple, page);
5376 
5377  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5378 
5379  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5380  reg = gnc_ledger_display_get_split_register (priv->ledger);
5381 
5383  if (!split)
5384  return;
5385 
5386  query = qof_query_create_for (GNC_ID_SPLIT);
5387 
5388  qof_query_set_book (query, gnc_get_current_book());
5389 
5390  xaccQueryAddGUIDMatch (query, xaccSplitGetGUID (split),
5391  GNC_ID_SPLIT, QOF_QUERY_AND);
5392 
5393  window = GNC_MAIN_WINDOW (GNC_PLUGIN_PAGE (page)->window);
5394  id = report_helper (priv->ledger, split, query);
5395  if (id >= 0)
5396  gnc_main_window_open_report (id, window);
5397  LEAVE (" ");
5398 }
5399 
5400 /************************************************************/
5401 /* Auxiliary functions */
5402 /************************************************************/
5403 
5404 void
5406  gint lines_default,
5407  gboolean read_only)
5408 {
5409  GncPluginPageRegister* page;
5411 
5412  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
5413 
5414  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
5415  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5416  priv->lines_default = lines_default;
5417  priv->read_only = read_only;
5418 }
5419 
5420 GNCSplitReg*
5422 {
5423  GncPluginPageRegister* page;
5425 
5426  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page), NULL);
5427 
5428  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
5429  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5430 
5431  return priv->gsr;
5432 }
5433 
5434 static void
5435 gnc_plugin_page_help_changed_cb (GNCSplitReg* gsr,
5436  GncPluginPageRegister* register_page)
5437 {
5439  SplitRegister* reg;
5440  GncWindow* window;
5441  char* help;
5442 
5443  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (register_page));
5444 
5445  window = GNC_WINDOW (GNC_PLUGIN_PAGE (register_page)->window);
5446  if (!window)
5447  {
5448  // This routine can be called before the page is added to a
5449  // window.
5450  return;
5451  }
5452 
5453  // only update status text if on current page
5454  if (GNC_IS_MAIN_WINDOW(window) && (gnc_main_window_get_current_page
5455  (GNC_MAIN_WINDOW(window)) != GNC_PLUGIN_PAGE(register_page)))
5456  return;
5457 
5458  /* Get the text from the ledger */
5459  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (register_page);
5460  reg = gnc_ledger_display_get_split_register (priv->ledger);
5461  help = gnc_table_get_help (reg->table);
5462  gnc_window_set_status (window, GNC_PLUGIN_PAGE (register_page), help);
5463  g_free (help);
5464 }
5465 
5466 static void
5467 gnc_plugin_page_popup_menu_cb (GNCSplitReg* gsr,
5468  GncPluginPageRegister* page)
5469 {
5470  GncWindow* window;
5471 
5472  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5473 
5474  window = GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window);
5475  if (!window)
5476  {
5477  // This routine can be called before the page is added to a
5478  // window.
5479  return;
5480  }
5481  gnc_main_window_popup_menu_cb (GTK_WIDGET (window),
5482  GNC_PLUGIN_PAGE (page));
5483 }
5484 
5485 static void
5486 gnc_plugin_page_register_refresh_cb (GHashTable* changes, gpointer user_data)
5487 {
5488  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
5490 
5491  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
5492  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5493 
5494  if (changes)
5495  {
5496  const EventInfo* ei;
5497  ei = gnc_gui_get_entity_events (changes, &priv->key);
5498  if (ei)
5499  {
5500  if (ei->event_mask & QOF_EVENT_DESTROY)
5501  {
5502  gnc_main_window_close_page (GNC_PLUGIN_PAGE (page));
5503  return;
5504  }
5505  if (ei->event_mask & QOF_EVENT_MODIFY)
5506  {
5507  }
5508  }
5509  }
5510  else
5511  {
5512  /* forced updates */
5513  gnucash_register_refresh_from_prefs (priv->gsr->reg);
5514  gtk_widget_queue_draw (priv->widget);
5515  }
5516 
5517  gnc_plugin_page_register_ui_update (NULL, page);
5518 }
5519 
5520 static void
5521 gnc_plugin_page_register_close_cb (gpointer user_data)
5522 {
5523  GncPluginPage* plugin_page = GNC_PLUGIN_PAGE (user_data);
5524  gnc_main_window_close_page (plugin_page);
5525 }
5526 
5535 static void
5536 gppr_account_destroy_cb (Account* account)
5537 {
5538  GncPluginPageRegister* page;
5540  GNCLedgerDisplayType ledger_type;
5541  const GncGUID* acct_guid;
5542  const GList* citem;
5543  GList* item, *kill = NULL;
5544 
5545  acct_guid = xaccAccountGetGUID (account);
5546 
5547  /* Find all windows that need to be killed. Don't kill them yet, as
5548  * that would affect the list being walked.*/
5549  citem = gnc_gobject_tracking_get_list (GNC_PLUGIN_PAGE_REGISTER_NAME);
5550  for (; citem; citem = g_list_next (citem))
5551  {
5552  page = (GncPluginPageRegister*)citem->data;
5553  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5554  ledger_type = gnc_ledger_display_type (priv->ledger);
5555  if (ledger_type == LD_GL)
5556  {
5557  kill = g_list_prepend (kill, page);
5558  /* kill it */
5559  }
5560  else if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
5561  {
5562  if (guid_compare (acct_guid, &priv->key) == 0)
5563  {
5564  kill = g_list_prepend (kill, page);
5565  }
5566  }
5567  }
5568 
5569  kill = g_list_reverse (kill);
5570  /* Now kill them. */
5571  for (item = kill; item; item = g_list_next (item))
5572  {
5573  page = (GncPluginPageRegister*)item->data;
5574  gnc_main_window_close_page (GNC_PLUGIN_PAGE (page));
5575  }
5576  g_list_free (kill);
5577 }
5578 
5593 static void
5594 gnc_plugin_page_register_event_handler (QofInstance* entity,
5595  QofEventId event_type,
5596  GncPluginPageRegister* page,
5597  GncEventData* ed)
5598 {
5599  Transaction* trans;
5600  QofBook* book;
5601  GncPluginPage* visible_page;
5602  GtkWidget* window;
5603 
5604  g_return_if_fail (page); /* Required */
5605  if (!GNC_IS_TRANS (entity) && !GNC_IS_ACCOUNT (entity))
5606  return;
5607 
5608  ENTER ("entity %p of type %d, page %p, event data %p",
5609  entity, event_type, page, ed);
5610 
5611  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
5612 
5613  if (GNC_IS_ACCOUNT (entity))
5614  {
5615  if (GNC_IS_MAIN_WINDOW (window))
5616  {
5617  GncPluginPageRegisterPrivate *priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
5618 
5619  if (!gnc_ledger_display_leader (priv->ledger))
5620  {
5621  LEAVE ("account is NULL");
5622  return;
5623  }
5624 
5625  gchar *name = gnc_plugin_page_register_get_tab_name (GNC_PLUGIN_PAGE (page));
5626  main_window_update_page_name (GNC_PLUGIN_PAGE (page), name);
5627 
5628  gchar *long_name = gnc_plugin_page_register_get_long_name (GNC_PLUGIN_PAGE (page));
5629  main_window_update_page_long_name (GNC_PLUGIN_PAGE (page), long_name);
5630 
5631  gchar *color = gnc_plugin_page_register_get_tab_color (GNC_PLUGIN_PAGE (page));
5632  main_window_update_page_color (GNC_PLUGIN_PAGE (page), color);
5633  // update page icon if read only registers
5634  gnc_plugin_page_register_update_page_icon (GNC_PLUGIN_PAGE (page));
5635 
5636  g_free (color);
5637  g_free (name);
5638  g_free (long_name);
5639  }
5640  LEAVE ("tab contents updated");
5641  return;
5642  }
5643 
5644  if (! (event_type & (QOF_EVENT_MODIFY | QOF_EVENT_DESTROY)))
5645  {
5646  LEAVE ("not a modify");
5647  return;
5648  }
5649  trans = GNC_TRANS (entity);
5650  book = qof_instance_get_book (QOF_INSTANCE (trans));
5651  if (!gnc_plugin_page_has_book (GNC_PLUGIN_PAGE (page), book))
5652  {
5653  LEAVE ("not in this book");
5654  return;
5655  }
5656 
5657  if (GNC_IS_MAIN_WINDOW (window))
5658  {
5659  visible_page = gnc_main_window_get_current_page (GNC_MAIN_WINDOW (window));
5660  if (visible_page != GNC_PLUGIN_PAGE (page))
5661  {
5662  LEAVE ("page not visible");
5663  return;
5664  }
5665  }
5666 
5667  gnc_plugin_page_register_ui_update (NULL, page);
5668  LEAVE (" ");
5669  return;
5670 }
5671 
5672 
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:4502
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:3233
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:3210
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:1332
GSimpleActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GSimpleActionGroup object associated with this page.
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition: guid.cpp:208
void gnc_ledger_display_set_query(GNCLedgerDisplay *ledger_display, Query *q)
Set the query used for a register.
gint gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
Cleanup functions for business objects.
gnc_numeric gncInvoiceGetTotal(GncInvoice *invoice)
Return the "total" amount of the invoice as seen on the document (and shown to the user in the report...
Definition: gncInvoice.c:1008
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition: gnc-state.c:248
void gnc_ui_edit_account_window(GtkWindow *parent, Account *account)
Display a window for editing the attributes of an existing account.
gboolean gnc_split_register_current_trans_expanded(SplitRegister *reg)
Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER.
GncPluginPage * gnc_main_window_get_current_page(GncMainWindow *window)
Retrieve a pointer to the page that is currently at the front of the specified window.
const char * xaccTransGetDocLink(const Transaction *trans)
Gets the transaction Document Link.
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
Query * gnc_ledger_display_get_query(GNCLedgerDisplay *ld)
return the query associated with a ledger
Functions for adding content to a window.
void gnc_plugin_add_menu_tooltip_callbacks(GtkWidget *menubar, GMenuModel *menubar_model, GtkWidget *statusbar)
This function adds the tooltip callbacks to make the tooltips appear in the status bar...
Definition: gnc-plugin.c:268
GncPluginPage * gnc_plugin_page_register_new_ledger(GNCLedgerDisplay *ledger)
Create a new "register" plugin page, given a pointer to an already created ledger.
void(* update_edit_menu_actions)(GncPluginPage *plugin_page, gboolean hide)
This function vector allows page specific actions to override the generic code for setting the sensit...
#define VREC
split is void
Definition: Split.h:77
void(* destroy_widget)(GncPluginPage *plugin_page)
Function called to destroy the display widget for a particular type of plugin.
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition: qofevent.cpp:73
void main_window_update_page_long_name(GncPluginPage *page, const gchar *long_name_in)
Update the long name of the page in the main window.
void gnc_tm_free(struct tm *time)
free a struct tm* created with gnc_localtime() or gnc_gmtime()
Definition: gnc-date.cpp:95
const char * xaccAccountGetColor(const Account *acc)
Get the account&#39;s color.
Definition: Account.cpp:3316
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:3271
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:1299
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:1350
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:3129
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:4478
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:3374
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:3367
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:165
void gnc_plugin_page_register_filter_status_select_all_cb(GtkButton *button, GncPluginPageRegister *plugin_page)
This function is called whenever the "select all" status button is clicked.
time64 gnc_time64_get_today_end(void)
The gnc_time64_get_today_end() routine returns a time64 value corresponding to the last second of tod...
Definition: gnc-date.cpp:1359
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:1319
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:3255
The type used to store guids in C.
Definition: guid.h:75
GNCSplitReg * gnc_plugin_page_register_get_gsr(GncPluginPage *plugin_page)
Get the GNCSplitReg data structure associated with this register page.
void gnc_plugin_page_register_sort_order_reverse_cb(GtkToggleButton *button, GncPluginPageRegister *page)
This function is called whenever the reverse sort order is checked or unchecked which allows reversin...
void main_window_update_page_name(GncPluginPage *page, const gchar *name_in)
Update the name of the page in the main window.
A Query.
Definition: qofquery.cpp:74
gboolean gnc_menubar_model_update_item(GMenuModel *menu_model, const gchar *action_name, const gchar *target, const gchar *label, const gchar *accel_name, const gchar *tooltip)
Update the GMenuModel item based on the action name by copying existing item, removing it and inserti...
GAction * gnc_plugin_page_get_action(GncPluginPage *page, const gchar *name)
Retrieve a GAction object associated with this page.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.
void gnc_plugin_page_register_set_options(GncPluginPage *plugin_page, gint lines_default, gboolean read_only)
Set various register options on a newly created "register" plugin page.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
GtkWidget * summarybar
The summary bar widget (if any) that is associated with this plugin.
SplitRegisterStyle
Register styles.
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn&#39;t be...
Definition: Split.cpp:1884
GList * qof_query_get_books(QofQuery *q)
Return the list of books we&#39;re using.
Definition: qofquery.cpp:1341
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
Definition: gnc-prefs.cpp:142
void gnc_split_register_copy_current(SplitRegister *reg)
Makes a copy of the current entity, either a split or a transaction, so that it can be pasted later...
Utility functions for file access.
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2048