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