GnuCash  5.6-150-g038405b370+
gnc-plugin-page-register.cpp
1 /**********************************************************************
2  * gnc-plugin-page-register.c -- register page functions *
3  * *
4  * Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de> *
5  * Copyright (C) 2003,2005,2006 David Hampton <hampton@employees.org> *
6  * Copyright (C) 2011, Robert Fewell *
7  * *
8  * This program is free software; you can redistribute it and/or *
9  * modify it under the terms of the GNU General Public License as *
10  * published by the Free Software Foundation; either version 2 of *
11  * the License, or (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, contact: *
20  * *
21  * Free Software Foundation Voice: +1-617-542-5942 *
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
23  * Boston, MA 02110-1301, USA gnu@gnu.org *
24  **********************************************************************/
25 
36 #include <config.h>
37 
38 #include <optional>
39 
40 #include <libguile.h>
41 #include <gtk/gtk.h>
42 #include <glib/gi18n.h>
43 #include "swig-runtime.h"
44 #include "guile-mappings.h"
45 
47 #include "gnc-plugin-register.h"
49 #include "gnc-plugin-page-report.h"
50 #include "gnc-plugin-business.h"
51 
52 #include "dialog-account.h"
53 #include "dialog-dup-trans.h"
54 #include "dialog-find-account.h"
55 #include "dialog-find-transactions.h"
56 #include "dialog-print-check.h"
57 #include "dialog-invoice.h"
58 #include "dialog-transfer.h"
59 #include "dialog-utils.h"
60 #include "assistant-stock-split.h"
61 #include "assistant-stock-transaction.h"
62 #include "gnc-component-manager.h"
63 #include "gnc-date.h"
64 #include "gnc-date-edit.h"
65 #include "gnc-engine.h"
66 #include "gnc-event.h"
67 #include "gnc-features.h"
68 #include "gnc-glib-utils.h"
69 #include "gnc-gnome-utils.h"
70 #include "gnc-gobject-utils.h"
71 #include "gnc-gui-query.h"
72 #include "gnc-icons.h"
73 #include "gnc-split-reg.h"
74 #include "gnc-state.h"
75 #include "gnc-prefs.h"
76 #include "gnc-ui-util.h"
77 #include "gnc-window.h"
78 #include "gnc-main-window.h"
79 #include "gnc-session.h"
80 #include "gnc-ui.h"
81 #include "gnc-warnings.h"
82 #include "gnucash-sheet.h"
83 #include "dialog-lot-viewer.h"
84 #include "Scrub.h"
85 #include "ScrubBusiness.h"
86 #include "qof.h"
87 #include "window-reconcile.h"
88 #include "window-autoclear.h"
89 #include "window-report.h"
90 #include "engine-helpers.h"
91 #include "qofbookslots.h"
92 #include "gnc-gtk-utils.h"
93 
94 /* gschema: org.gnucash.GnuCash.general.register.JumpMultipleSplits */
95 typedef enum : gint
96 {
97  JUMP_DEFAULT = 0, /* Do nothing */
98  JUMP_LARGEST_VALUE_FIRST_SPLIT = 1,
99  JUMP_SMALLEST_VALUE_FIRST_SPLIT = 2,
100 } GncPrefJumpMultSplits;
101 
102 /* This static indicates the debugging module that this .o belongs to. */
103 static QofLogModule log_module = GNC_MOD_GUI;
104 
105 #define DEFAULT_LINES_AMOUNT 50
106 
107 static void gnc_plugin_page_register_finalize (GObject* object);
108 
109 /* static Account *gnc_plugin_page_register_get_current_account (GncPluginPageRegister *page); */
110 
111 static GtkWidget* gnc_plugin_page_register_create_widget (GncPluginPage*
112  plugin_page);
113 static void gnc_plugin_page_register_destroy_widget (GncPluginPage*
114  plugin_page);
115 static void gnc_plugin_page_register_window_changed (GncPluginPage*
116  plugin_page, GtkWidget* window);
117 static gboolean gnc_plugin_page_register_focus_widget (GncPluginPage*
118  plugin_page);
119 static void gnc_plugin_page_register_focus (GncPluginPage* plugin_page,
120  gboolean current_page);
121 static void gnc_plugin_page_register_save_page (GncPluginPage* plugin_page,
122  GKeyFile* file, const gchar* group);
123 static GncPluginPage* gnc_plugin_page_register_recreate_page (GtkWidget* window,
124  GKeyFile* file,
125  const gchar* group);
126 static void gnc_plugin_page_register_update_edit_menu (GncPluginPage* plugin_page,
127  gboolean hide);
128 static gboolean gnc_plugin_page_register_finish_pending (GncPluginPage* plugin_page);
129 
130 static gchar* gnc_plugin_page_register_get_tab_name (GncPluginPage*
131  plugin_page);
132 static gchar* gnc_plugin_page_register_get_tab_color (GncPluginPage*
133  plugin_page);
134 static gchar* gnc_plugin_page_register_get_long_name (GncPluginPage*
135  plugin_page);
136 
137 static void gnc_plugin_page_register_summarybar_position_changed (gpointer prefs,
138  gchar* pref,
139  gpointer user_data);
140 
141 /* Command callbacks */
142 static void gnc_plugin_page_register_cmd_print_check (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
143 static void gnc_plugin_page_register_cmd_cut (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
144 static void gnc_plugin_page_register_cmd_copy (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
145 static void gnc_plugin_page_register_cmd_paste (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
146 static void gnc_plugin_page_register_cmd_edit_account (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
147 static void gnc_plugin_page_register_cmd_find_account (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
148 static void gnc_plugin_page_register_cmd_find_transactions (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
149 static void gnc_plugin_page_register_cmd_edit_tax_options (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
150 static void gnc_plugin_page_register_cmd_cut_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
151 static void gnc_plugin_page_register_cmd_copy_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
152 static void gnc_plugin_page_register_cmd_paste_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
153 static void gnc_plugin_page_register_cmd_void_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
154 static void gnc_plugin_page_register_cmd_unvoid_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
155 static void gnc_plugin_page_register_cmd_reverse_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
156 static void gnc_plugin_page_register_cmd_view_sort_by (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
157 static void gnc_plugin_page_register_cmd_view_filter_by (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
158 
159 static void gnc_plugin_page_register_cmd_style_changed (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
160 static void gnc_plugin_page_register_cmd_style_double_line (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
161 static void gnc_plugin_page_register_cmd_expand_transaction (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
162 
163 static void gnc_plugin_page_register_cmd_reconcile (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
164 static void gnc_plugin_page_register_cmd_stock_assistant (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
165 static void gnc_plugin_page_register_cmd_autoclear (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
166 static void gnc_plugin_page_register_cmd_transfer (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
167 static void gnc_plugin_page_register_cmd_stock_split (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
168 static void gnc_plugin_page_register_cmd_lots (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
169 static void gnc_plugin_page_register_cmd_enter_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
170 static void gnc_plugin_page_register_cmd_cancel_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
171 static void gnc_plugin_page_register_cmd_delete_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
172 static void gnc_plugin_page_register_cmd_blank_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
173 static void gnc_plugin_page_register_cmd_goto_date (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
174 static void gnc_plugin_page_register_cmd_duplicate_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
175 static void gnc_plugin_page_register_cmd_reinitialize_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
176 static void gnc_plugin_page_register_cmd_exchange_rate (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
177 static void gnc_plugin_page_register_cmd_jump (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
178 static void gnc_plugin_page_register_cmd_reload (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
179 static void gnc_plugin_page_register_cmd_schedule (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
180 static void gnc_plugin_page_register_cmd_scrub_all (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
181 static void gnc_plugin_page_register_cmd_scrub_current (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
182 static void gnc_plugin_page_register_cmd_account_report (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
183 static void gnc_plugin_page_register_cmd_transaction_report (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
184 static void gnc_plugin_page_register_cmd_linked_transaction (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
185 static void gnc_plugin_page_register_cmd_linked_transaction_open (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
186 static void gnc_plugin_page_register_cmd_jump_linked_invoice (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
187 
188 static void gnc_plugin_page_help_changed_cb (GNCSplitReg* gsr,
189  GncPluginPageRegister* page);
190 static void gnc_plugin_page_popup_menu_cb (GNCSplitReg* gsr,
191  GncPluginPageRegister* page);
192 static void gnc_plugin_page_register_refresh_cb (GHashTable* changes,
193  gpointer user_data);
194 static void gnc_plugin_page_register_close_cb (gpointer user_data);
195 
196 static void gnc_plugin_page_register_ui_update (gpointer various,
197  GncPluginPageRegister* page);
198 static void gppr_account_destroy_cb (Account* account);
199 static void gnc_plugin_page_register_event_handler (QofInstance* entity,
200  QofEventId event_type,
201  GncPluginPageRegister* page,
202  GncEventData* ed);
203 
204 static GncInvoice* invoice_from_split (Split* split);
205 
206 /************************************************************/
207 /* Actions */
208 /************************************************************/
209 
210 #define CUT_TRANSACTION_LABEL N_("Cu_t Transaction")
211 #define COPY_TRANSACTION_LABEL N_("_Copy Transaction")
212 #define PASTE_TRANSACTION_LABEL N_("_Paste Transaction")
213 #define DUPLICATE_TRANSACTION_LABEL N_("Dup_licate Transaction")
214 #define DELETE_TRANSACTION_LABEL N_("_Delete Transaction")
215 /* Translators: This is a menu item that opens a dialog for linking an
216  external file or URL with the bill, invoice, transaction, or voucher or
217  removing such an link. */
218 #define LINK_TRANSACTION_LABEL N_("_Manage Document Link…")
219 /* Translators: This is a menu item that opens an external file or URI that may
220  be linked to the current bill, invoice, transaction, or voucher using
221  the operating system's default application for the file or URI mime type. */
222 #define LINK_TRANSACTION_OPEN_LABEL N_("_Open Linked Document")
223 /* Translators: This is a menu item that will open the bill, invoice, or voucher
224  that is posted to the current transaction if there is one. */
225 #define JUMP_LINKED_INVOICE_LABEL N_("Jump to Business item")
226 #define CUT_SPLIT_LABEL N_("Cu_t Split")
227 #define COPY_SPLIT_LABEL N_("_Copy Split")
228 #define PASTE_SPLIT_LABEL N_("_Paste Split")
229 #define DUPLICATE_SPLIT_LABEL N_("Dup_licate Split")
230 #define DELETE_SPLIT_LABEL N_("_Delete Split")
231 #define CUT_TRANSACTION_TIP N_("Cut the selected transaction into clipboard")
232 #define COPY_TRANSACTION_TIP N_("Copy the selected transaction into clipboard")
233 #define PASTE_TRANSACTION_TIP N_("Paste the transaction from the clipboard")
234 #define DUPLICATE_TRANSACTION_TIP N_("Make a copy of the current transaction")
235 #define DELETE_TRANSACTION_TIP N_("Delete the current transaction")
236 #define LINK_TRANSACTION_TIP N_("Add, change, or unlink the document linked with the current transaction")
237 #define LINK_TRANSACTION_OPEN_TIP N_("Open the linked document for the current transaction")
238 #define JUMP_LINKED_INVOICE_TIP N_("Jump to the linked invoice, bill, expense or credit note")
239 #define CUT_SPLIT_TIP N_("Cut the selected split into clipboard")
240 #define COPY_SPLIT_TIP N_("Copy the selected split into clipboard")
241 #define PASTE_SPLIT_TIP N_("Paste the split from the clipboard")
242 #define DUPLICATE_SPLIT_TIP N_("Make a copy of the current split")
243 #define DELETE_SPLIT_TIP N_("Delete the current split")
244 
245 static GActionEntry gnc_plugin_page_register_actions [] =
246 {
247  { "FilePrintAction", gnc_plugin_page_register_cmd_print_check, NULL, NULL, NULL },
248  { "EditCutAction", gnc_plugin_page_register_cmd_cut, NULL, NULL, NULL },
249  { "EditCopyAction", gnc_plugin_page_register_cmd_copy, NULL, NULL, NULL },
250  { "EditPasteAction", gnc_plugin_page_register_cmd_paste, NULL, NULL, NULL },
251  { "EditEditAccountAction", gnc_plugin_page_register_cmd_edit_account, NULL, NULL, NULL },
252  { "EditFindAccountAction", gnc_plugin_page_register_cmd_find_account, NULL, NULL, NULL },
253  { "EditFindTransactionsAction", gnc_plugin_page_register_cmd_find_transactions, NULL, NULL, NULL },
254  { "EditTaxOptionsAction", gnc_plugin_page_register_cmd_edit_tax_options, NULL, NULL, NULL },
255  { "CutTransactionAction", gnc_plugin_page_register_cmd_cut_transaction, NULL, NULL, NULL },
256  { "CopyTransactionAction", gnc_plugin_page_register_cmd_copy_transaction, NULL, NULL, NULL },
257  { "PasteTransactionAction", gnc_plugin_page_register_cmd_paste_transaction, NULL, NULL, NULL },
258  { "DuplicateTransactionAction", gnc_plugin_page_register_cmd_duplicate_transaction, NULL, NULL, NULL },
259  { "DeleteTransactionAction", gnc_plugin_page_register_cmd_delete_transaction, NULL, NULL, NULL },
260  { "RemoveTransactionSplitsAction", gnc_plugin_page_register_cmd_reinitialize_transaction, NULL, NULL, NULL },
261  { "RecordTransactionAction", gnc_plugin_page_register_cmd_enter_transaction, NULL, NULL, NULL },
262  { "CancelTransactionAction", gnc_plugin_page_register_cmd_cancel_transaction, NULL, NULL, NULL },
263  { "VoidTransactionAction", gnc_plugin_page_register_cmd_void_transaction, NULL, NULL, NULL },
264  { "UnvoidTransactionAction", gnc_plugin_page_register_cmd_unvoid_transaction, NULL, NULL, NULL },
265  { "ReverseTransactionAction", gnc_plugin_page_register_cmd_reverse_transaction, NULL, NULL, NULL },
266  { "LinkTransactionAction", gnc_plugin_page_register_cmd_linked_transaction, NULL, NULL, NULL },
267  { "LinkedTransactionOpenAction", gnc_plugin_page_register_cmd_linked_transaction_open, NULL, NULL, NULL },
268  { "JumpLinkedInvoiceAction", gnc_plugin_page_register_cmd_jump_linked_invoice, NULL, NULL, NULL },
269  { "ViewSortByAction", gnc_plugin_page_register_cmd_view_sort_by, NULL, NULL, NULL },
270  { "ViewFilterByAction", gnc_plugin_page_register_cmd_view_filter_by, NULL, NULL, NULL },
271  { "ViewRefreshAction", gnc_plugin_page_register_cmd_reload, NULL, NULL, NULL },
272  { "ActionsTransferAction", gnc_plugin_page_register_cmd_transfer, NULL, NULL, NULL },
273  { "ActionsReconcileAction", gnc_plugin_page_register_cmd_reconcile, NULL, NULL, NULL },
274  { "ActionsAutoClearAction", gnc_plugin_page_register_cmd_autoclear, NULL, NULL, NULL },
275  { "ActionsStockAssistantAction", gnc_plugin_page_register_cmd_stock_assistant, NULL, NULL, NULL },
276  { "ActionsStockSplitAction", gnc_plugin_page_register_cmd_stock_split, NULL, NULL, NULL },
277  { "ActionsLotsAction", gnc_plugin_page_register_cmd_lots, NULL, NULL, NULL },
278  { "BlankTransactionAction", gnc_plugin_page_register_cmd_blank_transaction, NULL, NULL, NULL },
279  { "GotoDateAction", gnc_plugin_page_register_cmd_goto_date, NULL, NULL, NULL },
280  { "EditExchangeRateAction", gnc_plugin_page_register_cmd_exchange_rate, NULL, NULL, NULL },
281  { "JumpTransactionAction", gnc_plugin_page_register_cmd_jump, NULL, NULL, NULL },
282  { "ScheduleTransactionAction", gnc_plugin_page_register_cmd_schedule, NULL, NULL, NULL },
283  { "ScrubAllAction", gnc_plugin_page_register_cmd_scrub_all, NULL, NULL, NULL },
284  { "ScrubCurrentAction", gnc_plugin_page_register_cmd_scrub_current, NULL, NULL, NULL },
285  { "ReportsAccountReportAction", gnc_plugin_page_register_cmd_account_report, NULL, NULL, NULL },
286  { "ReportsAcctTransReportAction", gnc_plugin_page_register_cmd_transaction_report, NULL, NULL, NULL },
287 
288  { "ViewStyleDoubleLineAction", gnc_plugin_page_register_cmd_style_double_line, NULL, "false", NULL },
289  { "SplitTransactionAction", gnc_plugin_page_register_cmd_expand_transaction, NULL, "false", NULL },
290  { "ViewStyleRadioAction", gnc_plugin_page_register_cmd_style_changed, "i", "@i 0", NULL },
291 };
292 static guint gnc_plugin_page_register_n_actions = G_N_ELEMENTS(gnc_plugin_page_register_actions);
293 
295 static const gchar *gnc_plugin_load_ui_items [] =
296 {
297  "FilePlaceholder3",
298  "EditPlaceholder1",
299  "EditPlaceholder2",
300  "EditPlaceholder3",
301  "EditPlaceholder5",
302  "ViewPlaceholder1",
303  "ViewPlaceholder2",
304  "ViewPlaceholder3",
305  "ViewPlaceholder4",
306  "TransPlaceholder0",
307  "TransPlaceholder1",
308  "TransPlaceholder2",
309  "TransPlaceholder3",
310  "TransPlaceholder4",
311  "ActionsPlaceholder4",
312  "ActionsPlaceholder5",
313  "ActionsPlaceholder6",
314  "ReportsPlaceholder1",
315  NULL,
316 };
317 
320 static const gchar* actions_requiring_account[] =
321 {
322  "EditEditAccountAction",
323  "ActionsReconcileAction",
324  "ActionsAutoClearAction",
325  "ActionsLotsAction",
326  NULL
327 };
328 
329 static const gchar* actions_requiring_priced_account[] =
330 {
331  "ActionsStockAssistantAction",
332  NULL
333 };
334 
336 static GncToolBarShortNames toolbar_labels[] =
337 {
338  { "ActionsTransferAction", N_ ("Transfer") },
339  { "RecordTransactionAction", N_ ("Enter") },
340  { "CancelTransactionAction", N_ ("Cancel") },
341  { "DeleteTransactionAction", N_ ("Delete") },
342  { "DuplicateTransactionAction", N_ ("Duplicate") },
343  { "SplitTransactionAction",
344  /* Translators: This is the label of a toolbar button. So keep it short. */
345  N_ ("Show Splits") },
346  { "JumpTransactionAction", N_ ("Jump") },
347  { "ScheduleTransactionAction", N_ ("Schedule") },
348  { "BlankTransactionAction", N_ ("Blank") },
349  { "ActionsReconcileAction", N_ ("Reconcile") },
350  { "ActionsStockAssistantAction", N_ ("Stock Assistant") },
351  { NULL, NULL },
352 };
353 
354 /************************************************************/
355 /* Data Structures */
356 /************************************************************/
357 
359 {
360  GNCLedgerDisplay* ledger;
361  GNCSplitReg* gsr;
362 
363  GtkWidget* widget;
364 
365  gint event_handler_id;
366  gint component_manager_id;
367  GncGUID key; /* The guid of the Account we're watching */
368 
369  gint lines_default;
370  gboolean read_only;
371  gboolean page_focus;
372  gboolean enable_refresh; // used to reduce ledger display refreshes
373  Query* search_query; // saved search query for comparison
374  Query* filter_query; // saved filter query for comparison
375 
376  SortData sd;
377  FilterData fd;
378 
380 
381 G_DEFINE_TYPE_WITH_PRIVATE (GncPluginPageRegister, gnc_plugin_page_register,
382  GNC_TYPE_PLUGIN_PAGE)
383 
384 #define GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(o) \
385  ((GncPluginPageRegisterPrivate*)gnc_plugin_page_register_get_instance_private((GncPluginPageRegister*)o))
386 
387 /************************************************************/
388 /* Implementation */
389 /************************************************************/
390 
391 static GncPluginPage*
392 gnc_plugin_page_register_new_common (GNCLedgerDisplay* ledger)
393 {
394  GncPluginPageRegister* page;
396  GncPluginPage* plugin_page;
397  GNCSplitReg* gsr;
398  const GList* item;
399  GList* book_list;
400  gchar* label;
401  gchar* label_color;
402  QofQuery* q;
403 
404  // added for version 4.0 onwards
405  if (!gnc_features_check_used (gnc_get_current_book(), GNC_FEATURE_REG_SORT_FILTER))
406  gnc_features_set_used (gnc_get_current_book(), GNC_FEATURE_REG_SORT_FILTER);
407 
408  // added for version 4.14 onwards
409  if (!gnc_using_equity_type_opening_balance_account (gnc_get_current_book()))
410  gnc_set_use_equity_type_opening_balance_account (gnc_get_current_book());
411 
412  /* Is there an existing page? */
413  gsr = GNC_SPLIT_REG(gnc_ledger_display_get_user_data (ledger));
414  if (gsr)
415  {
416  item = gnc_gobject_tracking_get_list (GNC_PLUGIN_PAGE_REGISTER_NAME);
417  for (; item; item = g_list_next (item))
418  {
419  page = (GncPluginPageRegister*)item->data;
420  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
421  if (priv->gsr == gsr)
422  return GNC_PLUGIN_PAGE (page);
423  }
424  }
425 
426  page = GNC_PLUGIN_PAGE_REGISTER(g_object_new (GNC_TYPE_PLUGIN_PAGE_REGISTER, nullptr));
427  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
428  priv->ledger = ledger;
429  priv->key = *guid_null();
430 
431  plugin_page = GNC_PLUGIN_PAGE (page);
432  label = gnc_plugin_page_register_get_tab_name (plugin_page);
433  gnc_plugin_page_set_page_name (plugin_page, label);
434  g_free (label);
435 
436  label_color = gnc_plugin_page_register_get_tab_color (plugin_page);
437  gnc_plugin_page_set_page_color (plugin_page, label_color);
438  g_free (label_color);
439 
440  label = gnc_plugin_page_register_get_long_name (plugin_page);
441  gnc_plugin_page_set_page_long_name (plugin_page, label);
442  g_free (label);
443 
444  q = gnc_ledger_display_get_query (ledger);
445  book_list = qof_query_get_books (q);
446  for (item = book_list; item; item = g_list_next (item))
447  gnc_plugin_page_add_book (plugin_page, (QofBook*)item->data);
448  // Do not free the list. It is owned by the query.
449 
450  priv->component_manager_id = 0;
451  return plugin_page;
452 }
453 
454 static gpointer
455 gnc_plug_page_register_check_commodity (Account* account, void* usr_data)
456 {
457  // Check that account's commodity matches the commodity in usr_data
458  gnc_commodity* com0 = (gnc_commodity*) usr_data;
459  gnc_commodity* com1 = xaccAccountGetCommodity (account);
460  return gnc_commodity_equal (com1, com0) ? NULL : com1;
461 }
462 
464 gnc_plugin_page_register_new (Account* account, gboolean subaccounts)
465 {
466  GNCLedgerDisplay* ledger;
467  GncPluginPage* plugin_page;
469  gnc_commodity* com0;
470  gnc_commodity* com1;
471 
472  ENTER ("account=%p, subaccounts=%s", account,
473  subaccounts ? "TRUE" : "FALSE");
474 
475  com0 = gnc_account_get_currency_or_parent (account);
476  com1 = GNC_COMMODITY(gnc_account_foreach_descendant_until (account,
477  gnc_plug_page_register_check_commodity,
478  static_cast<gpointer>(com0)));
479 
480  if (subaccounts)
481  ledger = gnc_ledger_display_subaccounts (account, com1 != NULL);
482  else
483  ledger = gnc_ledger_display_simple (account);
484 
485  plugin_page = gnc_plugin_page_register_new_common (ledger);
486  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
487  priv->key = *xaccAccountGetGUID (account);
488 
489  LEAVE ("%p", plugin_page);
490  return plugin_page;
491 }
492 
495 {
496  GNCLedgerDisplay* ledger;
497 
498  ledger = gnc_ledger_display_gl();
499  return gnc_plugin_page_register_new_common (ledger);
500 }
501 
503 gnc_plugin_page_register_new_ledger (GNCLedgerDisplay* ledger)
504 {
505  return gnc_plugin_page_register_new_common (ledger);
506 }
507 
508 static void
509 gnc_plugin_page_register_class_init (GncPluginPageRegisterClass* klass)
510 {
511  GObjectClass* object_class = G_OBJECT_CLASS (klass);
512  GncPluginPageClass* gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS (klass);
513 
514  object_class->finalize = gnc_plugin_page_register_finalize;
515 
516  gnc_plugin_class->tab_icon = GNC_ICON_ACCOUNT;
517  gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_REGISTER_NAME;
518  gnc_plugin_class->create_widget = gnc_plugin_page_register_create_widget;
519  gnc_plugin_class->destroy_widget = gnc_plugin_page_register_destroy_widget;
520  gnc_plugin_class->window_changed = gnc_plugin_page_register_window_changed;
521  gnc_plugin_class->focus_page = gnc_plugin_page_register_focus;
522  gnc_plugin_class->save_page = gnc_plugin_page_register_save_page;
523  gnc_plugin_class->recreate_page = gnc_plugin_page_register_recreate_page;
524  gnc_plugin_class->update_edit_menu_actions = gnc_plugin_page_register_update_edit_menu;
525  gnc_plugin_class->finish_pending = gnc_plugin_page_register_finish_pending;
526  gnc_plugin_class->focus_page_function = gnc_plugin_page_register_focus_widget;
527 
528  gnc_ui_register_account_destroy_callback (gppr_account_destroy_cb);
529 }
530 
531 static void
532 gnc_plugin_page_register_init (GncPluginPageRegister* page)
533 {
535  GncPluginPage* plugin_page;
536  GSimpleActionGroup *simple_action_group;
537  gboolean use_new;
538 
539  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
540 
541  /* Init parent declared variables */
542  plugin_page = GNC_PLUGIN_PAGE (page);
543  use_new = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
544  GNC_PREF_USE_NEW);
545  g_object_set (G_OBJECT (page),
546  "page-name", _ ("General Journal"),
547  "ui-description", "gnc-plugin-page-register.ui",
548  "use-new-window", use_new,
549  NULL);
550 
551  /* Create menu and toolbar information */
552  simple_action_group = gnc_plugin_page_create_action_group (plugin_page,
553  "GncPluginPageRegisterActions");
554  g_action_map_add_action_entries (G_ACTION_MAP(simple_action_group),
555  gnc_plugin_page_register_actions,
556  gnc_plugin_page_register_n_actions,
557  page);
558 
559  priv->lines_default = DEFAULT_LINES_AMOUNT;
560  priv->read_only = FALSE;
561  priv->fd.cleared_match = CLEARED_ALL;
562  priv->fd.days = 0;
563  priv->enable_refresh = TRUE;
564  priv->search_query = NULL;
565  priv->filter_query = NULL;
566 }
567 
568 static void
569 gnc_plugin_page_register_finalize (GObject* object)
570 {
571  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (object));
572 
573  ENTER ("object %p", object);
574 
575  G_OBJECT_CLASS (gnc_plugin_page_register_parent_class)->finalize (object);
576  LEAVE (" ");
577 }
578 
579 Account*
581 {
583  GNCLedgerDisplayType ledger_type;
584  Account* leader;
585 
586  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
587  ledger_type = gnc_ledger_display_type (priv->ledger);
588  leader = gnc_ledger_display_leader (priv->ledger);
589 
590  if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
591  return leader;
592  return NULL;
593 }
594 
595 Transaction*
597 {
599  SplitRegister* reg;
600 
601  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
602  reg = gnc_ledger_display_get_split_register (priv->ledger);
604 }
605 
610 static gboolean
611 gnc_plugin_page_register_focus_widget (GncPluginPage* plugin_page)
612 {
613  if (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page))
614  {
615  GncWindow* gnc_window = GNC_WINDOW(GNC_PLUGIN_PAGE(plugin_page)->window);
616  GNCSplitReg *gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE(plugin_page));
617 
618  if (GNC_IS_MAIN_WINDOW(GNC_PLUGIN_PAGE(plugin_page)->window))
619  {
620  /* Enable the Transaction menu */
621  GAction *action = gnc_main_window_find_action (GNC_MAIN_WINDOW(plugin_page->window), "TransactionAction");
622  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), TRUE);
623  /* Disable the Schedule menu */
624  action = gnc_main_window_find_action (GNC_MAIN_WINDOW(plugin_page->window), "ScheduledAction");
625  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
626 
627  gnc_main_window_update_menu_and_toolbar (GNC_MAIN_WINDOW(plugin_page->window),
628  plugin_page,
629  gnc_plugin_load_ui_items);
630  }
631  else
632  {
633  GtkWidget *toolbar = gnc_window_get_toolbar (gnc_window);
634  GtkWidget *menubar = gnc_window_get_menubar (gnc_window);
635  GMenuModel *menubar_model = gnc_window_get_menubar_model (gnc_window);
636  GtkWidget *statusbar = gnc_window_get_statusbar (gnc_window);
637 
638  // add tooltip redirect call backs
639  gnc_plugin_add_toolbar_tooltip_callbacks (toolbar, statusbar);
640  gnc_plugin_add_menu_tooltip_callbacks (menubar, menubar_model, statusbar);
641  }
642 
643  // setup any short toolbar names
644  gnc_plugin_init_short_names (gnc_window_get_toolbar (gnc_window), toolbar_labels);
645 
646  gnc_plugin_page_register_ui_update (NULL, GNC_PLUGIN_PAGE_REGISTER(plugin_page));
647 
648  gnc_split_reg_focus_on_sheet (gsr);
649  }
650  return FALSE;
651 }
652 
653 /* This is the list of actions which are switched inactive in a read-only book. */
654 static const char* readonly_inactive_actions[] =
655 {
656  "EditCutAction",
657  "EditPasteAction",
658  "CutTransactionAction",
659  "PasteTransactionAction",
660  "DuplicateTransactionAction",
661  "DeleteTransactionAction",
662  "RemoveTransactionSplitsAction",
663  "RecordTransactionAction",
664  "CancelTransactionAction",
665  "UnvoidTransactionAction",
666  "VoidTransactionAction",
667  "ReverseTransactionAction",
668  "ActionsTransferAction",
669  "ActionsReconcileAction",
670  "ActionsStockSplitAction",
671  "ScheduleTransactionAction",
672  "ScrubAllAction",
673  "ScrubCurrentAction",
674  "LinkTransactionAction",
675  NULL
676 };
677 
678 /* This is the list of actions whose text needs to be changed based on whether */
679 /* the current cursor class is transaction or split. */
680 static const char* tran_vs_split_actions[] =
681 {
682  "CutTransactionAction",
683  "CopyTransactionAction",
684  "PasteTransactionAction",
685  "DuplicateTransactionAction",
686  "DeleteTransactionAction",
687  NULL
688 };
689 
690 /* This is the list of labels for when the current cursor class is transaction. */
691 static const char* tran_action_labels[] =
692 {
693  CUT_TRANSACTION_LABEL,
694  COPY_TRANSACTION_LABEL,
695  PASTE_TRANSACTION_LABEL,
696  DUPLICATE_TRANSACTION_LABEL,
697  DELETE_TRANSACTION_LABEL,
698  NULL
699 };
700 
701 /* This is the list of tooltips for when the current cursor class is transaction. */
702 static const char* tran_action_tips[] =
703 {
704  CUT_TRANSACTION_TIP,
705  COPY_TRANSACTION_TIP,
706  PASTE_TRANSACTION_TIP,
707  DUPLICATE_TRANSACTION_TIP,
708  DELETE_TRANSACTION_TIP,
709  NULL
710 };
711 
712 /* This is the list of labels for when the current cursor class is split. */
713 static const char* split_action_labels[] =
714 {
715  CUT_SPLIT_LABEL,
716  COPY_SPLIT_LABEL,
717  PASTE_SPLIT_LABEL,
718  DUPLICATE_SPLIT_LABEL,
719  DELETE_SPLIT_LABEL,
720  NULL
721 };
722 
723 /* This is the list of tooltips for when the current cursor class is split. */
724 static const char* split_action_tips[] =
725 {
726  CUT_SPLIT_TIP,
727  COPY_SPLIT_TIP,
728  PASTE_SPLIT_TIP,
729  DUPLICATE_SPLIT_TIP,
730  DELETE_SPLIT_TIP,
731  NULL
732 };
733 
734 static std::vector<GncInvoice*>
735 invoices_from_transaction (const Transaction* trans)
736 {
737  std::vector<GncInvoice*> rv;
738 
739  g_return_val_if_fail (GNC_IS_TRANSACTION (trans), rv);
740 
741  for (auto node = xaccTransGetSplitList (trans); node; node = g_list_next (node))
742  {
743  auto split = GNC_SPLIT(node->data);
744  auto account = xaccSplitGetAccount (split);
745  if (!account || !xaccAccountIsAPARType(xaccAccountGetType(account)))
746  continue;
747  auto inv = invoice_from_split (split);
748  if (inv)
749  rv.push_back (inv);
750  }
751  return rv;
752 }
753 
754 static void
755 gnc_plugin_page_register_ui_update (gpointer various,
756  GncPluginPageRegister* page)
757 {
759  SplitRegister* reg;
760  GAction* action;
761  GNCLedgerDisplayType ledger_type;
762  gboolean expanded, voided, read_only = FALSE, read_only_reg = FALSE;
763  Transaction* trans;
764  CursorClass cursor_class;
765  const char* uri;
766  Account *account;
767  GncWindow* gnc_window = GNC_WINDOW(GNC_PLUGIN_PAGE(page)->window);
768 
769  /* Set 'Split Transaction' */
770  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
771  reg = gnc_ledger_display_get_split_register (priv->ledger);
772  cursor_class = gnc_split_register_get_current_cursor_class (reg);
774 
775  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "SplitTransactionAction");
776  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), reg->style == REG_STYLE_LEDGER);
777 
778  /* Set "style" radio button */
779  ledger_type = gnc_ledger_display_type (priv->ledger);
780  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "ViewStyleRadioAction");
781 
782  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), ledger_type != LD_GL);
783  g_action_change_state (G_ACTION(action), g_variant_new_int32 (reg->style));
784 
785  /* Set double line */
786  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "ViewStyleDoubleLineAction");
787  g_action_change_state (G_ACTION(action), g_variant_new_boolean (reg->use_double_line));
788 
789  /* Split Expand */
790  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "SplitTransactionAction");
791  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), reg->style == REG_STYLE_LEDGER);
792 
793  g_signal_handlers_block_by_func (action, (gpointer)gnc_plugin_page_register_cmd_expand_transaction, page);
794  g_action_change_state (G_ACTION(action), g_variant_new_boolean (expanded));
795  g_signal_handlers_unblock_by_func (action, (gpointer)gnc_plugin_page_register_cmd_expand_transaction, page);
796 
797  account = gnc_plugin_page_register_get_account (page);
798 
799  /* Done like this as the register can be displayed in embedded window */
800  if (GNC_IS_MAIN_WINDOW(GNC_PLUGIN_PAGE(page)->window))
801  {
802  /* Enable the FilePrintAction */
803  action = gnc_main_window_find_action (GNC_MAIN_WINDOW(GNC_PLUGIN_PAGE(page)->window), "FilePrintAction");
804  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), TRUE);
805 
806  /* Set the vis of the StockAssistant */
807  gnc_main_window_set_vis_of_items_by_action (GNC_MAIN_WINDOW(GNC_PLUGIN_PAGE(page)->window),
808  actions_requiring_priced_account,
809  account &&
810  xaccAccountIsPriced (account));
811  }
812 
813  /* If we are in a readonly book, or possibly a place holder
814  * account register make any modifying action inactive */
815  if (qof_book_is_readonly (gnc_get_current_book()) ||
816  gnc_split_reg_get_read_only (priv->gsr))
817  read_only_reg = TRUE;
818 
819  gnc_plugin_set_actions_enabled (G_ACTION_MAP(gnc_plugin_page_get_action_group (GNC_PLUGIN_PAGE(page))),
820  actions_requiring_account,
821  !read_only_reg && account != NULL);
822 
823  gnc_plugin_set_actions_enabled (G_ACTION_MAP(gnc_plugin_page_get_action_group (GNC_PLUGIN_PAGE(page))),
824  actions_requiring_priced_account,
825  account && xaccAccountIsPriced (account));
826 
827  /* Set available actions based on read only */
829 
830  if (cursor_class == CURSOR_CLASS_SPLIT)
831  {
832  if (GNC_IS_MAIN_WINDOW(GNC_PLUGIN_PAGE(page)->window))
833  gnc_plugin_page_set_menu_popup_qualifier (GNC_PLUGIN_PAGE(page), "split");
834  else
835  gnc_plugin_page_set_menu_popup_qualifier (GNC_PLUGIN_PAGE(page), "split-sx");
836  }
837  else
838  {
839  if (GNC_IS_MAIN_WINDOW(GNC_PLUGIN_PAGE(page)->window))
840  gnc_plugin_page_set_menu_popup_qualifier (GNC_PLUGIN_PAGE(page), "trans");
841  else
842  gnc_plugin_page_set_menu_popup_qualifier (GNC_PLUGIN_PAGE(page), "trans-sx");
843  }
844 
845  /* If the register is not read only, make any modifying action active
846  * to start with */
847  if (!read_only_reg)
848  {
849  const char** iter;
850  for (iter = readonly_inactive_actions; *iter; ++iter)
851  {
852  /* Set the action's sensitivity */
853  GAction* action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), *iter);
854  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), TRUE);
855  }
856  main_window_update_page_set_read_only_icon (GNC_PLUGIN_PAGE(page), FALSE);
857 
858  if (trans)
859  read_only = xaccTransIsReadonlyByPostedDate (trans);
860 
861  voided = xaccTransHasSplitsInState (trans, VREC);
862 
863  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
864  "CutTransactionAction");
865  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !read_only & !voided);
866 
867  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
868  "PasteTransactionAction");
869  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !read_only & !voided);
870 
871  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
872  "DeleteTransactionAction");
873  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !read_only & !voided);
874 
875  if (cursor_class == CURSOR_CLASS_SPLIT)
876  {
877  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
878  "DuplicateTransactionAction");
879  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !read_only & !voided);
880  }
881 
882  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
883  "RemoveTransactionSplitsAction");
884  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !read_only & !voided);
885 
886  /* Set 'Void' and 'Unvoid' */
887  if (read_only)
888  voided = TRUE;
889 
890  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
891  "VoidTransactionAction");
892  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !voided);
893 
894  if (read_only)
895  voided = FALSE;
896 
897  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
898  "UnvoidTransactionAction");
899  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), voided);
900  }
901 
902  /* Set 'Open and Remove Linked Documents' */
903  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
904  "LinkedTransactionOpenAction");
905  if (trans)
906  {
907  uri = xaccTransGetDocLink (trans);
908  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), (uri ? TRUE:FALSE));
909  }
910  /* Set 'ExecAssociatedInvoice'
911  We can determine an invoice from a txn if either
912  - it is an invoice transaction
913  - it has splits with an invoice associated with it
914  */
915  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
916  "JumpLinkedInvoiceAction");
917  if (trans)
918  {
919  auto invoices = invoices_from_transaction (trans);
920  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), !invoices.empty());
921  }
922 
923  gnc_plugin_business_split_reg_ui_update (GNC_PLUGIN_PAGE(page));
924 
925  // Transaction/Split paste action
926  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
927  "PasteTransactionAction");
928  g_simple_action_set_enabled (G_SIMPLE_ACTION(action),
930 
931  /* If we are read only, make any modifying action inactive */
932  if (read_only_reg)
933  {
934  const char** iter;
935  for (iter = readonly_inactive_actions; *iter; ++iter)
936  {
937  /* Set the action's sensitivity */
938  GAction* action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), *iter);
939  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
940  }
941  main_window_update_page_set_read_only_icon (GNC_PLUGIN_PAGE(page), TRUE);
942  }
943 
944  /* Modifying action descriptions based on cursor class */
945  {
946  GncMenuModelSearch *gsm = g_new0 (GncMenuModelSearch, 1);
947  gboolean found = FALSE;
948  const char** iter, **label_iter, **tooltip_iter;
949  gboolean curr_label_trans = FALSE;
950  iter = tran_vs_split_actions;
951  label_iter = tran_action_labels;
952 
953  gsm->search_action_label = NULL;
954  gsm->search_action_name = *iter;
955  gsm->search_action_target = NULL;
956 
957  found = gnc_menubar_model_find_item (gnc_window_get_menubar_model (gnc_window), gsm);
958 
959  PINFO("Test for action '%s', found is %d, iter label is '%s'", *iter, found, _(*label_iter));
960 
961  if (!found)
962  {
963  g_free (gsm);
964  return;
965  }
966 
967  if (g_strcmp0 (gsm->search_action_label, _(*label_iter)) == 0)
968  curr_label_trans = TRUE;
969 
970  g_free (gsm);
971 
972  if ((cursor_class == CURSOR_CLASS_SPLIT) && curr_label_trans)
973  {
974  gboolean found = FALSE;
975  label_iter = split_action_labels;
976  tooltip_iter = split_action_tips;
977  for (iter = tran_vs_split_actions; *iter; ++iter)
978  {
979  /* Adjust the action's label and tooltip */
980  found = gnc_menubar_model_update_item (gnc_window_get_menubar_model (gnc_window),
981  *iter, NULL, _(*label_iter), NULL, _(*tooltip_iter));
982 
983  PINFO("split model_item action '%s', found is %d, iter label is '%s'",
984  *iter, found, _(*label_iter));
985 
986  ++label_iter;
987  ++tooltip_iter;
988  }
989  }
990  else if ((cursor_class == CURSOR_CLASS_TRANS) && !curr_label_trans)
991  {
992  gboolean found = FALSE;
993  label_iter = tran_action_labels;
994  tooltip_iter = tran_action_tips;
995  for (iter = tran_vs_split_actions; *iter; ++iter)
996  {
997  /* Adjust the action's label and tooltip */
998  found = gnc_menubar_model_update_item (gnc_window_get_menubar_model (gnc_window),
999  *iter, NULL, _(*label_iter), NULL, _(*tooltip_iter));
1000 
1001  PINFO("trans model_item action '%s', found is %d, iter label is '%s'",
1002  *iter, found, _(*label_iter));
1003 
1004  ++label_iter;
1005  ++tooltip_iter;
1006  }
1007  }
1008  // now add the callbacks to the replaced menu items.
1009  gnc_plugin_add_menu_tooltip_callbacks (gnc_window_get_menubar (gnc_window),
1010  gnc_window_get_menubar_model (gnc_window),
1011  gnc_window_get_statusbar (gnc_window));
1012 
1013  // need to add any accelerator keys, default or user added
1014  gnc_add_accelerator_keys_for_menu (gnc_window_get_menubar (gnc_window),
1015  gnc_window_get_menubar_model (gnc_window),
1016  gnc_window_get_accel_group (gnc_window));
1017  }
1018 }
1019 
1020 static void
1021 gnc_plugin_page_register_ui_initial_state (GncPluginPageRegister* page)
1022 {
1024  GSimpleActionGroup *simple_action_group;
1025  GAction *action;
1026  Account* account;
1027  SplitRegister* reg;
1028  GNCLedgerDisplayType ledger_type;
1029  gboolean is_readwrite = !qof_book_is_readonly (gnc_get_current_book());
1030 
1031  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1032  account = gnc_plugin_page_register_get_account (page);
1033 
1034  /* Get the action group */
1035  simple_action_group = gnc_plugin_page_get_action_group (GNC_PLUGIN_PAGE(page));
1036  g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP(simple_action_group));
1037 
1038  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), actions_requiring_account,
1039  is_readwrite && account != NULL);
1040 
1041  /* Set "style" radio button */
1042  ledger_type = gnc_ledger_display_type (priv->ledger);
1043  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "ViewStyleRadioAction");
1044  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), ledger_type == LD_SINGLE);
1045 
1046  reg = gnc_ledger_display_get_split_register (priv->ledger);
1047 
1048  g_signal_handlers_block_by_func (action,
1049  (gpointer)gnc_plugin_page_register_cmd_style_changed, page);
1050  g_action_change_state (G_ACTION(action), g_variant_new_int32 (reg->style));
1051  g_signal_handlers_unblock_by_func (action,
1052  (gpointer)gnc_plugin_page_register_cmd_style_changed, page);
1053 
1054  /* Set "double line" toggle button */
1055  action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "ViewStyleDoubleLineAction");
1056  g_signal_handlers_block_by_func (action,
1057  (gpointer)gnc_plugin_page_register_cmd_style_double_line, page);
1058  g_action_change_state (G_ACTION(action), g_variant_new_boolean (reg->use_double_line));
1059  g_signal_handlers_unblock_by_func (action,
1060  (gpointer)gnc_plugin_page_register_cmd_style_double_line, page);
1061 }
1062 
1063 /* For setting the focus on a register page, the default gnc_plugin
1064  * function for 'focus_page' is overridden so that the page focus
1065  * can be conditionally set. This is to allow for enabling the setting
1066  * of the sheet focus only when the page is the current one.
1067  */
1068 static void
1069 gnc_plugin_page_register_focus (GncPluginPage* plugin_page,
1070  gboolean on_current_page)
1071 {
1072  GncPluginPageRegister* page;
1074  GNCSplitReg* gsr;
1075  gboolean main_window_is_quitting = FALSE;
1076 
1077  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
1078 
1079  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1080  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1081 
1082  gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE (plugin_page));
1083 
1084  if (GNC_IS_MAIN_WINDOW(plugin_page->window))
1085  main_window_is_quitting = gnc_main_window_is_quitting (GNC_MAIN_WINDOW(plugin_page->window));
1086 
1087  if (on_current_page)
1088  {
1089  priv->page_focus = TRUE;
1090 
1091  // Chain up to use parent version of 'focus_page' which will
1092  // use an idle_add as the page changed signal is emitted multiple times.
1093  GNC_PLUGIN_PAGE_CLASS (gnc_plugin_page_register_parent_class)->focus_page (plugin_page, TRUE);
1094  }
1095  else
1096  priv->page_focus = FALSE;
1097 
1098  // set the sheet focus setting
1099  gnc_split_reg_set_sheet_focus (gsr, priv->page_focus);
1100 
1101  // No need to do a refresh on application closing
1102  if (on_current_page && !main_window_is_quitting)
1103  gnc_ledger_display_set_focus (priv->ledger, priv->page_focus);
1104 }
1105 
1106 static void
1107 gnc_ppr_update_filter_and_sort (GncPluginPage* plugin_page)
1108 {
1109  GncPluginPageRegister *page = GNC_PLUGIN_PAGE_REGISTER(plugin_page);
1110  GncPluginPageRegisterPrivate *priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
1111 
1112  ENTER("page %p", plugin_page);
1113 
1114  priv->enable_refresh = FALSE; // disable refresh
1115 
1116  // Load the saved register sort and filter properties
1117  gnc_ppr_sort_update_register (plugin_page);
1118  gnc_ppr_filter_update_register (plugin_page);
1119 
1120  priv->enable_refresh = TRUE; // enable refresh
1121 
1122  // Set filter tooltip for summary bar
1123  gnc_ppr_filter_set_tooltip (plugin_page, &priv->fd);
1124 }
1125 
1126 static GtkWidget*
1127 gnc_plugin_page_register_create_widget (GncPluginPage* plugin_page)
1128 {
1129  GncPluginPageRegister* page;
1131  GncWindow* gnc_window;
1132  guint numRows;
1133  GtkWidget* gsr;
1134  SplitRegister* reg;
1135  Account* acct;
1136 
1137  ENTER ("page %p", plugin_page);
1138  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1139  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1140 
1141  if (priv->widget != NULL)
1142  {
1143  LEAVE ("existing widget %p", priv->widget);
1144  return priv->widget;
1145  }
1146 
1147  priv->widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1148  gtk_box_set_homogeneous (GTK_BOX (priv->widget), FALSE);
1149  gtk_widget_show (priv->widget);
1150 
1151  // Set the name for this widget so it can be easily manipulated with css
1152  gtk_widget_set_name (GTK_WIDGET(priv->widget), "gnc-id-register-page");
1153 
1154  numRows = priv->lines_default;
1155  numRows = MIN (numRows, DEFAULT_LINES_AMOUNT);
1156 
1157  gnc_window = GNC_WINDOW(GNC_PLUGIN_PAGE(page)->window);
1158  gsr = gnc_split_reg_new (priv->ledger,
1159  gnc_window_get_gtk_window (gnc_window),
1160  numRows, priv->read_only);
1161  priv->gsr = (GNCSplitReg *)gsr;
1162  g_object_ref (gsr);
1163 
1164  gtk_widget_show (gsr);
1165  gtk_box_pack_start (GTK_BOX (priv->widget), gsr, TRUE, TRUE, 0);
1166 
1167  g_signal_connect (G_OBJECT (gsr), "help-changed",
1168  G_CALLBACK (gnc_plugin_page_help_changed_cb),
1169  page);
1170 
1171  g_signal_connect (G_OBJECT (gsr), "show-popup-menu",
1172  G_CALLBACK (gnc_plugin_page_popup_menu_cb),
1173  page);
1174 
1175  reg = gnc_ledger_display_get_split_register (priv->ledger);
1176  gnc_split_register_config (reg, reg->type, reg->style,
1177  reg->use_double_line);
1178 
1179  gnc_plugin_page_register_ui_initial_state (page);
1180  gnc_plugin_page_register_ui_update (NULL, page);
1181 
1182  // Now setup the sort and filter settings
1183  gnc_ppr_update_filter_and_sort (plugin_page);
1184 
1185  plugin_page->summarybar = gsr_create_summary_bar (priv->gsr);
1186  if (plugin_page->summarybar)
1187  {
1188  gtk_widget_show_all (plugin_page->summarybar);
1189  gtk_box_pack_start (GTK_BOX (priv->widget), plugin_page->summarybar,
1190  FALSE, FALSE, 0);
1191 
1192  gnc_plugin_page_register_summarybar_position_changed (NULL, NULL, page);
1193  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
1194  GNC_PREF_SUMMARYBAR_POSITION_TOP,
1195  (gpointer)gnc_plugin_page_register_summarybar_position_changed,
1196  page);
1197  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
1198  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
1199  (gpointer)gnc_plugin_page_register_summarybar_position_changed,
1200  page);
1201  }
1202 
1203  priv->event_handler_id = qof_event_register_handler
1204  ((QofEventHandler)gnc_plugin_page_register_event_handler, page);
1205  priv->component_manager_id =
1206  gnc_register_gui_component (GNC_PLUGIN_PAGE_REGISTER_NAME,
1207  gnc_plugin_page_register_refresh_cb,
1208  gnc_plugin_page_register_close_cb,
1209  page);
1210  gnc_gui_component_set_session (priv->component_manager_id,
1211  gnc_get_current_session());
1213  if (acct)
1214  gnc_gui_component_watch_entity (
1215  priv->component_manager_id, xaccAccountGetGUID (acct),
1216  QOF_EVENT_DESTROY | QOF_EVENT_MODIFY);
1217 
1218  gnc_split_reg_set_moved_cb
1219  (priv->gsr, (GFunc)gnc_plugin_page_register_ui_update, page);
1220 
1221  g_signal_connect (G_OBJECT (plugin_page), "inserted",
1222  G_CALLBACK (gnc_plugin_page_inserted_cb),
1223  NULL);
1224 
1225  /* DRH - Probably lots of other stuff from regWindowLedger should end up here. */
1226  LEAVE (" ");
1227  return priv->widget;
1228 }
1229 
1230 static void
1231 gnc_plugin_page_register_destroy_widget (GncPluginPage* plugin_page)
1232 {
1233  GncPluginPageRegister* page;
1235 
1236  ENTER ("page %p", plugin_page);
1237  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1238  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
1239 
1240  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
1241  GNC_PREF_SUMMARYBAR_POSITION_TOP,
1242  (gpointer)gnc_plugin_page_register_summarybar_position_changed,
1243  page);
1244  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
1245  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
1246  (gpointer)gnc_plugin_page_register_summarybar_position_changed,
1247  page);
1248 
1249  // Remove the page_changed signal callback
1250  gnc_plugin_page_disconnect_page_changed (GNC_PLUGIN_PAGE (plugin_page));
1251 
1252  // Remove the page focus idle function if present
1253  g_idle_remove_by_data (GNC_PLUGIN_PAGE_REGISTER (plugin_page));
1254 
1255  if (priv->widget == NULL)
1256  return;
1257 
1258  if (priv->component_manager_id)
1259  {
1260  gnc_unregister_gui_component (priv->component_manager_id);
1261  priv->component_manager_id = 0;
1262  }
1263 
1264  if (priv->event_handler_id)
1265  {
1266  qof_event_unregister_handler (priv->event_handler_id);
1267  priv->event_handler_id = 0;
1268  }
1269 
1270  if (priv->sd.dialog)
1271  {
1272  gtk_widget_destroy (priv->sd.dialog);
1273  memset (&priv->sd, 0, sizeof (priv->sd));
1274  }
1275 
1276  if (priv->fd.dialog)
1277  {
1278  gtk_widget_destroy (priv->fd.dialog);
1279  memset (&priv->fd, 0, sizeof (priv->fd));
1280  }
1281 
1282  qof_query_destroy (priv->search_query);
1283  qof_query_destroy (priv->filter_query);
1284 
1285  gtk_widget_hide (priv->widget);
1286 
1287  g_object_unref(priv->widget);
1288  priv->widget = NULL;
1289 
1290  gnc_ledger_display_close (priv->ledger);
1291  priv->ledger = NULL;
1292 
1293  LEAVE (" ");
1294 }
1295 
1296 static void
1297 gnc_plugin_page_register_window_changed (GncPluginPage* plugin_page,
1298  GtkWidget* window)
1299 {
1300  GncPluginPageRegister* page;
1302 
1303  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
1304 
1305  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1306  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1307  priv->gsr->window =
1308  GTK_WIDGET (gnc_window_get_gtk_window (GNC_WINDOW (window)));
1309 }
1310 
1311 static const gchar* style_names[] =
1312 {
1313  "Ledger",
1314  "Auto Ledger",
1315  "Journal",
1316  NULL
1317 };
1318 
1319 #define KEY_REGISTER_TYPE "RegisterType"
1320 #define KEY_ACCOUNT_NAME "AccountName"
1321 #define KEY_ACCOUNT_GUID "AccountGuid"
1322 #define KEY_REGISTER_STYLE "RegisterStyle"
1323 #define KEY_DOUBLE_LINE "DoubleLineMode"
1324 
1325 #define LABEL_ACCOUNT "Account"
1326 #define LABEL_SUBACCOUNT "SubAccount"
1327 #define LABEL_GL "GL"
1328 #define LABEL_SEARCH "Search"
1329 
1330 
1340 static void
1341 gnc_plugin_page_register_save_page (GncPluginPage* plugin_page,
1342  GKeyFile* key_file,
1343  const gchar* group_name)
1344 {
1345  GncPluginPageRegister* page;
1347  GNCLedgerDisplayType ledger_type;
1348  SplitRegister* reg;
1349  Account* leader;
1350 
1351  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
1352  g_return_if_fail (key_file != NULL);
1353  g_return_if_fail (group_name != NULL);
1354 
1355  ENTER ("page %p, key_file %p, group_name %s", plugin_page, key_file,
1356  group_name);
1357 
1358  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1359  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1360 
1361  reg = gnc_ledger_display_get_split_register (priv->ledger);
1362  ledger_type = gnc_ledger_display_type (priv->ledger);
1363  if (ledger_type > LD_GL)
1364  {
1365  LEAVE ("Unsupported ledger type");
1366  return;
1367  }
1368  if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
1369  {
1370  const gchar* label;
1371  gchar* name;
1372  gchar acct_guid[GUID_ENCODING_LENGTH + 1];
1373  label = (ledger_type == LD_SINGLE) ? LABEL_ACCOUNT : LABEL_SUBACCOUNT;
1374  leader = gnc_ledger_display_leader (priv->ledger);
1375  g_key_file_set_string (key_file, group_name, KEY_REGISTER_TYPE, label);
1376  name = gnc_account_get_full_name (leader);
1377  g_key_file_set_string (key_file, group_name, KEY_ACCOUNT_NAME, name);
1378  g_free (name);
1379  guid_to_string_buff (xaccAccountGetGUID (leader), acct_guid);
1380  g_key_file_set_string (key_file, group_name, KEY_ACCOUNT_GUID, acct_guid);
1381  }
1382  else if (reg->type == GENERAL_JOURNAL)
1383  {
1384  g_key_file_set_string (key_file, group_name, KEY_REGISTER_TYPE,
1385  LABEL_GL);
1386  }
1387  else if (reg->type == SEARCH_LEDGER)
1388  {
1389  g_key_file_set_string (key_file, group_name, KEY_REGISTER_TYPE,
1390  LABEL_SEARCH);
1391  }
1392  else
1393  {
1394  LEAVE ("Unsupported register type");
1395  return;
1396  }
1397 
1398  g_key_file_set_string (key_file, group_name, KEY_REGISTER_STYLE,
1399  style_names[reg->style]);
1400  g_key_file_set_boolean (key_file, group_name, KEY_DOUBLE_LINE,
1401  reg->use_double_line);
1402 
1403  LEAVE(" ");
1404 }
1405 
1406 
1419 static void
1420 gnc_plugin_page_register_restore_edit_menu (GncPluginPage* plugin_page,
1421  GKeyFile* key_file,
1422  const gchar* group_name)
1423 {
1424  GAction* action;
1425  GVariant *state;
1426  GError* error = NULL;
1427  gchar* style_name;
1428  gint i;
1429  gboolean use_double_line;
1430 
1431  ENTER (" ");
1432 
1433  /* Convert the style name to an index */
1434  style_name = g_key_file_get_string (key_file, group_name,
1435  KEY_REGISTER_STYLE, &error);
1436  for (i = 0 ; style_names[i]; i++)
1437  {
1438  if (g_ascii_strcasecmp (style_name, style_names[i]) == 0)
1439  {
1440  DEBUG ("Found match for style name: %s", style_name);
1441  break;
1442  }
1443  }
1444  g_free (style_name);
1445 
1446  /* Update the style menu action for this page */
1447  if (i <= REG_STYLE_JOURNAL)
1448  {
1449  DEBUG ("Setting style: %d", i);
1450  action = gnc_plugin_page_get_action (plugin_page, "ViewStyleRadioAction");
1451  g_action_activate (G_ACTION(action), g_variant_new_int32 (i));
1452  }
1453 
1454  /* Update the double line action on this page */
1455  use_double_line = g_key_file_get_boolean (key_file, group_name,
1456  KEY_DOUBLE_LINE, &error);
1457  DEBUG ("Setting double_line_mode: %d", use_double_line);
1458  action = gnc_plugin_page_get_action (plugin_page, "ViewStyleDoubleLineAction");
1459 
1460  state = g_action_get_state (G_ACTION(action));
1461 
1462  if (use_double_line != g_variant_get_boolean (state))
1463  g_action_activate (G_ACTION(action), NULL);
1464 
1465  g_variant_unref (state);
1466 
1467  LEAVE (" ");
1468 }
1469 
1470 
1480 static GncPluginPage*
1481 gnc_plugin_page_register_recreate_page (GtkWidget* window,
1482  GKeyFile* key_file,
1483  const gchar* group_name)
1484 {
1486  GncPluginPage* plugin_page;
1487  GError* error = NULL;
1488  gchar* reg_type, *acct_guid;
1489  GncGUID guid;
1490  Account* account = NULL;
1491  QofBook* book;
1492  gboolean include_subs;
1493 
1494  g_return_val_if_fail (key_file, NULL);
1495  g_return_val_if_fail (group_name, NULL);
1496  ENTER ("key_file %p, group_name %s", key_file, group_name);
1497 
1498  /* Create the new page. */
1499  reg_type = g_key_file_get_string (key_file, group_name,
1500  KEY_REGISTER_TYPE, &error);
1501  DEBUG ("Page type: %s", reg_type);
1502  if ((g_ascii_strcasecmp (reg_type, LABEL_ACCOUNT) == 0) ||
1503  (g_ascii_strcasecmp (reg_type, LABEL_SUBACCOUNT) == 0))
1504  {
1505  include_subs = (g_ascii_strcasecmp (reg_type, LABEL_SUBACCOUNT) == 0);
1506  DEBUG ("Include subs: %d", include_subs);
1507  book = qof_session_get_book (gnc_get_current_session());
1508  if (!book)
1509  {
1510  LEAVE("Session has no book");
1511  return NULL;
1512  }
1513  acct_guid = g_key_file_get_string (key_file, group_name,
1514  KEY_ACCOUNT_GUID, &error);
1515  if (string_to_guid (acct_guid, &guid)) //find account by guid
1516  {
1517  account = xaccAccountLookup (&guid, book);
1518  g_free (acct_guid);
1519  }
1520  if (account == NULL) //find account by full name
1521  {
1522  gchar* acct_name = g_key_file_get_string (key_file, group_name,
1523  KEY_ACCOUNT_NAME, &error);
1524  account = gnc_account_lookup_by_full_name (gnc_book_get_root_account (book),
1525  acct_name);
1526  g_free (acct_name);
1527  }
1528  if (account == NULL)
1529  {
1530  LEAVE ("Bad account name");
1531  g_free (reg_type);
1532  return NULL;
1533  }
1534  plugin_page = gnc_plugin_page_register_new (account, include_subs);
1535  }
1536  else if (g_ascii_strcasecmp (reg_type, LABEL_GL) == 0)
1537  {
1538  plugin_page = gnc_plugin_page_register_new_gl();
1539  }
1540  else
1541  {
1542  LEAVE ("Bad ledger type");
1543  g_free (reg_type);
1544  return NULL;
1545  }
1546  g_free (reg_type);
1547 
1548  /* disable the refresh of the display ledger, this is for
1549  * sort/filter updates and double line/style changes */
1550  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
1551  priv->enable_refresh = FALSE;
1552 
1553  /* Recreate page in given window */
1554  gnc_plugin_page_set_use_new_window (plugin_page, FALSE);
1555 
1556  /* Install it now so we can them manipulate the created widget */
1557  gnc_main_window_open_page (GNC_MAIN_WINDOW (window), plugin_page);
1558 
1559  /* Now update the page to the last state it was in */
1560  gnc_plugin_page_register_restore_edit_menu (plugin_page, key_file, group_name);
1561 
1562  /* enable the refresh */
1563  priv->enable_refresh = TRUE;
1564  LEAVE (" ");
1565  return plugin_page;
1566 }
1567 
1568 
1569 /*
1570  * Based on code from Epiphany (src/ephy-window.c)
1571  */
1572 static void
1573 gnc_plugin_page_register_update_edit_menu (GncPluginPage* plugin_page, gboolean hide)
1574 {
1576  GncPluginPageRegister* page;
1577  GAction* action;
1578  gboolean can_copy = FALSE, can_cut = FALSE, can_paste = FALSE;
1579  gboolean has_selection;
1580  gboolean is_readwrite = !qof_book_is_readonly (gnc_get_current_book());
1581 
1582  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1583  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1584  has_selection = gnucash_register_has_selection (priv->gsr->reg);
1585 
1586  can_copy = has_selection;
1587  can_cut = is_readwrite && has_selection;
1588  can_paste = is_readwrite;
1589 
1590  action = gnc_plugin_page_get_action (plugin_page, "EditCopyAction");
1591  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), can_copy);
1592  action = gnc_plugin_page_get_action (plugin_page, "EditCutAction");
1593  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), can_cut);
1594  action = gnc_plugin_page_get_action (plugin_page, "EditPasteAction");
1595  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), can_paste);
1596 }
1597 
1598 static gboolean is_scrubbing = FALSE;
1599 static gboolean show_abort_verify = TRUE;
1600 
1601 static const char*
1602 check_repair_abort_YN = N_("'Check & Repair' is currently running, do you want to abort it?");
1603 
1604 static gboolean
1605 finish_scrub (GncPluginPage* plugin_page)
1606 {
1607  gboolean ret = FALSE;
1608 
1609  if (is_scrubbing)
1610  {
1611  ret = gnc_verify_dialog (GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(plugin_page))),
1612  false, "%s", _(check_repair_abort_YN));
1613 
1614  show_abort_verify = FALSE;
1615 
1616  if (ret)
1617  gnc_set_abort_scrub (TRUE);
1618  }
1619  return ret;
1620 }
1621 
1622 static gboolean
1623 gnc_plugin_page_register_finish_pending (GncPluginPage* plugin_page)
1624 {
1626  GncPluginPageRegister* page;
1627  SplitRegister* reg;
1628  GtkWidget* dialog, *window;
1629  gchar* name;
1630  gint response;
1631 
1632  if (is_scrubbing && show_abort_verify)
1633  {
1634  if (!finish_scrub (plugin_page))
1635  return FALSE;
1636  }
1637 
1638  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1639  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1640  reg = gnc_ledger_display_get_split_register (priv->ledger);
1641 
1642  if (!reg || !gnc_split_register_changed (reg))
1643  return TRUE;
1644 
1645  name = gnc_plugin_page_register_get_tab_name (plugin_page);
1646  window = gnc_plugin_page_get_window (plugin_page);
1647  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1648  GTK_DIALOG_DESTROY_WITH_PARENT,
1649  GTK_MESSAGE_WARNING,
1650  GTK_BUTTONS_NONE,
1651  /* Translators: %s is the name
1652  of the tab page */
1653  _ ("Save changes to %s?"), name);
1654  g_free (name);
1655  gtk_message_dialog_format_secondary_text
1656  (GTK_MESSAGE_DIALOG (dialog),
1657  "%s",
1658  _ ("This register has pending changes to a transaction. "
1659  "Would you like to save the changes to this transaction, "
1660  "discard the transaction, or cancel the operation?"));
1661  gnc_gtk_dialog_add_button (dialog, _ ("_Discard Transaction"),
1662  "edit-delete", GTK_RESPONSE_REJECT);
1663  gtk_dialog_add_button (GTK_DIALOG (dialog),
1664  _ ("_Cancel"), GTK_RESPONSE_CANCEL);
1665  gnc_gtk_dialog_add_button (dialog, _ ("_Save Transaction"),
1666  "document-save", GTK_RESPONSE_ACCEPT);
1667 
1668  response = gtk_dialog_run (GTK_DIALOG (dialog));
1669  gtk_widget_destroy (dialog);
1670 
1671  switch (response)
1672  {
1673  case GTK_RESPONSE_ACCEPT:
1674  gnc_split_register_save (reg, TRUE);
1675  return TRUE;
1676 
1677  case GTK_RESPONSE_REJECT:
1679  gnc_split_register_save (reg, TRUE);
1680  return TRUE;
1681 
1682  default:
1683  return FALSE;
1684  }
1685 }
1686 
1687 
1688 static gchar*
1689 gnc_plugin_page_register_get_tab_name (GncPluginPage* plugin_page)
1690 {
1692  GNCLedgerDisplayType ledger_type;
1693  GNCLedgerDisplay* ld;
1694  SplitRegister* reg;
1695  Account* leader;
1696 
1697  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
1698  g_strdup (_("unknown")));
1699 
1700  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
1701  ld = priv->ledger;
1703  ledger_type = gnc_ledger_display_type (ld);
1704  leader = gnc_ledger_display_leader (ld);
1705 
1706  switch (ledger_type)
1707  {
1708  case LD_SINGLE:
1709  return g_strdup (xaccAccountGetName (leader));
1710 
1711  case LD_SUBACCOUNT:
1712  return g_strdup_printf ("%s+", xaccAccountGetName (leader));
1713 
1714  case LD_GL:
1715  switch (reg->type)
1716  {
1717  case GENERAL_JOURNAL:
1718  case INCOME_LEDGER:
1719  return g_strdup (_ ("General Journal"));
1720  case PORTFOLIO_LEDGER:
1721  return g_strdup (_ ("Portfolio"));
1722  case SEARCH_LEDGER:
1723  return g_strdup (_ ("Search Results"));
1724  default:
1725  break;
1726  }
1727  break;
1728 
1729  default:
1730  break;
1731  }
1732 
1733  return g_strdup (_ ("unknown"));
1734 }
1735 
1736 static gchar*
1737 gnc_plugin_page_register_get_tab_color (GncPluginPage* plugin_page)
1738 {
1740  GNCLedgerDisplayType ledger_type;
1741  GNCLedgerDisplay* ld;
1742  Account* leader;
1743  const char* color;
1744 
1745  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
1746  g_strdup (_("unknown")));
1747 
1748  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
1749  ld = priv->ledger;
1750  ledger_type = gnc_ledger_display_type (ld);
1751  leader = gnc_ledger_display_leader (ld);
1752  color = NULL;
1753 
1754  if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
1755  color = xaccAccountGetColor (leader);
1756 
1757  return g_strdup (color ? color : "Not Set");
1758 }
1759 
1760 static gchar*
1761 gnc_plugin_page_register_get_long_name (GncPluginPage* plugin_page)
1762 {
1764  GNCLedgerDisplayType ledger_type;
1765  GNCLedgerDisplay* ld;
1766  Account* leader;
1767 
1768  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
1769  _ ("unknown"));
1770 
1771  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
1772  ld = priv->ledger;
1773  ledger_type = gnc_ledger_display_type (ld);
1774  leader = gnc_ledger_display_leader (ld);
1775 
1776  switch (ledger_type)
1777  {
1778  case LD_SINGLE:
1779  return gnc_account_get_full_name (leader);
1780 
1781  case LD_SUBACCOUNT:
1782  {
1783  gchar* account_full_name = gnc_account_get_full_name (leader);
1784  gchar* return_string = g_strdup_printf ("%s+", account_full_name);
1785  g_free ((gpointer*) account_full_name);
1786  return return_string;
1787  }
1788 
1789  default:
1790  break;
1791  }
1792 
1793  return NULL;
1794 }
1795 
1796 static void
1797 gnc_plugin_page_register_summarybar_position_changed (gpointer prefs,
1798  gchar* pref,
1799  gpointer user_data)
1800 {
1801  GncPluginPage* plugin_page;
1802  GncPluginPageRegister* page;
1804  GtkPositionType position = GTK_POS_BOTTOM;
1805 
1806  g_return_if_fail (user_data != NULL);
1807 
1808  if (!GNC_IS_PLUGIN_PAGE (user_data))
1809  return;
1810 
1811  plugin_page = GNC_PLUGIN_PAGE (user_data);
1812  page = GNC_PLUGIN_PAGE_REGISTER (user_data);
1813  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1814 
1815  if (priv == NULL)
1816  return;
1817 
1818  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL,
1819  GNC_PREF_SUMMARYBAR_POSITION_TOP))
1820  position = GTK_POS_TOP;
1821 
1822  gtk_box_reorder_child (GTK_BOX (priv->widget),
1823  plugin_page->summarybar,
1824  (position == GTK_POS_TOP ? 0 : -1));
1825 }
1826 
1827 static void
1828 gnc_plugin_page_register_update_page_icon (GncPluginPage* plugin_page)
1829 {
1831  gboolean read_only;
1832 
1833  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
1834 
1835  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
1836 
1837  if (qof_book_is_readonly (gnc_get_current_book()) ||
1838  gnc_split_reg_get_read_only (priv->gsr))
1839  read_only = TRUE;
1840  else
1841  read_only = FALSE;
1842 
1843  main_window_update_page_set_read_only_icon (GNC_PLUGIN_PAGE(plugin_page),
1844  read_only);
1845 }
1846 
1852 Query*
1854 {
1855  GncPluginPageRegister* page;
1857 
1858  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page), NULL);
1859 
1860  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
1861  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1862  return gnc_ledger_display_get_query (priv->ledger);
1863 }
1864 
1865 void
1867 {
1869 
1870  ENTER(" ");
1871  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
1872 
1873  // clear previous filter query and save current
1874  qof_query_destroy (priv->filter_query);
1875  priv->filter_query = qof_query_copy (query);
1876 
1877  if (priv->enable_refresh)
1878  gnc_ledger_display_refresh (priv->ledger);
1879  LEAVE(" ");
1880 }
1881 
1882 void
1884 {
1886  SplitRegister* reg;
1887 
1888  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
1889  reg = gnc_ledger_display_get_split_register (priv->ledger);
1890 
1891  if (reg->type == SEARCH_LEDGER)
1892  {
1893  Query* query_tmp = gnc_ledger_display_get_query (priv->ledger);
1894 
1895  // if filter_query is NULL, then the dialogue find has been run
1896  // before coming here. if query_tmp does not equal filter_query
1897  // then the dialogue find has been run again before coming here
1898  if ((priv->filter_query == NULL) ||
1899  (!qof_query_equal (query_tmp, priv->filter_query)))
1900  {
1901  qof_query_destroy (priv->search_query);
1902  priv->search_query = qof_query_copy (query_tmp);
1903  }
1904  gnc_ledger_display_set_query (priv->ledger, priv->search_query);
1905  }
1906 }
1907 
1908 void
1910  gboolean enable_refresh)
1911 {
1913 
1914  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(page));
1915 
1916  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
1917 
1918  priv->enable_refresh = enable_refresh;
1919 }
1920 
1921 void
1923 {
1924  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page));
1925 
1927 }
1928 
1929 /************************************************************/
1930 /* Report Helper Functions */
1931 /************************************************************/
1932 
1933 static char*
1934 gnc_reg_get_name (GNCLedgerDisplay* ledger, gboolean for_window)
1935 {
1936  Account* leader;
1937  SplitRegister* reg;
1938  gchar* account_name;
1939  gchar* reg_name;
1940  gchar* name;
1941  GNCLedgerDisplayType ledger_type;
1942 
1943  if (ledger == NULL)
1944  return NULL;
1945 
1947  ledger_type = gnc_ledger_display_type (ledger);
1948 
1949  switch (reg->type)
1950  {
1951  case GENERAL_JOURNAL:
1952  case INCOME_LEDGER:
1953  if (for_window)
1954  reg_name = _ ("General Journal");
1955  else
1956  reg_name = _ ("Transaction Report");
1957  break;
1958  case PORTFOLIO_LEDGER:
1959  if (for_window)
1960  reg_name = _ ("Portfolio");
1961  else
1962  reg_name = _ ("Portfolio Report");
1963  break;
1964  case SEARCH_LEDGER:
1965  if (for_window)
1966  reg_name = _ ("Search Results");
1967  else
1968  reg_name = _ ("Search Results Report");
1969  break;
1970  default:
1971  if (for_window)
1972  reg_name = _ ("Register");
1973  else
1974  reg_name = _ ("Transaction Report");
1975  break;
1976  }
1977 
1978  leader = gnc_ledger_display_leader (ledger);
1979 
1980  if ((leader != NULL) && (ledger_type != LD_GL))
1981  {
1982  account_name = gnc_account_get_full_name (leader);
1983 
1984  if (ledger_type == LD_SINGLE)
1985  {
1986  name = g_strconcat (account_name, " - ", reg_name, NULL);
1987  }
1988  else
1989  {
1990  name = g_strconcat (account_name, " ", _ ("and subaccounts"), " - ", reg_name,
1991  NULL);
1992  }
1993  g_free (account_name);
1994  }
1995  else
1996  name = g_strdup (reg_name);
1997 
1998  return name;
1999 }
2000 
2001 static int
2002 report_helper (GNCLedgerDisplay* ledger, Split* split, Query* query)
2003 {
2004  SplitRegister* reg = gnc_ledger_display_get_split_register (ledger);
2005  Account* account;
2006  char* str;
2007  const char* tmp;
2008  swig_type_info* qtype;
2009  SCM args;
2010  SCM func;
2011  SCM arg;
2012 
2013  args = SCM_EOL;
2014 
2015  func = scm_c_eval_string ("gnc:register-report-create");
2016  g_return_val_if_fail (scm_is_procedure (func), -1);
2017 
2019  arg = scm_from_utf8_string (tmp ? tmp : _ ("Credit"));
2020  args = scm_cons (arg, args);
2021 
2023  arg = scm_from_utf8_string (tmp ? tmp : _ ("Debit"));
2024  args = scm_cons (arg, args);
2025 
2026  str = gnc_reg_get_name (ledger, FALSE);
2027  arg = scm_from_utf8_string (str ? str : "");
2028  args = scm_cons (arg, args);
2029  g_free (str);
2030 
2031  arg = SCM_BOOL (reg->use_double_line);
2032  args = scm_cons (arg, args);
2033 
2034  arg = SCM_BOOL (reg->type == GENERAL_JOURNAL || reg->type == INCOME_LEDGER
2035  || reg->type == SEARCH_LEDGER);
2036  args = scm_cons (arg, args);
2037 
2038  arg = SCM_BOOL (reg->style == REG_STYLE_JOURNAL);
2039  args = scm_cons (arg, args);
2040 
2041  if (!query)
2042  {
2043  query = gnc_ledger_display_get_query (ledger);
2044  g_return_val_if_fail (query != NULL, -1);
2045  }
2046 
2047  qtype = SWIG_TypeQuery ("_p__QofQuery");
2048  g_return_val_if_fail (qtype, -1);
2049 
2050  arg = SWIG_NewPointerObj (query, qtype, 0);
2051  args = scm_cons (arg, args);
2052  g_return_val_if_fail (arg != SCM_UNDEFINED, -1);
2053 
2054 
2055  if (split)
2056  {
2057  qtype = SWIG_TypeQuery ("_p_Split");
2058  g_return_val_if_fail (qtype, -1);
2059  arg = SWIG_NewPointerObj (split, qtype, 0);
2060  }
2061  else
2062  {
2063  arg = SCM_BOOL_F;
2064  }
2065  args = scm_cons (arg, args);
2066  g_return_val_if_fail (arg != SCM_UNDEFINED, -1);
2067 
2068 
2069  qtype = SWIG_TypeQuery ("_p_Account");
2070  g_return_val_if_fail (qtype, -1);
2071 
2072  account = gnc_ledger_display_leader (ledger);
2073  arg = SWIG_NewPointerObj (account, qtype, 0);
2074  args = scm_cons (arg, args);
2075  g_return_val_if_fail (arg != SCM_UNDEFINED, -1);
2076 
2077 
2078  /* Apply the function to the args */
2079  arg = scm_apply (func, args, SCM_EOL);
2080  g_return_val_if_fail (scm_is_exact (arg), -1);
2081 
2082  return scm_to_int (arg);
2083 }
2084 
2085 /************************************************************/
2086 /* Command callbacks */
2087 /************************************************************/
2088 
2089 static void
2090 gnc_plugin_page_register_cmd_print_check (GSimpleAction *simple,
2091  GVariant *paramter,
2092  gpointer user_data)
2093 {
2094  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2096  SplitRegister* reg;
2097  Split* split;
2098  Transaction* trans;
2099  GList* splits = NULL, *item;
2100  GNCLedgerDisplayType ledger_type;
2101  Account* account, *subaccount = NULL;
2102  GtkWidget* window;
2103 
2104  ENTER ("(action %p, page %p)", simple, page);
2105 
2106  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2107 
2108  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2109  reg = gnc_ledger_display_get_split_register (priv->ledger);
2110  ledger_type = gnc_ledger_display_type (priv->ledger);
2111  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
2112  if (ledger_type == LD_SINGLE || ledger_type == LD_SUBACCOUNT)
2113  {
2114  account = gnc_plugin_page_register_get_account (page);
2116  trans = xaccSplitGetParent (split);
2117  if (ledger_type == LD_SUBACCOUNT)
2118  {
2119  /* Set up subaccount printing, where the check amount matches the
2120  * value displayed in the register. */
2121  subaccount = account;
2122  }
2123 
2124  if (split && trans)
2125  {
2126  if (xaccSplitGetAccount (split) == account)
2127  {
2128  splits = g_list_prepend (splits, split);
2129  gnc_ui_print_check_dialog_create (window, splits, subaccount);
2130  g_list_free (splits);
2131  }
2132  else
2133  {
2134  /* This split is not for the account shown in this register. Get the
2135  split that anchors the transaction to the registor */
2136  split = gnc_split_register_get_current_trans_split (reg, NULL);
2137  if (split)
2138  {
2139  splits = g_list_prepend (splits, split);
2140  gnc_ui_print_check_dialog_create (window, splits, subaccount);
2141  g_list_free (splits);
2142  }
2143  }
2144  }
2145  }
2146  else if (ledger_type == LD_GL && reg->type == SEARCH_LEDGER)
2147  {
2148  Account* common_acct = NULL;
2149 
2150  /* the following GList* splits must not be freed */
2151  splits = qof_query_run (gnc_ledger_display_get_query (priv->ledger));
2152 
2153  /* Make sure each split is from the same account */
2154  for (item = splits; item; item = g_list_next (item))
2155  {
2156  split = (Split*) item->data;
2157  if (common_acct == NULL)
2158  {
2159  common_acct = xaccSplitGetAccount (split);
2160  }
2161  else
2162  {
2163  if (xaccSplitGetAccount (split) != common_acct)
2164  {
2165  GtkWidget* dialog;
2166  gint response;
2167  const gchar* title = _ ("Print checks from multiple accounts?");
2168  const gchar* message =
2169  _ ("This search result contains splits from more than one account. "
2170  "Do you want to print the checks even though they are not all "
2171  "from the same account?");
2172  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
2173  GTK_DIALOG_DESTROY_WITH_PARENT,
2174  GTK_MESSAGE_WARNING,
2175  GTK_BUTTONS_CANCEL,
2176  "%s", title);
2177  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
2178  "%s", message);
2179  gtk_dialog_add_button (GTK_DIALOG (dialog), _ ("_Print checks"),
2180  GTK_RESPONSE_YES);
2181  response = gnc_dialog_run (GTK_DIALOG (dialog),
2182  GNC_PREF_WARN_CHECKPRINTING_MULTI_ACCT);
2183  gtk_widget_destroy (dialog);
2184  if (response != GTK_RESPONSE_YES)
2185  {
2186  LEAVE ("Multiple accounts");
2187  return;
2188  }
2189  break;
2190  }
2191  }
2192  }
2193  gnc_ui_print_check_dialog_create (window, splits, NULL);
2194  }
2195  else
2196  {
2197  gnc_error_dialog (GTK_WINDOW (window), "%s",
2198  _ ("You can only print checks from a bank account register or search results."));
2199  LEAVE ("Unsupported ledger type");
2200  return;
2201  }
2202  LEAVE (" ");
2203 }
2204 
2205 
2206 static void
2207 gnc_plugin_page_register_cmd_cut (GSimpleAction *simple,
2208  GVariant *paramter,
2209  gpointer user_data)
2210 {
2211  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2213 
2214  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2215 
2216  ENTER ("(action %p, page %p)", simple, page);
2217  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2218 
2219  GtkWidget *widget = gtk_window_get_focus(GTK_WINDOW (priv->gsr->window));
2220  const char *name = gtk_widget_get_name(widget);
2221  if (strcmp(name, "GnucashSheet") != 0)
2222  {
2223  gtk_editable_cut_clipboard( GTK_EDITABLE(widget));
2224  LEAVE("Not cut from GnucashSheet");
2225 
2226  return;
2227  }
2228 
2229  gnucash_register_cut_clipboard (priv->gsr->reg);
2230  LEAVE ("");
2231 }
2232 
2233 
2234 static void
2235 gnc_plugin_page_register_cmd_copy (GSimpleAction *simple,
2236  GVariant *paramter,
2237  gpointer user_data)
2238 {
2239  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2241 
2242  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2243 
2244  ENTER ("(action %p, page %p)", simple, page);
2245  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2246 
2247  GtkWidget *widget = gtk_window_get_focus(GTK_WINDOW (priv->gsr->window));
2248  const char *name = gtk_widget_get_name(widget);
2249  if (strcmp(name, "GnucashSheet") != 0)
2250  {
2251  gtk_editable_copy_clipboard( GTK_EDITABLE(widget));
2252  LEAVE("Not copied from GnucashSheet");
2253 
2254  return;
2255  }
2256 
2257  gnucash_register_copy_clipboard (priv->gsr->reg);
2258  LEAVE ("");
2259 }
2260 
2261 
2262 static void
2263 gnc_plugin_page_register_cmd_paste (GSimpleAction *simple,
2264  GVariant *paramter,
2265  gpointer user_data)
2266 {
2267  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2269 
2270  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2271 
2272  ENTER ("(action %p, page %p)", simple, page);
2273  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2274 
2275  GtkWidget *widget = gtk_window_get_focus(GTK_WINDOW (priv->gsr->window));
2276  const char *name = gtk_widget_get_name(widget);
2277  if (strcmp(name, "GnucashSheet") != 0)
2278  {
2279  gtk_editable_paste_clipboard( GTK_EDITABLE(widget));
2280  LEAVE("Not pasted to GnucashSheet");
2281 
2282  return;
2283  }
2284 
2285  gnucash_register_paste_clipboard (priv->gsr->reg);
2286  LEAVE ("");
2287 }
2288 
2289 
2290 static void
2291 gnc_plugin_page_register_cmd_edit_account (GSimpleAction *simple,
2292  GVariant *paramter,
2293  gpointer user_data)
2294 {
2295  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2296  Account* account;
2297  GtkWindow* parent = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page)));
2298  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2299 
2300  ENTER ("(action %p, page %p)", simple, page);
2301  account = gnc_plugin_page_register_get_account (page);
2302  if (account)
2303  gnc_ui_edit_account_window (parent, account);
2304  LEAVE (" ");
2305 }
2306 
2307 
2308 static void
2309 gnc_plugin_page_register_cmd_find_account (GSimpleAction *simple,
2310  GVariant *paramter,
2311  gpointer user_data)
2312 {
2313  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2314  GtkWidget* window;
2315 
2316  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2317 
2318  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
2319  gnc_find_account_dialog (window, NULL);
2320 }
2321 
2322 
2323 static void
2324 gnc_plugin_page_register_cmd_find_transactions (GSimpleAction *simple,
2325  GVariant *paramter,
2326  gpointer user_data)
2327 {
2328  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2330  GtkWindow* window;
2331 
2332  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2333 
2334  ENTER ("(action %p, page %p)", simple, page);
2335  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2336  window = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
2337  gnc_ui_find_transactions_dialog_create (window, priv->ledger);
2338  LEAVE (" ");
2339 }
2340 
2341 
2342 static void
2343 gnc_plugin_page_register_cmd_edit_tax_options (GSimpleAction *simple,
2344  GVariant *paramter,
2345  gpointer user_data)
2346 {
2347  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2348  GtkWidget *window;
2349  Account* account;
2350 
2351  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2352 
2353  ENTER ("(action %p, page %p)", simple, page);
2354  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
2355  account = gnc_plugin_page_register_get_account (page);
2356  gnc_tax_info_dialog (window, account);
2357  LEAVE (" ");
2358 }
2359 
2360 static void
2361 gnc_plugin_page_register_cmd_cut_transaction (GSimpleAction *simple,
2362  GVariant *paramter,
2363  gpointer user_data)
2364 {
2365  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2367 
2368  ENTER ("(action %p, page %p)", simple, page);
2369 
2370  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2371 
2372  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2373  gsr_default_cut_txn_handler (priv->gsr, NULL);
2374 
2375  // Transaction/Split paste action
2376  GAction *action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
2377  "PasteTransactionAction");
2378  g_simple_action_set_enabled (G_SIMPLE_ACTION(action),
2380  LEAVE (" ");
2381 }
2382 
2383 
2384 static void
2385 gnc_plugin_page_register_cmd_copy_transaction (GSimpleAction *simple,
2386  GVariant *paramter,
2387  gpointer user_data)
2388 {
2389  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2391  SplitRegister* reg;
2392 
2393  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2394 
2395  ENTER ("(action %p, page %p)", simple, page);
2396  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2397  reg = gnc_ledger_display_get_split_register (priv->ledger);
2399 
2400  // Transaction/Split paste action
2401  GAction *action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
2402  "PasteTransactionAction");
2403  g_simple_action_set_enabled (G_SIMPLE_ACTION(action),
2405  LEAVE (" ");
2406 }
2407 
2408 
2409 static void
2410 gnc_plugin_page_register_cmd_paste_transaction (GSimpleAction *simple,
2411  GVariant *paramter,
2412  gpointer user_data)
2413 {
2414  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2416  SplitRegister* reg;
2417 
2418  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2419 
2420  ENTER ("(action %p, page %p)", simple, page);
2421  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2422  reg = gnc_ledger_display_get_split_register (priv->ledger);
2424  LEAVE (" ");
2425 }
2426 
2427 
2428 static void
2429 gnc_plugin_page_register_cmd_void_transaction (GSimpleAction *simple,
2430  GVariant *paramter,
2431  gpointer user_data)
2432 {
2433  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2435  GtkWidget* dialog, *entry;
2436  SplitRegister* reg;
2437  Transaction* trans;
2438  GtkBuilder* builder;
2439  const char* reason;
2440  gint result;
2441  GtkWindow* window;
2442 
2443  ENTER ("(action %p, page %p)", simple, page);
2444 
2445  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2446 
2447  window = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
2448  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2449  reg = gnc_ledger_display_get_split_register (priv->ledger);
2451  if (trans == NULL)
2452  return;
2453  if (xaccTransHasSplitsInState (trans, VREC))
2454  return;
2455  if (xaccTransHasReconciledSplits (trans) ||
2457  {
2458  gnc_error_dialog (window, "%s",
2459  _ ("You cannot void a transaction with reconciled or cleared splits."));
2460  return;
2461  }
2462  reason = xaccTransGetReadOnly (trans);
2463  if (reason)
2464  {
2465  gnc_error_dialog (window,
2466  _ ("This transaction is marked read-only with the comment: '%s'"), reason);
2467  return;
2468  }
2469 
2470  if (!gnc_plugin_page_register_finish_pending (GNC_PLUGIN_PAGE (page)))
2471  return;
2472 
2473  builder = gtk_builder_new();
2474  gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade",
2475  "void_transaction_dialog");
2476  dialog = GTK_WIDGET (gtk_builder_get_object (builder,
2477  "void_transaction_dialog"));
2478  entry = GTK_WIDGET (gtk_builder_get_object (builder, "reason"));
2479 
2480  gtk_window_set_transient_for (GTK_WINDOW (dialog), window);
2481 
2482  result = gtk_dialog_run (GTK_DIALOG (dialog));
2483  if (result == GTK_RESPONSE_OK)
2484  {
2485  reason = gtk_entry_get_text (GTK_ENTRY (entry));
2486  if (reason == NULL)
2487  reason = "";
2489  }
2490 
2491  /* All done. Get rid of it. */
2492  gtk_widget_destroy (dialog);
2493  g_object_unref (G_OBJECT (builder));
2494 }
2495 
2496 
2497 static void
2498 gnc_plugin_page_register_cmd_unvoid_transaction (GSimpleAction *simple,
2499  GVariant *paramter,
2500  gpointer user_data)
2501 {
2502  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2504  SplitRegister* reg;
2505  Transaction* trans;
2506 
2507  ENTER ("(action %p, page %p)", simple, page);
2508 
2509  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2510 
2511  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2512  reg = gnc_ledger_display_get_split_register (priv->ledger);
2514  if (!xaccTransHasSplitsInState (trans, VREC))
2515  return;
2517  LEAVE (" ");
2518 }
2519 
2520 static std::optional<time64>
2521 input_date (GtkWidget * parent, const char *window_title, const char* title)
2522 {
2523  time64 rv = gnc_time (nullptr);
2524  if (!gnc_dup_time64_dialog (parent, window_title, title, &rv))
2525  return {};
2526 
2527  return rv;
2528 }
2529 
2530 static void
2531 gnc_plugin_page_register_cmd_reverse_transaction (GSimpleAction *simple,
2532  GVariant *paramter,
2533  gpointer user_data)
2534 {
2535  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2537  SplitRegister* reg;
2538  GNCSplitReg* gsr;
2539  Transaction* trans, *new_trans;
2540  GtkWidget *window;
2541  Account *account;
2542  Split *split;
2543 
2544  ENTER ("(action %p, page %p)", simple, page);
2545 
2546  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2547 
2548  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2549  reg = gnc_ledger_display_get_split_register (priv->ledger);
2550  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
2552  if (trans == NULL)
2553  return;
2554 
2556  account = xaccSplitGetAccount (split);
2557 
2558  if (!account)
2559  {
2560  LEAVE ("shouldn't try to reverse the blank transaction...");
2561  return;
2562  }
2563 
2564  new_trans = xaccTransGetReversedBy (trans);
2565  if (new_trans)
2566  {
2567  const char *rev = _("A reversing entry has already been created for this transaction.");
2568  const char *jump = _("Jump to the transaction?");
2569  if (!gnc_verify_dialog (GTK_WINDOW (window), TRUE, "%s\n\n%s", rev, jump))
2570  {
2571  LEAVE ("reverse cancelled");
2572  return;
2573  }
2574  }
2575  else
2576  {
2577  auto date = input_date (window, _("Reverse Transaction"), _("New Transaction Information"));
2578  if (!date)
2579  {
2580  LEAVE ("reverse cancelled");
2581  return;
2582  }
2583 
2584  gnc_suspend_gui_refresh ();
2585  new_trans = xaccTransReverse (trans);
2586 
2587  /* Clear transaction level info */
2588  xaccTransSetDatePostedSecsNormalized (new_trans, date.value());
2589  xaccTransSetDateEnteredSecs (new_trans, gnc_time (NULL));
2590 
2591  gnc_resume_gui_refresh();
2592  }
2593 
2594  /* Now jump to new trans */
2595  gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE (page));
2596  split = xaccTransFindSplitByAccount(new_trans, account);
2597 
2598  /* Test for visibility of split */
2599  if (gnc_split_reg_clear_filter_for_split (gsr, split))
2600  gnc_plugin_page_register_clear_current_filter (GNC_PLUGIN_PAGE(page));
2601 
2602  gnc_split_reg_jump_to_split (gsr, split);
2603  LEAVE (" ");
2604 }
2605 
2606 static bool
2607 gnc_plugin_page_register_show_fs_save (GncPluginPageRegister* page)
2608 {
2609  GncPluginPageRegisterPrivate* priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2610  GNCLedgerDisplayType ledger_type = gnc_ledger_display_type (priv->ledger);
2611  SplitRegister* reg = gnc_ledger_display_get_split_register (priv->ledger);
2612 
2613  if (ledger_type == LD_SINGLE || ledger_type == LD_SUBACCOUNT)
2614  return true;
2615  else
2616  {
2617  switch (reg->type)
2618  {
2619  case GENERAL_JOURNAL:
2620  return true;
2621  break;
2622 
2623  case INCOME_LEDGER:
2624  case PORTFOLIO_LEDGER:
2625  case SEARCH_LEDGER:
2626  default:
2627  return false;
2628  break;
2629  }
2630  }
2631 }
2632 
2633 static void
2634 gnc_plugin_page_register_cmd_view_sort_by (GSimpleAction *simple,
2635  GVariant *paramter,
2636  gpointer user_data)
2637 {
2638  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2640 
2641  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(page));
2642  ENTER ("(action %p, page %p)", simple, page);
2643 
2644  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
2645  if (priv->sd.dialog)
2646  {
2647  gtk_window_present (GTK_WINDOW (priv->sd.dialog));
2648  LEAVE("existing dialog");
2649  return;
2650  }
2651 
2652  SplitRegister* reg = gnc_ledger_display_get_split_register (priv->ledger);
2653  bool show_save_button = gnc_plugin_page_register_show_fs_save (page);
2654 
2655  gnc_ppr_sort_dialog (GNC_PLUGIN_PAGE(page), reg,
2656  &priv->sd, show_save_button);
2657 }
2658 
2659 static void
2660 gnc_plugin_page_register_cmd_view_filter_by (GSimpleAction *simple,
2661  GVariant *paramter,
2662  gpointer user_data)
2663 {
2664  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2666 
2667  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(page));
2668  ENTER ("(action %p, page %p)", simple, page);
2669 
2670  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
2671  if (priv->fd.dialog)
2672  {
2673  gtk_window_present (GTK_WINDOW(priv->fd.dialog));
2674  LEAVE ("existing dialog");
2675  return;
2676  }
2677 
2678  Query* query = gnc_ledger_display_get_query (priv->ledger);
2679  bool show_save_button = gnc_plugin_page_register_show_fs_save (page);
2680 
2681  gnc_ppr_filter_by (GNC_PLUGIN_PAGE(page), query,
2682  &priv->fd, show_save_button);
2683 
2684  LEAVE (" ");
2685 }
2686 
2687 static void
2688 gnc_plugin_page_register_cmd_reload (GSimpleAction *simple,
2689  GVariant *paramter,
2690  gpointer user_data)
2691 {
2692  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2694  SplitRegister* reg;
2695 
2696  ENTER ("(action %p, page %p)", simple, page);
2697 
2698  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2699 
2700  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2701  reg = gnc_ledger_display_get_split_register (priv->ledger);
2702 
2703  /* Check for trans being edited */
2704  if (gnc_split_register_changed (reg))
2705  {
2706  LEAVE ("register has pending edits");
2707  return;
2708  }
2709  gnc_ledger_display_refresh (priv->ledger);
2710  LEAVE (" ");
2711 }
2712 
2713 static void
2714 gnc_plugin_page_register_cmd_style_changed (GSimpleAction *simple,
2715  GVariant *parameter,
2716  gpointer user_data)
2717 {
2718  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2720  SplitRegisterStyle value;
2721 
2722  ENTER ("(action %p, page %p)", simple, page);
2723 
2724  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2725 
2726  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2727 
2728  value = (SplitRegisterStyle)g_variant_get_int32 (parameter);
2729 
2730  g_action_change_state (G_ACTION(simple), parameter);
2731 
2732  gnc_split_reg_change_style (priv->gsr, value, priv->enable_refresh);
2733 
2734  gnc_plugin_page_register_ui_update (NULL, page);
2735  LEAVE (" ");
2736 }
2737 
2738 static void
2739 gnc_plugin_page_register_cmd_style_double_line (GSimpleAction *simple,
2740  GVariant *parameter,
2741  gpointer user_data)
2742 {
2743  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2745  SplitRegister* reg;
2746  gboolean use_double_line;
2747  GVariant *state;
2748 
2749  ENTER ("(action %p, page %p)", simple, page);
2750 
2751  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(page));
2752 
2753  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2754  reg = gnc_ledger_display_get_split_register (priv->ledger);
2755 
2756  state = g_action_get_state (G_ACTION(simple));
2757 
2758  g_action_change_state (G_ACTION(simple), g_variant_new_boolean (!g_variant_get_boolean (state)));
2759 
2760  use_double_line = !g_variant_get_boolean (state);
2761 
2762  if (use_double_line != reg->use_double_line)
2763  {
2764  gnc_split_register_config (reg, reg->type, reg->style, use_double_line);
2765  if (priv->enable_refresh)
2766  gnc_ledger_display_refresh (priv->ledger);
2767  }
2768  g_variant_unref (state);
2769  LEAVE (" ");
2770 }
2771 
2772 static void
2773 gnc_plugin_page_register_cmd_transfer (GSimpleAction *simple,
2774  GVariant *paramter,
2775  gpointer user_data)
2776 {
2777  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2778  Account* account;
2779  GncWindow* gnc_window;
2780  GtkWidget* window;
2781 
2782  ENTER ("(action %p, page %p)", simple, page);
2783 
2784  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2785 
2786  account = gnc_plugin_page_register_get_account (page);
2787  gnc_window = GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window);
2788  window = GTK_WIDGET (gnc_window_get_gtk_window (gnc_window));
2789  gnc_xfer_dialog (window, account);
2790  LEAVE (" ");
2791 }
2792 
2793 static void
2794 gnc_plugin_page_register_cmd_reconcile (GSimpleAction *simple,
2795  GVariant *paramter,
2796  gpointer user_data)
2797 {
2798  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2799  Account* account;
2800  GtkWindow* window;
2801  RecnWindow* recnData;
2802 
2803  ENTER ("(action %p, page %p)", simple, page);
2804 
2805  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2806 
2807  /* To prevent mistakes involving saving an edited transaction after
2808  * finishing a reconciliation (reverting the reconcile state), require
2809  * pending activity on the current register to be finished.
2810  *
2811  * The reconcile window isn't modal so it's still possible to start editing
2812  * a transaction after opening it, but at that point the user should know
2813  * what they're doing is unsafe.
2814  */
2815  if (!gnc_plugin_page_register_finish_pending (GNC_PLUGIN_PAGE (page)))
2816  return;
2817 
2818  account = gnc_plugin_page_register_get_account (page);
2819 
2820  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (
2821  page)->window));
2822  recnData = recnWindow (GTK_WIDGET (window), account);
2823  gnc_ui_reconcile_window_raise (recnData);
2824  LEAVE (" ");
2825 }
2826 
2827 static void
2828 gnc_plugin_page_register_cmd_stock_assistant (GSimpleAction *simple,
2829  GVariant *paramter,
2830  gpointer user_data)
2831 {
2832  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2833  Account *account;
2834  GtkWindow *window;
2835 
2836  ENTER ("(action %p, page %p)", simple, page);
2837 
2838  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2839  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window));
2840  account = gnc_plugin_page_register_get_account (page);
2841  gnc_stock_transaction_assistant (GTK_WIDGET (window), account);
2842 
2843  LEAVE (" ");
2844 }
2845 
2846 static void
2847 gnc_plugin_page_register_cmd_autoclear (GSimpleAction *simple,
2848  GVariant *paramter,
2849  gpointer user_data)
2850 {
2851  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2852  Account* account;
2853  GtkWindow* window;
2854  AutoClearWindow* autoClearData;
2855 
2856  ENTER ("(action %p, page %p)", simple, page);
2857 
2858  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2859 
2860  account = gnc_plugin_page_register_get_account (page);
2861 
2862  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (
2863  page)->window));
2864  autoClearData = autoClearWindow (GTK_WIDGET (window), account);
2865  gnc_ui_autoclear_window_raise (autoClearData);
2866  LEAVE (" ");
2867 }
2868 
2869 static void
2870 gnc_plugin_page_register_cmd_stock_split (GSimpleAction *simple,
2871  GVariant *paramter,
2872  gpointer user_data)
2873 {
2874  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2875  Account* account;
2876  GtkWindow* window;
2877 
2878  ENTER ("(action %p, page %p)", simple, page);
2879 
2880  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2881 
2882  account = gnc_plugin_page_register_get_account (page);
2883  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window));
2884  gnc_stock_split_dialog (GTK_WIDGET (window), account);
2885  LEAVE (" ");
2886 }
2887 
2888 static void
2889 gnc_plugin_page_register_cmd_lots (GSimpleAction *simple,
2890  GVariant *paramter,
2891  gpointer user_data)
2892 {
2893  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2894  GtkWindow* window;
2895  Account* account;
2896 
2897  ENTER ("(action %p, page %p)", simple, page);
2898 
2899  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2900 
2901  window = gnc_window_get_gtk_window (GNC_WINDOW (GNC_PLUGIN_PAGE (
2902  page)->window));
2903  account = gnc_plugin_page_register_get_account (page);
2904  gnc_lot_viewer_dialog (window, account);
2905  LEAVE (" ");
2906 }
2907 
2908 static void
2909 gnc_plugin_page_register_cmd_enter_transaction (GSimpleAction *simple,
2910  GVariant *paramter,
2911  gpointer user_data)
2912 {
2913  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2915 
2916  ENTER ("(action %p, page %p)", simple, page);
2917 
2918  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2919 
2920  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2921  gnc_split_reg_enter (priv->gsr, FALSE);
2922  LEAVE (" ");
2923 }
2924 
2925 static void
2926 gnc_plugin_page_register_cmd_cancel_transaction (GSimpleAction *simple,
2927  GVariant *paramter,
2928  gpointer user_data)
2929 {
2930  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2932 
2933  ENTER ("(action %p, page %p)", simple, page);
2934 
2935  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2936 
2937  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2939  (gnc_ledger_display_get_split_register (priv->ledger));
2940  LEAVE (" ");
2941 }
2942 
2943 static void
2944 gnc_plugin_page_register_cmd_delete_transaction (GSimpleAction *simple,
2945  GVariant *paramter,
2946  gpointer user_data)
2947 {
2948  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2950 
2951  ENTER ("(action %p, page %p)", simple, page);
2952 
2953  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2954 
2955  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2956  gsr_default_delete_handler (priv->gsr, NULL);
2957  LEAVE (" ");
2958 
2959 }
2960 
2961 static void
2962 gnc_plugin_page_register_cmd_linked_transaction (GSimpleAction *simple,
2963  GVariant *paramter,
2964  gpointer user_data)
2965 {
2966  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2968 
2969  ENTER ("(action %p, page %p)", simple, page);
2970 
2971  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2972 
2973  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2974  gsr_default_doclink_handler (priv->gsr);
2975  gnc_plugin_page_register_ui_update (NULL, page);
2976  LEAVE (" ");
2977 }
2978 
2979 static void
2980 gnc_plugin_page_register_cmd_linked_transaction_open (GSimpleAction *simple,
2981  GVariant *paramter,
2982  gpointer user_data)
2983 {
2984  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
2986 
2987  ENTER ("(action %p, page %p)", simple, page);
2988 
2989  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
2990 
2991  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
2992  gsr_default_doclink_open_handler (priv->gsr);
2993  LEAVE (" ");
2994 }
2995 
2996 static GncInvoice*
2997 invoice_from_split (Split* split)
2998 {
2999  GncInvoice* invoice;
3000  GNCLot* lot;
3001 
3002  if (!split)
3003  return NULL;
3004 
3005  lot = xaccSplitGetLot (split);
3006  if (!lot)
3007  return NULL;
3008 
3009  invoice = gncInvoiceGetInvoiceFromLot (lot);
3010  if (!invoice)
3011  return NULL;
3012 
3013  return invoice;
3014 }
3015 
3016 
3017 static void
3018 gnc_plugin_page_register_cmd_jump_linked_invoice (GSimpleAction *simple,
3019  GVariant *paramter,
3020  gpointer user_data)
3021 {
3022  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3024  SplitRegister* reg;
3025  GncInvoice* invoice;
3026  Transaction *txn;
3027  GtkWidget *window;
3028 
3029  ENTER ("(action %p, page %p)", simple, page);
3030 
3031  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3032  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3033  reg = gnc_ledger_display_get_split_register (priv->gsr->ledger);
3035  invoice = invoice_from_split (gnc_split_register_get_current_split (reg));
3036  window = GNC_PLUGIN_PAGE(page)->window;
3037 
3038  if (!invoice)
3039  {
3040  auto invoices = invoices_from_transaction (txn);
3041  if (invoices.empty())
3042  PERR ("shouldn't happen: if no invoices, function is never called");
3043  else if (invoices.size() == 1)
3044  invoice = invoices[0];
3045  else
3046  {
3047  GList *details = NULL;
3048  gint choice;
3049  const gchar *amt;
3050  for (const auto& inv : invoices)
3051  {
3052  gchar *date = qof_print_date (gncInvoiceGetDatePosted (inv));
3053  amt = xaccPrintAmount
3054  (gncInvoiceGetTotal (inv),
3055  gnc_account_print_info (gncInvoiceGetPostedAcc (inv), TRUE));
3056  details = g_list_prepend
3057  (details,
3058  /* Translators: %s refer to the following in
3059  order: invoice type, invoice ID, owner name,
3060  posted date, amount */
3061  g_strdup_printf (_("%s %s from %s, posted %s, amount %s"),
3062  gncInvoiceGetTypeString (inv),
3063  gncInvoiceGetID (inv),
3064  gncOwnerGetName (gncInvoiceGetOwner (inv)),
3065  date, amt));
3066  g_free (date);
3067  }
3068  details = g_list_reverse (details);
3069  choice = gnc_choose_radio_option_dialog
3070  (window, _("Select Business Item"),
3071  _("Several business items are linked with this transaction. \
3072 Please choose one:"), _("Select"), 0, details);
3073  if ((choice >= 0) && ((size_t)choice < invoices.size()))
3074  invoice = invoices[choice];
3075  g_list_free_full (details, g_free);
3076  }
3077  }
3078 
3079  if (invoice)
3080  {
3081  GtkWindow *gtk_window = gnc_window_get_gtk_window (GNC_WINDOW (window));
3082  gnc_ui_invoice_edit (gtk_window, invoice);
3083  }
3084 
3085  LEAVE (" ");
3086 }
3087 
3088 static void
3089 gnc_plugin_page_register_cmd_blank_transaction (GSimpleAction *simple,
3090  GVariant *paramter,
3091  gpointer user_data)
3092 {
3093  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3095  SplitRegister* reg;
3096 
3097  ENTER ("(action %p, page %p)", simple, page);
3098 
3099  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3100 
3101  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3102  reg = gnc_ledger_display_get_split_register (priv->ledger);
3103 
3104  if (gnc_split_register_save (reg, TRUE))
3106 
3107  gnc_split_reg_jump_to_blank (priv->gsr);
3108  LEAVE (" ");
3109 }
3110 
3111 static bool
3112 find_after_date (Split *split, time64* find_date)
3113 {
3114  auto trans = xaccSplitGetParent (split);
3115  return !(xaccSplitGetAccount (split) != nullptr &&
3116  xaccTransGetDate (trans) >= *find_date &&
3117  xaccTransCountSplits (trans) != 1);
3118 }
3119 
3120 static void
3121 gnc_plugin_page_register_cmd_goto_date (GSimpleAction *simple,
3122  GVariant *paramter,
3123  gpointer user_data)
3124 {
3125  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3126  GNCSplitReg* gsr;
3127  Query* query;
3128  GList *splits;
3129  GtkWidget *window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
3130 
3131  ENTER ("(action %p, page %p)", simple, page);
3132  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3133 
3134  auto date = input_date (window, _("Go to Date"), _("Go to Date"));
3135 
3136  if (!date)
3137  {
3138  LEAVE ("goto_date cancelled");
3139  return;
3140  }
3141 
3142  gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE (page));
3143  query = gnc_plugin_page_register_get_query (GNC_PLUGIN_PAGE (page));
3144  splits = g_list_copy (qof_query_run (query));
3145  splits = g_list_sort (splits, (GCompareFunc)xaccSplitOrder);
3146 
3147  // if gl register, there could be blank splits from other open registers
3148  // included in split list so check for and ignore them
3149  auto it = g_list_find_custom (splits, &date.value(), (GCompareFunc)find_after_date);
3150 
3151  if (it)
3152  gnc_split_reg_jump_to_split (gsr, GNC_SPLIT(it->data));
3153  else
3154  gnc_split_reg_jump_to_blank (gsr);
3155 
3156  g_list_free (splits);
3157  LEAVE (" ");
3158 }
3159 
3160 static void
3161 gnc_plugin_page_register_cmd_duplicate_transaction (GSimpleAction *simple,
3162  GVariant *paramter,
3163  gpointer user_data)
3164 {
3165  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3167 
3168  ENTER ("(action %p, page %p)", simple, page);
3169 
3170  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3171 
3172  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3174  (gnc_ledger_display_get_split_register (priv->ledger));
3175  LEAVE (" ");
3176 }
3177 
3178 static void
3179 gnc_plugin_page_register_cmd_reinitialize_transaction (GSimpleAction *simple,
3180  GVariant *paramter,
3181  gpointer user_data)
3182 {
3183  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3185 
3186  ENTER ("(action %p, page %p)", simple, page);
3187 
3188  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3189 
3190  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3191  gsr_default_reinit_handler (priv->gsr, NULL);
3192  LEAVE (" ");
3193 }
3194 
3195 static void
3196 gnc_plugin_page_register_cmd_expand_transaction (GSimpleAction *simple,
3197  GVariant *parameter,
3198  gpointer user_data)
3199 {
3200  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3202  SplitRegister* reg;
3203  gboolean expand;
3204  GVariant *state;
3205 
3206  ENTER ("(action %p, page %p)", simple, page);
3207 
3208  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3209 
3210  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3211  reg = gnc_ledger_display_get_split_register (priv->ledger);
3212 
3213  state = g_action_get_state (G_ACTION(simple));
3214 
3215  g_action_change_state (G_ACTION(simple), g_variant_new_boolean (!g_variant_get_boolean (state)));
3216 
3217  expand = !g_variant_get_boolean (state);
3218 
3220  g_variant_unref (state);
3221  LEAVE (" ");
3222 }
3223 
3226 static void
3227 gnc_plugin_page_register_cmd_exchange_rate (GSimpleAction *simple,
3228  GVariant *paramter,
3229  gpointer user_data)
3230 {
3231  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3233  SplitRegister* reg;
3234 
3235  ENTER ("(action %p, page %p)", simple, page);
3236 
3237  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3238 
3239  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3240  reg = gnc_ledger_display_get_split_register (priv->ledger);
3241 
3242  /* XXX Ignore the return value -- we don't care if this succeeds */
3243  (void)gnc_split_register_handle_exchange (reg, TRUE);
3244  LEAVE (" ");
3245 }
3246 
3247 static Split*
3248 jump_multiple_splits_by_single_account (Account *account, Split *split)
3249 {
3250  Transaction *trans;
3251  SplitList *splits;
3252  Account *other_account = NULL;
3253  Split *other_split = NULL;
3254 
3255  trans = xaccSplitGetParent(split);
3256  if (!trans)
3257  return NULL;
3258 
3259  for (splits = xaccTransGetSplitList(trans); splits; splits = splits->next)
3260  {
3261  Split *s = (Split*)splits->data;
3262  Account *a = xaccSplitGetAccount(s);
3263 
3264  if (!xaccTransStillHasSplit(trans, s))
3265  continue;
3266 
3267  if (a == account)
3268  continue;
3269 
3270  if (other_split)
3271  {
3272  if (other_account != a)
3273  return NULL;
3274 
3275  continue;
3276  }
3277 
3278  other_account = a;
3279  other_split = s;
3280  }
3281 
3282  // Jump to the same account so that the right warning is triggered
3283  if (!other_split)
3284  other_split = split;
3285 
3286  return other_split;
3287 }
3288 
3289 static Split*
3290 jump_multiple_splits_by_value (Account *account, Split *split, gboolean largest)
3291 {
3292  Transaction *trans;
3293  SplitList *splits;
3294  Split *other_split = NULL;
3295  gnc_numeric best;
3296  int cmp = largest ? 1 : -1;
3297 
3298  trans = xaccSplitGetParent(split);
3299  if (!trans)
3300  return NULL;
3301 
3302  for (splits = xaccTransGetSplitList(trans); splits; splits = splits->next)
3303  {
3304  Split *s = (Split*)splits->data;
3305  gnc_numeric value;
3306 
3307  if (!xaccTransStillHasSplit(trans, s))
3308  continue;
3309 
3310  if (xaccSplitGetAccount(s) == account)
3311  continue;
3312 
3313  value = gnc_numeric_abs(xaccSplitGetValue(s));
3314  if (gnc_numeric_check(value))
3315  continue;
3316 
3317  /* For splits with the same value as the best, the first split
3318  * encountered is used.
3319  */
3320  if (other_split && gnc_numeric_compare(value, best) != cmp)
3321  continue;
3322 
3323  best = value;
3324  other_split = s;
3325  }
3326 
3327  // Jump to the same account so that the right warning is triggered
3328  if (!other_split)
3329  other_split = split;
3330 
3331  return other_split;
3332 }
3333 
3334 static Split*
3335 jump_multiple_splits (Account* account, Split *split)
3336 {
3337  GncPrefJumpMultSplits mode = (GncPrefJumpMultSplits)gnc_prefs_get_enum(GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_JUMP_MULT_SPLITS);
3338 
3339  switch (mode)
3340  {
3341  case JUMP_LARGEST_VALUE_FIRST_SPLIT:
3342  return jump_multiple_splits_by_value (account, split, TRUE);
3343 
3344  case JUMP_SMALLEST_VALUE_FIRST_SPLIT:
3345  return jump_multiple_splits_by_value (account, split, FALSE);
3346 
3347  case JUMP_DEFAULT:
3348  default:
3349  break;
3350  }
3351 
3352  // If there's only one other account, use that one
3353  return jump_multiple_splits_by_single_account (account, split);
3354 }
3355 
3356 static void
3357 gnc_plugin_page_register_cmd_jump (GSimpleAction *simple,
3358  GVariant *paramter,
3359  gpointer user_data)
3360 {
3361  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3363  GncPluginPage* new_plugin_page;
3364  GtkWidget* window;
3365  GNCSplitReg* gsr;
3366  SplitRegister* reg;
3367  Account* account;
3368  Account* leader;
3369  Split* split;
3370  Split* other_split;
3371  gboolean multiple_splits;
3372 
3373  ENTER ("(action %p, page %p)", simple, page);
3374 
3375  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3376 
3377  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3378  window = GNC_PLUGIN_PAGE (page)->window;
3379  if (window == NULL)
3380  {
3381  LEAVE ("no window");
3382  return;
3383  }
3384 
3385  reg = gnc_ledger_display_get_split_register (priv->ledger);
3387  if (split == NULL)
3388  {
3389  LEAVE ("no split (1)");
3390  return;
3391  }
3392 
3393  account = xaccSplitGetAccount (split);
3394  if (account == NULL)
3395  {
3396  LEAVE ("no account");
3397  return;
3398  }
3399 
3400  other_split = xaccSplitGetOtherSplit (split);
3401  multiple_splits = other_split == NULL;
3402 
3403  leader = gnc_ledger_display_leader (priv->ledger);
3404  if (account == leader)
3405  {
3407  if (cursor_class == CURSOR_CLASS_SPLIT)
3408  {
3409  /* If you've selected the transaction itself, we jump to the "other"
3410  * account corresponding to the anchoring split.
3411  *
3412  * If you've selected the split for another account, we jump to that
3413  * split's account (account != leader, so this block is never
3414  * reached).
3415  *
3416  * If you've selected a split for this account, for consistency with
3417  * selecting the split of another account we should do nothing.
3418  * You're already on the account for the split you selected. Jumping
3419  * to the "other" account now would make the "multiple split"
3420  * options confusing.
3421  *
3422  * We could jump to a different anchoring split but that'll be very
3423  * subtle and only cause problems because it'll have to save any
3424  * modifications to the current register.
3425  */
3426  LEAVE ("split for this account");
3427  return;
3428  }
3429 
3430  if (multiple_splits)
3431  {
3432  other_split = jump_multiple_splits (account, split);
3433  }
3434  if (other_split == NULL)
3435  {
3436  GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(window),
3437  (GtkDialogFlags)(GTK_DIALOG_MODAL
3438  | GTK_DIALOG_DESTROY_WITH_PARENT),
3439  GTK_MESSAGE_ERROR,
3440  GTK_BUTTONS_NONE,
3441  "%s",
3442  _("Unable to jump to other account"));
3443 
3444  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
3445  "%s", _("This transaction involves more than one other account. Select a specific split to jump to that account."));
3446  gtk_dialog_add_button (GTK_DIALOG(dialog), _("_OK"), GTK_RESPONSE_OK);
3447  gnc_dialog_run (GTK_DIALOG(dialog), GNC_PREF_WARN_REG_TRANS_JUMP_MULTIPLE_SPLITS);
3448  gtk_widget_destroy (dialog);
3449 
3450  LEAVE ("no split (2)");
3451  return;
3452  }
3453 
3454  split = other_split;
3455 
3456  account = xaccSplitGetAccount (split);
3457  if (account == NULL)
3458  {
3459  LEAVE ("no account (2)");
3460  return;
3461  }
3462 
3463  if (account == leader)
3464  {
3465  GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(window),
3466  (GtkDialogFlags)(GTK_DIALOG_MODAL
3467  | GTK_DIALOG_DESTROY_WITH_PARENT),
3468  GTK_MESSAGE_ERROR,
3469  GTK_BUTTONS_NONE,
3470  "%s",
3471  _("Unable to jump to other account"));
3472 
3473  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
3474  "%s", _("This transaction only involves the current account so there is no other account to jump to."));
3475  gtk_dialog_add_button (GTK_DIALOG(dialog), _("_OK"), GTK_RESPONSE_OK);
3476  gnc_dialog_run (GTK_DIALOG(dialog), GNC_PREF_WARN_REG_TRANS_JUMP_SINGLE_ACCOUNT);
3477  gtk_widget_destroy (dialog);
3478 
3479  LEAVE ("register open for account");
3480  return;
3481  }
3482  }
3483 
3484  new_plugin_page = gnc_plugin_page_register_new (account, FALSE);
3485  if (new_plugin_page == NULL)
3486  {
3487  LEAVE ("couldn't create new page");
3488  return;
3489  }
3490 
3491  gnc_main_window_open_page (GNC_MAIN_WINDOW (window), new_plugin_page);
3492  gsr = gnc_plugin_page_register_get_gsr (new_plugin_page);
3493 
3494  SplitRegister *new_page_reg = gnc_ledger_display_get_split_register (gsr->ledger);
3495  gboolean jump_twice = FALSE;
3496 
3497  /* Selecting the split (instead of just the transaction to open the "other"
3498  * account) requires jumping a second time after expanding the transaction,
3499  * in the basic and auto ledger modes.
3500  */
3501  if (new_page_reg->style != REG_STYLE_JOURNAL)
3502  jump_twice = TRUE;
3503 
3504  /* Test for visibility of split */
3505  if (gnc_split_reg_clear_filter_for_split (gsr, split))
3506  gnc_plugin_page_register_clear_current_filter (GNC_PLUGIN_PAGE(new_plugin_page));
3507 
3508  gnc_split_reg_jump_to_split (gsr, split);
3509 
3510  if (multiple_splits && jump_twice)
3511  {
3512  /* Expand the transaction for the basic and auto ledger to identify the
3513  * split in this register, but only if there are more than two splits.
3514  */
3515  gnc_split_register_expand_current_trans (new_page_reg, TRUE);
3516  gnc_split_reg_jump_to_split (gsr, split);
3517  }
3518  LEAVE (" ");
3519 }
3520 
3521 static void
3522 gnc_plugin_page_register_cmd_schedule (GSimpleAction *simple,
3523  GVariant *paramter,
3524  gpointer user_data)
3525 {
3526  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3528  GtkWindow* window;
3529 
3530  ENTER ("(action %p, page %p)", simple, page);
3531 
3532  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3533 
3534  window = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (
3535  page)));
3536  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3537  gsr_default_schedule_handler (priv->gsr, window);
3538  LEAVE (" ");
3539 }
3540 
3541 static void
3542 scrub_split (Split *split)
3543 {
3544  Account *acct;
3545  Transaction *trans;
3546  GNCLot *lot;
3547 
3548  g_return_if_fail (split);
3549  acct = xaccSplitGetAccount (split);
3550  trans = xaccSplitGetParent (split);
3551  lot = xaccSplitGetLot (split);
3552  g_return_if_fail (trans);
3553 
3554  xaccTransScrubOrphans (trans);
3555  xaccTransScrubImbalance (trans, gnc_get_current_root_account(), NULL);
3556  if (lot && xaccAccountIsAPARType (xaccAccountGetType (acct)))
3557  {
3558  gncScrubBusinessLot (lot);
3559  gncScrubBusinessSplit (split);
3560  }
3561 }
3562 
3563 static void
3564 gnc_plugin_page_register_cmd_scrub_current (GSimpleAction *simple,
3565  GVariant *paramter,
3566  gpointer user_data)
3567 {
3568  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3570  Query* query;
3571  SplitRegister* reg;
3572 
3573  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3574 
3575  ENTER ("(action %p, page %p)", simple, page);
3576 
3577  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3578  query = gnc_ledger_display_get_query (priv->ledger);
3579  if (query == NULL)
3580  {
3581  LEAVE ("no query found");
3582  return;
3583  }
3584 
3585  reg = gnc_ledger_display_get_split_register (priv->ledger);
3586 
3587  gnc_suspend_gui_refresh();
3588  scrub_split (gnc_split_register_get_current_split (reg));
3589  gnc_resume_gui_refresh();
3590  LEAVE (" ");
3591 }
3592 
3593 static gboolean
3594 scrub_kp_handler (GtkWidget *widget, GdkEventKey *event, gpointer data)
3595 {
3596  if (event->length == 0) return FALSE;
3597 
3598  switch (event->keyval)
3599  {
3600  case GDK_KEY_Escape:
3601  {
3602  auto abort_scrub = gnc_verify_dialog (GTK_WINDOW(widget), false,
3603  "%s", _(check_repair_abort_YN));
3604 
3605  if (abort_scrub)
3606  gnc_set_abort_scrub (TRUE);
3607 
3608  return TRUE;
3609  }
3610  default:
3611  break;
3612  }
3613  return FALSE;
3614 }
3615 
3616 static void
3617 gnc_plugin_page_register_cmd_scrub_all (GSimpleAction *simple,
3618  GVariant *paramter,
3619  gpointer user_data)
3620 {
3621  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3623  Query* query;
3624  GncWindow* window;
3625  GList* node, *splits;
3626  gint split_count = 0, curr_split_no = 0;
3627  gulong scrub_kp_handler_ID;
3628  const char* message = _ ("Checking splits in current register: %u of %u");
3629 
3630  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3631 
3632  ENTER ("(action %p, page %p)", simple, page);
3633 
3634  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3635  query = gnc_ledger_display_get_query (priv->ledger);
3636  if (!query)
3637  {
3638  LEAVE ("no query found");
3639  return;
3640  }
3641 
3642  gnc_suspend_gui_refresh();
3643  is_scrubbing = TRUE;
3644  gnc_set_abort_scrub (FALSE);
3645  window = GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window);
3646  scrub_kp_handler_ID = g_signal_connect (G_OBJECT (window), "key-press-event",
3647  G_CALLBACK (scrub_kp_handler), NULL);
3648  gnc_window_set_progressbar_window (window);
3649 
3650  splits = qof_query_run (query);
3651  split_count = g_list_length (splits);
3652  for (node = splits; node && !gnc_get_abort_scrub (); node = node->next, curr_split_no++)
3653  {
3654  auto split = GNC_SPLIT(node->data);
3655 
3656  if (!split) continue;
3657 
3658  PINFO ("Start processing split %d of %d",
3659  curr_split_no + 1, split_count);
3660 
3661  scrub_split (split);
3662 
3663  PINFO ("Finished processing split %d of %d",
3664  curr_split_no + 1, split_count);
3665 
3666  if (curr_split_no % 10 == 0)
3667  {
3668  char* progress_msg = g_strdup_printf (message, curr_split_no, split_count);
3669  gnc_window_show_progress (progress_msg, (100 * curr_split_no) / split_count);
3670  g_free (progress_msg);
3671  }
3672  }
3673 
3674  g_signal_handler_disconnect (G_OBJECT(window), scrub_kp_handler_ID);
3675  gnc_window_show_progress (NULL, -1.0);
3676  is_scrubbing = FALSE;
3677  show_abort_verify = TRUE;
3678  gnc_set_abort_scrub (FALSE);
3679 
3680  gnc_resume_gui_refresh();
3681  LEAVE (" ");
3682 }
3683 
3684 static void
3685 gnc_plugin_page_register_cmd_account_report (GSimpleAction *simple,
3686  GVariant *paramter,
3687  gpointer user_data)
3688 {
3689  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3691  GncMainWindow* window;
3692  int id;
3693 
3694  ENTER ("(action %p, page %p)", simple, page);
3695 
3696  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3697 
3698  window = GNC_MAIN_WINDOW (GNC_PLUGIN_PAGE (page)->window);
3699  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3700  id = report_helper (priv->ledger, NULL, NULL);
3701  if (id >= 0)
3702  gnc_main_window_open_report (id, window);
3703  LEAVE (" ");
3704 }
3705 
3706 static void
3707 gnc_plugin_page_register_cmd_transaction_report (GSimpleAction *simple,
3708  GVariant *paramter,
3709  gpointer user_data)
3710 {
3711  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3713  GncMainWindow* window;
3714  SplitRegister* reg;
3715  Split* split;
3716  Query* query;
3717  int id;
3718 
3719 
3720  ENTER ("(action %p, page %p)", simple, page);
3721 
3722  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3723 
3724  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3725  reg = gnc_ledger_display_get_split_register (priv->ledger);
3726 
3728  if (!split)
3729  return;
3730 
3731  query = qof_query_create_for (GNC_ID_SPLIT);
3732 
3733  qof_query_set_book (query, gnc_get_current_book());
3734 
3735  xaccQueryAddGUIDMatch (query, xaccSplitGetGUID (split),
3736  GNC_ID_SPLIT, QOF_QUERY_AND);
3737 
3738  window = GNC_MAIN_WINDOW (GNC_PLUGIN_PAGE (page)->window);
3739  id = report_helper (priv->ledger, split, query);
3740  if (id >= 0)
3741  gnc_main_window_open_report (id, window);
3742  LEAVE (" ");
3743 }
3744 
3745 /************************************************************/
3746 /* Auxiliary functions */
3747 /************************************************************/
3748 
3749 void
3751  gint lines_default,
3752  gboolean read_only)
3753 {
3754  GncPluginPageRegister* page;
3756 
3757  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page));
3758 
3759  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
3760  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3761  priv->lines_default = lines_default;
3762  priv->read_only = read_only;
3763 }
3764 
3765 GNCSplitReg*
3767 {
3768  GncPluginPageRegister* page;
3770 
3771  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page), NULL);
3772 
3773  page = GNC_PLUGIN_PAGE_REGISTER (plugin_page);
3774  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3775 
3776  return priv->gsr;
3777 }
3778 
3779 FilterData *
3781 {
3782  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page), NULL);
3783 
3784  GncPluginPageRegister* page = GNC_PLUGIN_PAGE_REGISTER(plugin_page);
3785  GncPluginPageRegisterPrivate* priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
3786 
3787  return &priv->fd;
3788 }
3789 
3790 SortData *
3792 {
3793  g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page), NULL);
3794 
3795  GncPluginPageRegister* page = GNC_PLUGIN_PAGE_REGISTER(plugin_page);
3796  GncPluginPageRegisterPrivate* priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
3797 
3798  return &priv->sd;
3799 }
3800 
3801 static void
3802 gnc_plugin_page_help_changed_cb (GNCSplitReg* gsr,
3803  GncPluginPageRegister* page)
3804 {
3806  SplitRegister* reg;
3807  GncWindow* window;
3808  char* help;
3809 
3810  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3811 
3812  window = GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window);
3813  if (!window)
3814  {
3815  // This routine can be called before the page is added to a
3816  // window.
3817  return;
3818  }
3819 
3820  // only update status text if on current page
3821  if (GNC_IS_MAIN_WINDOW(window) && (gnc_main_window_get_current_page
3822  (GNC_MAIN_WINDOW(window)) != GNC_PLUGIN_PAGE(page)))
3823  return;
3824 
3825  /* Get the text from the ledger */
3826  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3827  reg = gnc_ledger_display_get_split_register (priv->ledger);
3828  help = gnc_table_get_help (reg->table);
3829  gnc_window_set_status (window, GNC_PLUGIN_PAGE (page), help);
3830  g_free (help);
3831 }
3832 
3833 static void
3834 gnc_plugin_page_popup_menu_cb (GNCSplitReg* gsr,
3835  GncPluginPageRegister* page)
3836 {
3837  GncWindow* window;
3838 
3839  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3840 
3841  window = GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window);
3842  if (!window)
3843  {
3844  // This routine can be called before the page is added to a
3845  // window.
3846  return;
3847  }
3848  gnc_main_window_popup_menu_cb (GTK_WIDGET (window),
3849  GNC_PLUGIN_PAGE (page));
3850 }
3851 
3852 static void
3853 gnc_plugin_page_register_refresh_cb (GHashTable* changes, gpointer user_data)
3854 {
3855  auto page = GNC_PLUGIN_PAGE_REGISTER(user_data);
3857 
3858  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (page));
3859  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3860 
3861  if (changes)
3862  {
3863  const EventInfo* ei;
3864  ei = gnc_gui_get_entity_events (changes, &priv->key);
3865  if (ei)
3866  {
3867  if (ei->event_mask & QOF_EVENT_DESTROY)
3868  {
3869  gnc_main_window_close_page (GNC_PLUGIN_PAGE (page));
3870  return;
3871  }
3872  if (ei->event_mask & QOF_EVENT_MODIFY)
3873  {
3874  }
3875  }
3876  }
3877  else
3878  {
3879  /* forced updates */
3880  gnucash_register_refresh_from_prefs (priv->gsr->reg);
3881  gtk_widget_queue_draw (priv->widget);
3882  }
3883 
3884  gnc_plugin_page_register_ui_update (NULL, page);
3885 }
3886 
3887 static void
3888 gnc_plugin_page_register_close_cb (gpointer user_data)
3889 {
3890  GncPluginPage* plugin_page = GNC_PLUGIN_PAGE (user_data);
3891  gnc_main_window_close_page (plugin_page);
3892 }
3893 
3902 static void
3903 gppr_account_destroy_cb (Account* account)
3904 {
3905  GncPluginPageRegister* page;
3907  GNCLedgerDisplayType ledger_type;
3908  const GncGUID* acct_guid;
3909  const GList* citem;
3910  GList* item, *kill = NULL;
3911 
3912  acct_guid = xaccAccountGetGUID (account);
3913 
3914  /* Find all windows that need to be killed. Don't kill them yet, as
3915  * that would affect the list being walked.*/
3916  citem = gnc_gobject_tracking_get_list (GNC_PLUGIN_PAGE_REGISTER_NAME);
3917  for (; citem; citem = g_list_next (citem))
3918  {
3919  page = (GncPluginPageRegister*)citem->data;
3920  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3921  ledger_type = gnc_ledger_display_type (priv->ledger);
3922  if (ledger_type == LD_GL)
3923  {
3924  kill = g_list_prepend (kill, page);
3925  /* kill it */
3926  }
3927  else if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
3928  {
3929  if (guid_compare (acct_guid, &priv->key) == 0)
3930  {
3931  kill = g_list_prepend (kill, page);
3932  }
3933  }
3934  }
3935 
3936  kill = g_list_reverse (kill);
3937  /* Now kill them. */
3938  for (item = kill; item; item = g_list_next (item))
3939  {
3940  page = (GncPluginPageRegister*)item->data;
3941  gnc_main_window_close_page (GNC_PLUGIN_PAGE (page));
3942  }
3943  g_list_free (kill);
3944 }
3945 
3960 static void
3961 gnc_plugin_page_register_event_handler (QofInstance* entity,
3962  QofEventId event_type,
3963  GncPluginPageRegister* page,
3964  GncEventData* ed)
3965 {
3966  Transaction* trans;
3967  QofBook* book;
3968  GncPluginPage* visable_plugin_page;
3969  GtkWidget* window;
3970 
3971  g_return_if_fail (page); /* Required */
3972  if (!GNC_IS_TRANS (entity) && !GNC_IS_ACCOUNT (entity))
3973  return;
3974 
3975  ENTER ("entity %p of type %d, page %p, event data %p",
3976  entity, event_type, page, ed);
3977 
3978  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page));
3979 
3980  if (GNC_IS_ACCOUNT (entity))
3981  {
3982  if (GNC_IS_MAIN_WINDOW (window))
3983  {
3984  GncPluginPageRegisterPrivate *priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
3985 
3986  if (!gnc_ledger_display_leader (priv->ledger))
3987  {
3988  LEAVE ("account is NULL");
3989  return;
3990  }
3991 
3992  gchar *name = gnc_plugin_page_register_get_tab_name (GNC_PLUGIN_PAGE (page));
3993  main_window_update_page_name (GNC_PLUGIN_PAGE (page), name);
3994 
3995  gchar *long_name = gnc_plugin_page_register_get_long_name (GNC_PLUGIN_PAGE (page));
3996  main_window_update_page_long_name (GNC_PLUGIN_PAGE (page), long_name);
3997 
3998  gchar *color = gnc_plugin_page_register_get_tab_color (GNC_PLUGIN_PAGE (page));
3999  main_window_update_page_color (GNC_PLUGIN_PAGE (page), color);
4000  // update page icon if read only registers
4001  gnc_plugin_page_register_update_page_icon (GNC_PLUGIN_PAGE (page));
4002 
4003  g_free (color);
4004  g_free (name);
4005  g_free (long_name);
4006  }
4007  LEAVE ("tab contents updated");
4008  return;
4009  }
4010 
4011  if (! (event_type & (QOF_EVENT_MODIFY | QOF_EVENT_DESTROY)))
4012  {
4013  LEAVE ("not a modify");
4014  return;
4015  }
4016  trans = GNC_TRANS (entity);
4017  book = qof_instance_get_book (QOF_INSTANCE (trans));
4018  if (!gnc_plugin_page_has_book (GNC_PLUGIN_PAGE (page), book))
4019  {
4020  LEAVE ("not in this book");
4021  return;
4022  }
4023 
4024  if (GNC_IS_MAIN_WINDOW (window))
4025  {
4026  visable_plugin_page = gnc_main_window_get_current_page (GNC_MAIN_WINDOW (window));
4027  if (visable_plugin_page != GNC_PLUGIN_PAGE (page))
4028  {
4029  LEAVE ("page not visible");
4030  return;
4031  }
4032  }
4033 
4034  gnc_plugin_page_register_ui_update (NULL, page);
4035  LEAVE (" ");
4036  return;
4037 }
4038 
4039 
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register&#39;s current cursor.
Split * gnc_split_register_get_current_trans_split(SplitRegister *reg, VirtualCellLocation *trans_split_loc)
Gets the anchoring split of the transaction at the current cursor location, which may be on the trans...
void gnc_ledger_display_close(GNCLedgerDisplay *ld)
close the window
GncPluginPage * gnc_plugin_page_register_new(Account *account, gboolean subaccounts)
Create a new "register" plugin page, given a pointer to an account.
void gnc_ledger_display_set_focus(GNCLedgerDisplay *ld, gboolean focus)
Mark the ledger as being in focus (refresh immediately) or not.
Functions to load, save and get gui state.
gint xaccSplitOrder(const Split *sa, const Split *sb)
The xaccSplitOrder(sa,sb) method is useful for sorting.
Definition: Split.cpp:1500
GtkWidget * gnc_plugin_page_get_window(GncPluginPage *page)
Retrieve a pointer to the GncMainWindow (GtkWindow) containing this page.
gboolean xaccTransHasReconciledSplits(const Transaction *trans)
FIXME: document me.
void gnc_ledger_display_refresh(GNCLedgerDisplay *ld)
redisplay/redraw only the indicated window.
const gchar * tab_icon
The relative name of the icon that should be shown on the tab for this page.
const char * gnc_split_register_get_credit_string(SplitRegister *reg)
Return the credit string used in the register.
gboolean(* focus_page_function)(GncPluginPage *plugin_page)
This function performs specific actions to set the focus on a specific widget.
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
void gnc_plugin_register_set_enable_refresh(GncPluginPageRegister *page, gboolean enable_refresh)
This allows controlling when refreshes happen, used to reduce refreshes when different aspects of the...
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.
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.
gboolean xaccTransIsReadonlyByPostedDate(const Transaction *trans)
Returns TRUE if this Transaction is read-only because its posted-date is older than the "auto-readonl...
Date and Time handling routines.
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Register a callback that gets triggered when the given preference changes.
Definition: gnc-prefs.cpp:127
gboolean gnc_split_register_save(SplitRegister *reg, gboolean do_commit)
Copy the contents of the current cursor to a split.
This file contains the functions to present a gui to the user for creating a new account or editing a...
void gnc_split_register_unvoid_current_trans(SplitRegister *reg)
Unvoids the transaction associated with the current cursor, if non-NULL.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.cpp:4510
void(* QofEventHandler)(QofInstance *ent, QofEventId event_type, gpointer handler_data, gpointer event_data)
Handler invoked when an event is generated.
Definition: qofevent.h:89
void gnc_split_register_expand_current_trans(SplitRegister *reg, gboolean expand)
Expand the current transaction if it is collapsed.
utility functions for the GnuCash UI
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
void gnc_main_window_set_vis_of_items_by_action(GncMainWindow *window, const gchar **action_names, gboolean vis)
Show or hide menu and toolbar items based on a NULL terminated list of action names.
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3241
Transaction * gnc_split_register_get_current_trans(SplitRegister *reg)
Gets the transaction at the current cursor location, which may be on the transaction itself or on any...
gtk helper routines.
GncPluginPage *(* recreate_page)(GtkWidget *window, GKeyFile *file, const gchar *group)
Create a new page based on the information saved during a previous instantiation of gnucash...
FilterData * gnc_plugin_page_register_get_filter_data(GncPluginPage *plugin_page)
Get the FilterData data structure associated with this register page.
gboolean gnc_menubar_model_find_item(GMenuModel *menu_model, GncMenuModelSearch *gsm)
Find a GtkMenu item from the action name.
STRUCTS.
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
gboolean string_to_guid(const gchar *string, GncGUID *guid)
Given a string, replace the given guid with the parsed one unless the given value is null...
Functions that are supported by all types of windows.
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
GSimpleActionGroup * gnc_plugin_page_get_action_group(GncPluginPage *page)
Retrieve the GSimpleActionGroup object associated with this page.
gpointer gnc_account_foreach_descendant_until(const Account *acc, AccountCb2 thunk, gpointer user_data)
This method will traverse all children of this accounts and their descendants, calling &#39;func&#39; on each...
Definition: Account.cpp:3218
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
void gnc_plugin_add_toolbar_tooltip_callbacks(GtkWidget *toolbar, GtkWidget *statusbar)
This function adds the tooltip callbacks to make the tooltips appear in the status bar...
Definition: gnc-plugin.c:299
QofQuery * qof_query_copy(QofQuery *q)
Make a copy of the indicated query.
Definition: qofquery.cpp:1018
gboolean qof_query_equal(const QofQuery *q1, const QofQuery *q2)
Compare two queries for equality.
Definition: qofquery.cpp:1472
GtkWidget * window
The window that contains the display widget for this plugin.
Account * gnc_ledger_display_leader(GNCLedgerDisplay *ld)
Implementations.
void gnc_plugin_page_set_page_long_name(GncPluginPage *page, const char *name)
Set the long name of this page.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
GSimpleActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GSimpleActionGroup object associated with this page.
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition: guid.cpp:208
void gnc_ledger_display_set_query(GNCLedgerDisplay *ledger_display, Query *q)
Set the query used for a register.
gint gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
Cleanup functions for business objects.
gnc_numeric gncInvoiceGetTotal(GncInvoice *invoice)
Return the "total" amount of the invoice as seen on the document (and shown to the user in the report...
Definition: gncInvoice.c:1008
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.
const char * xaccAccountGetColor(const Account *acc)
Get the account&#39;s color.
Definition: Account.cpp:3324
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
GNCLedgerDisplay * gnc_ledger_display_subaccounts(Account *account, gboolean mismatched_commodities)
opens up a register window to display the parent account and all of its children. ...
#define xaccAccountGetGUID(X)
Definition: Account.h:252
void gnc_set_abort_scrub(gboolean abort)
The gnc_set_abort_scrub () method causes a currently running scrub operation to stop, if abort is TRUE; gnc_set_abort_scrub(FALSE) must be called before any scrubbing operation.
Definition: Scrub.cpp:75
convert single-entry accounts to clean double-entry
char * qof_print_date(time64 secs)
Convenience; calls through to qof_print_date_dmy_buff().
Definition: gnc-date.cpp:610
gboolean gnc_main_window_is_quitting(GncMainWindow *window)
Check if the main window is quitting.
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
gboolean xaccTransHasSplitsInState(const Transaction *trans, const char state)
FIXME: document me.
gboolean gnc_split_register_has_copied_item(void)
Return TRUE if copied_item holds a transaction or split.
QofBook * qof_session_get_book(const QofSession *session)
Returns the QofBook of this session.
Definition: qofsession.cpp:575
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3279
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
Functions providing a register page for the GnuCash UI.
const char * gnc_split_register_get_debit_string(SplitRegister *reg)
Return the debit string used in the register.
void main_window_update_page_color(GncPluginPage *page, const gchar *color_in)
Update the color on the page tabs in the main window.
The class data structure for a content plugin.
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
gint QofEventId
Define the type of events allowed.
Definition: qofevent.h:45
Gobject helper routines.
void gnc_plugin_page_set_use_new_window(GncPluginPage *page, gboolean use_new)
Set the "use new window" setting associated with this page.
CursorClass
Types of cursors.
GAction * gnc_main_window_find_action(GncMainWindow *window, const gchar *action_name)
Find the GAction in the main window.
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition: guid.h:84
Transaction * gnc_plugin_page_register_get_current_txn(GncPluginPageRegister *page)
Get the currently selected transaction in this register page.
gboolean gnc_split_register_changed(SplitRegister *reg)
Returns TRUE if the register has changed cells.
void xaccTransScrubImbalance(Transaction *trans, Account *root, Account *account)
Correct transaction imbalances.
Definition: Scrub.cpp:845
void gnc_plugin_page_disconnect_page_changed(GncPluginPage *page)
Disconnect the page_changed_id signal callback.
gint gnc_prefs_get_enum(const gchar *group, const gchar *pref_name)
Get an enum value from the preferences backend.
gboolean gncScrubBusinessSplit(Split *split)
The gncScrubBusinessSplit() function will fix all issues found with the given split.
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...
const gchar * plugin_name
The textual name of this plugin.
void gnc_ppr_filter_set_tooltip(GncPluginPage *plugin_page, FilterData *fd)
This function is used to update the tooltip shown in the register which shows a summary of the curren...
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.
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.
void gnc_ppr_filter_update_register(GncPluginPage *plugin_page)
This function is called to update the register.
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
The gnc_account_lookup_full_name() subroutine works like gnc_account_lookup_by_name, but uses fully-qualified names using the given separator.
Definition: Account.cpp:3137
void gnc_split_register_void_current_trans(SplitRegister *reg, const char *reason)
Voids the transaction associated with the current cursor, if non-NULL.
void gnc_ppr_filter_by(GncPluginPage *plugin_page, Query *query, FilterData *fd, bool show_save_button)
This function is called for the filter dialog.
void xaccTransScrubOrphans(Transaction *trans)
The xaccTransScrubOrphans() method scrubs only the splits in the given transaction.
Definition: Scrub.cpp:179
void gnc_plugin_set_actions_enabled(GActionMap *action_map, const gchar **action_names, gboolean enable)
This function sets the sensitivity of a GAction in a specific group.
Definition: gnc-plugin.c:250
Gnome specific utility functions.
Public declarations of GnucashRegister class.
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition: Account.cpp:4486
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
SortData * gnc_plugin_page_register_get_sort_data(GncPluginPage *plugin_page)
Get the SortData data structure associated with this register page.
Additional event handling code.
#define xaccSplitGetGUID(X)
Definition: Split.h:552
gboolean(* finish_pending)(GncPluginPage *plugin_page)
This function vector is called to finish any outstanding activities.
All type declarations for the whole Gnucash engine.
#define CREC
The Split has been cleared.
Definition: Split.h:73
void(* save_page)(GncPluginPage *page, GKeyFile *file, const gchar *group)
Save enough information about this page so that it can be recreated next time the user starts gnucash...
gnc_commodity * gnc_account_get_currency_or_parent(const Account *account)
Returns a gnc_commodity that is a currency, suitable for being a Transaction&#39;s currency.
Definition: Account.cpp:3382
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:1288
void gnc_split_register_paste_current(SplitRegister *reg)
Pastes a previous copied entity onto the current entity, but only if the copied and current entity ha...
Transaction * xaccTransReverse(Transaction *orig)
xaccTransReverse creates a Transaction that reverses the given transaction by inverting all the numer...
GList * qof_query_run(QofQuery *query)
Perform the query, return the results.
void main_window_update_page_set_read_only_icon(GncPluginPage *page, gboolean read_only)
Update the icon on the page tabs in the main window.
gboolean qof_book_is_readonly(const QofBook *book)
Return whether the book is read only.
Definition: qofbook.cpp:497
A structure for defining alternate action names for use in the toolbar.
void gnc_plugin_page_set_page_color(GncPluginPage *page, const char *color)
Set the color of this page.
GncPluginPage * gnc_plugin_page_register_new_gl(void)
Create a new "register" plugin page containing a general journal.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
GNCLedgerDisplay * gnc_ledger_display_simple(Account *account)
opens up a register window to display a single account
gboolean gncScrubBusinessLot(GNCLot *lot)
The gncScrubBusinessLot() function makes sure that the indicated lot has all the correct properties r...
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
void gnc_ppr_sort_dialog(GncPluginPage *plugin_page, SplitRegister *reg, SortData *sd, bool show_save_button)
This function is called for the sort dialog.
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3375
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:165
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void gnc_plugin_page_set_menu_popup_qualifier(GncPluginPage *page, const char *menu_qualifier)
Set a qualifier string for this page.
void gnc_plugin_page_inserted_cb(GncPluginPage *page, gpointer user_data)
Set up the page_changed callback for when the current page is changed.
void gnc_main_window_close_page(GncPluginPage *page)
Remove a data plugin page from a window and display the previous page.
Transaction * xaccTransGetReversedBy(const Transaction *trans)
Returns the transaction that reversed the given transaction.
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
void gnc_plugin_page_set_page_name(GncPluginPage *page, const char *name)
Set the name of this page.
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:262
Account * gnc_plugin_page_register_get_account(GncPluginPageRegister *page)
Get the Account associated with this register page.
void gnc_plugin_page_add_book(GncPluginPage *page, QofBook *book)
Add a book reference to the specified page.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void gnc_plugin_page_register_query_update(GncPluginPageRegister *page, Query *query)
This updates the query after the filters have been applied.
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
SplitRegister * gnc_ledger_display_get_split_register(GNCLedgerDisplay *ld)
return the split register associated with a ledger display
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3263
void gnc_plugin_page_register_update_for_search_query(GncPluginPageRegister *page)
This checks if the register is a search register and if so saves the query.
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 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.
void gnc_ppr_sort_update_register(GncPluginPage *plugin_page)
This function is called to update the register.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.
void gnc_plugin_page_register_set_options(GncPluginPage *plugin_page, gint lines_default, gboolean read_only)
Set various register options on a newly created "register" plugin page.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
GtkWidget * summarybar
The summary bar widget (if any) that is associated with this plugin.
SplitRegisterStyle
Register styles.
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn&#39;t be...
Definition: Split.cpp:1884
GList * qof_query_get_books(QofQuery *q)
Return the list of books we&#39;re using.
Definition: qofquery.cpp:1341
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
Definition: gnc-prefs.cpp:142
void gnc_split_register_copy_current(SplitRegister *reg)
Makes a copy of the current entity, either a split or a transaction, so that it can be pasted later...
Utility functions for file access.
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2048
void gnc_ppr_filter_clear_current_filter(GncPluginPage *plugin_page)
This function is used to clear the current filter so that a specific split can be shown in the regist...