GnuCash  5.6-150-g038405b370+
gnc-plugin-page-sx-list.cpp
1 /********************************************************************\
2  * gnc-plugin-page-sx-list.cpp : scheduled transaction plugin *
3  * *
4  * Copyright (C) 2006 Joshua Sled <jsled@asynchronous.org> *
5  * Copyright (C) 2011 Robert Fewell *
6  * *
7  * This program is free software; you can redistribute it and/or *
8  * modify it under the terms of version 2 and/or version 3 of the *
9  * GNU General Public License as published by the Free Software *
10  * Foundation. *
11  * *
12  * As a special exception, permission is granted to link the binary *
13  * module resultant from this code with the OpenSSL project's *
14  * "OpenSSL" library (or modified versions of it that use the same *
15  * license as the "OpenSSL" library), and distribute the linked *
16  * executable. You must obey the GNU General Public License in all *
17  * respects for all of the code used other than "OpenSSL". If you *
18  * modify this file, you may extend this exception to your version *
19  * of the file, but you are not obligated to do so. If you do not *
20  * wish to do so, delete this exception statement from your version *
21  * of this file. *
22  * *
23  * This program is distributed in the hope that it will be useful, *
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
26  * GNU General Public License for more details. *
27  * *
28  * You should have received a copy of the GNU General Public License*
29  * along with this program; if not, contact: *
30  * *
31  * Free Software Foundation Voice: +1-617-542-5942 *
32  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
33  * Boston, MA 02110-1301, USA gnu@gnu.org *
34 \********************************************************************/
35 
44 #include <config.h>
45 
46 #include <gtk/gtk.h>
47 #include <glib.h>
48 #include <glib/gi18n.h>
49 
50 #include <gnc-gobject-utils.h>
51 #include "SX-book.h"
52 #include "Split.h"
53 #include "Transaction.h"
54 #include "dialog-sx-editor.h"
55 #include "dialog-utils.h"
56 #include "dialog-sx-since-last-run.h"
57 #include "gnc-commodity.h"
58 #include "gnc-component-manager.h"
59 #include "gnc-date.h"
60 #include "gnc-dense-cal.h"
61 #include "gnc-engine.h"
62 #include "gnc-event.h"
63 #include "gnc-glib-utils.h"
64 #include "gnc-icons.h"
65 #include "gnc-main-window.h"
66 #include "gnc-plugin.h"
67 #include "gnc-plugin-page-sx-list.h"
68 #include "gnc-prefs.h"
69 #include "gnc-session.h"
70 #include "gnc-sx-instance-dense-cal-adapter.h"
71 #include "gnc-sx-instance-model.h"
72 #include "gnc-sx-list-tree-model-adapter.h"
73 #include "gnc-tree-view-sx-list.h"
74 #include "gnc-ui-util.h"
75 #include "gnc-ui.h"
76 #include "gnc-window.h"
77 
78 #undef G_LOG_DOMAIN
79 #define G_LOG_DOMAIN "gnc.gui.plugin-page.sx-list"
80 
81 G_GNUC_UNUSED static QofLogModule log_module = GNC_MOD_GUI_SX;
82 
83 #define PLUGIN_PAGE_SX_LIST_CM_CLASS "plugin-page-sx-list"
84 #define STATE_SECTION "SX Transaction List"
85 #define GNC_PREF_DIVIDER_POS "divider-position"
86 #define GNC_PREF_NUM_OF_MONTHS "number-of-months"
87 
89 {
90  gboolean disposed;
91 
92  GtkWidget* widget;
93  gint gnc_component_id;
94 
95  GncSxInstanceDenseCalAdapter *dense_cal_model;
96  GncDenseCal* gdcal;
97 
98  GncSxInstanceModel* instances;
99  GtkTreeView* tree_view;
100  GList *selected_list;
101 
103 
104 G_DEFINE_TYPE_WITH_PRIVATE(GncPluginPageSxList, gnc_plugin_page_sx_list, GNC_TYPE_PLUGIN_PAGE)
105 
106 #define GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(o) \
107  ((GncPluginPageSxListPrivate*)gnc_plugin_page_sx_list_get_instance_private ((GncPluginPageSxList*)o))
108 
109 /************************************************************
110  * Prototypes *
111  ************************************************************/
112 /* Plugin Actions */
113 static void gnc_plugin_page_sx_list_dispose (GObject *object);
114 static void gnc_plugin_page_sx_list_finalize (GObject *object);
115 
116 static GtkWidget *gnc_plugin_page_sx_list_create_widget (GncPluginPage *plugin_page);
117 static void gnc_plugin_page_sx_list_destroy_widget (GncPluginPage *plugin_page);
118 static void gnc_plugin_page_sx_list_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
119 static GncPluginPage *gnc_plugin_page_sx_list_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
120 
121 static gboolean gppsl_key_press_cb (GtkTreeView *tree_view, GdkEventKey *event, gpointer user_data);
122 static void gppsl_row_activated_cb (GtkTreeView *tree_view, GtkTreePath *path,
123  GtkTreeViewColumn *column, gpointer user_data);
124 
125 static void gnc_plugin_page_sx_list_cmd_new (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
126 static void gnc_plugin_page_sx_list_cmd_edit (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
127 static void gnc_plugin_page_sx_list_cmd_delete (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
128 static void gnc_plugin_page_sx_list_cmd_run (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
129 static void gnc_plugin_page_sx_list_cmd_refresh (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
130 static void gnc_plugin_page_sx_list_cmd_save_layout (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
131 static void gnc_plugin_page_sx_list_cmd_edit_tax_options (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
132 
133 /* Command callbacks */
134 static GActionEntry gnc_plugin_page_sx_list_actions [] =
135 {
136  { "SxListAction", nullptr, nullptr, nullptr, nullptr },
137  { "SxListNewAction", gnc_plugin_page_sx_list_cmd_new, nullptr, nullptr, nullptr },
138  { "SxListEditAction", gnc_plugin_page_sx_list_cmd_edit, nullptr, nullptr, nullptr },
139  { "SxListDeleteAction", gnc_plugin_page_sx_list_cmd_delete, nullptr, nullptr, nullptr },
140  { "SxListRunAction", gnc_plugin_page_sx_list_cmd_run, nullptr, nullptr, nullptr },
141  { "ViewRefreshAction", gnc_plugin_page_sx_list_cmd_refresh, nullptr, nullptr, nullptr },
142  { "ViewSaveLayoutAction", gnc_plugin_page_sx_list_cmd_save_layout, nullptr, nullptr, nullptr },
143  { "EditTaxOptionsAction", gnc_plugin_page_sx_list_cmd_edit_tax_options, nullptr, nullptr, nullptr },
144 };
146 static guint gnc_plugin_page_sx_list_n_actions = G_N_ELEMENTS(gnc_plugin_page_sx_list_actions);
147 
149 static const gchar *gnc_plugin_load_ui_items [] =
150 {
151  "FilePlaceholder3",
152  "EditPlaceholder3",
153  "EditPlaceholder5",
154  "ViewPlaceholder4",
155  "SchedulePlaceholder0",
156  nullptr,
157 };
158 
159 
162 {
163  GncPluginPageSxList *plugin_page;
164  const GList *object = gnc_gobject_tracking_get_list (GNC_PLUGIN_PAGE_SX_LIST_NAME);
165  if (object && GNC_IS_PLUGIN_PAGE_SX_LIST(object->data))
166  plugin_page = GNC_PLUGIN_PAGE_SX_LIST(object->data);
167  else
168  {
169  plugin_page = GNC_PLUGIN_PAGE_SX_LIST(g_object_new (GNC_TYPE_PLUGIN_PAGE_SX_LIST, nullptr));
170  }
171  return GNC_PLUGIN_PAGE(plugin_page);
172 }
173 
174 
179 static gboolean
180 gnc_plugin_page_sx_list_focus_widget (GncPluginPage *sx_plugin_page)
181 {
182  if (GNC_IS_PLUGIN_PAGE_SX_LIST(sx_plugin_page))
183  {
184  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(sx_plugin_page);
185  GtkTreeView *tree_view = priv->tree_view;
186 
187  /* Disable the Transaction Menu */
188  GAction *action = gnc_main_window_find_action (GNC_MAIN_WINDOW(sx_plugin_page->window), "TransactionAction");
189  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), false);
190  /* Enable the Schedule Menu */
191  action = gnc_main_window_find_action (GNC_MAIN_WINDOW(sx_plugin_page->window), "ScheduledAction");
192  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), true);
193  /* Disable the FilePrintAction */
194  action = gnc_main_window_find_action (GNC_MAIN_WINDOW(sx_plugin_page->window), "FilePrintAction");
195  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), false);
196 
197  gnc_main_window_update_menu_and_toolbar (GNC_MAIN_WINDOW(sx_plugin_page->window),
198  sx_plugin_page,
199  gnc_plugin_load_ui_items);
200 
201  if (GTK_IS_TREE_VIEW(tree_view))
202  {
203  if (!gtk_widget_is_focus (GTK_WIDGET(tree_view)))
204  gtk_widget_grab_focus (GTK_WIDGET(tree_view));
205  }
206  }
207  return false;
208 }
209 
210 static void
211 gnc_plugin_page_sx_list_class_init (GncPluginPageSxListClass *klass)
212 {
213  GObjectClass *object_class = G_OBJECT_CLASS(klass);
214  GncPluginPageClass *gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS(klass);
215 
216  object_class->dispose = gnc_plugin_page_sx_list_dispose;
217  object_class->finalize = gnc_plugin_page_sx_list_finalize;
218 
219  gnc_plugin_class->tab_icon = GNC_ICON_ACCOUNT;
220  gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_SX_LIST_NAME;
221  gnc_plugin_class->create_widget = gnc_plugin_page_sx_list_create_widget;
222  gnc_plugin_class->destroy_widget = gnc_plugin_page_sx_list_destroy_widget;
223  gnc_plugin_class->save_page = gnc_plugin_page_sx_list_save_page;
224  gnc_plugin_class->recreate_page = gnc_plugin_page_sx_list_recreate_page;
225  gnc_plugin_class->focus_page_function = gnc_plugin_page_sx_list_focus_widget;
226 }
227 
228 
229 static void
230 gnc_plugin_page_sx_list_init (GncPluginPageSxList *plugin_page)
231 {
232  GSimpleActionGroup *simple_action_group;
233  GncPluginPage *parent;
234 
235  /* Init parent declared variables */
236  parent = GNC_PLUGIN_PAGE(plugin_page);
237  g_object_set(G_OBJECT(plugin_page),
238  "page-name", _("Scheduled Transactions"),
239  "ui-description", "gnc-plugin-page-sx-list.ui",
240  nullptr);
241 
242  gnc_plugin_page_add_book (parent, gnc_get_current_book());
243  simple_action_group = gnc_plugin_page_create_action_group (parent, "GncPluginPageSxListActions");
244  g_action_map_add_action_entries (G_ACTION_MAP(simple_action_group),
245  gnc_plugin_page_sx_list_actions,
246  gnc_plugin_page_sx_list_n_actions,
247  plugin_page);
248 }
249 
250 
251 static void
252 gnc_plugin_page_sx_list_dispose (GObject *object)
253 {
254  GncPluginPageSxList *page;
256 
257  page = GNC_PLUGIN_PAGE_SX_LIST(object);
258  g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(page));
259  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
260  g_return_if_fail (priv != nullptr);
261 
262  g_return_if_fail (!priv->disposed);
263  priv->disposed = true;
264 
265  g_object_unref (G_OBJECT(priv->dense_cal_model));
266  priv->dense_cal_model = nullptr;
267  g_object_unref (GTK_WIDGET(priv->gdcal));
268  priv->gdcal = nullptr;
269  g_object_unref (G_OBJECT(priv->instances));
270  priv->instances = nullptr;
271 
272  G_OBJECT_CLASS(gnc_plugin_page_sx_list_parent_class)->dispose (object);
273 }
274 
275 
276 static void
277 gnc_plugin_page_sx_list_finalize (GObject *object)
278 {
279  GncPluginPageSxList *page;
281 
282  page = GNC_PLUGIN_PAGE_SX_LIST(object);
283  g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(page));
284  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
285  g_return_if_fail (priv != nullptr);
286 
287  G_OBJECT_CLASS(gnc_plugin_page_sx_list_parent_class)->finalize (object);
288 }
289 
290 
291 /* Virtual Functions */
292 static void
293 gnc_plugin_page_sx_list_refresh_cb (GHashTable *changes, gpointer user_data)
294 {
295  auto page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
297 
298  g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(page));
299 
300  /* We're only looking for forced updates here. */
301  if (changes)
302  return;
303 
304  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
305  gtk_widget_queue_draw (priv->widget);
306 }
307 
308 
309 static void
310 gnc_plugin_page_sx_list_close_cb (gpointer user_data)
311 {
312  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(user_data);
313  gnc_main_window_close_page (plugin_page);
314 }
315 
316 
317 static void
318 gppsl_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
319 {
320  GncPluginPage *page;
321  GAction *edit_action, *delete_action, *run_action;
322  gboolean selection_state = true;
323 
324  page = GNC_PLUGIN_PAGE(user_data);
325  edit_action = gnc_plugin_page_get_action (page, "SxListEditAction");
326  delete_action = gnc_plugin_page_get_action (page, "SxListDeleteAction");
327  run_action = gnc_plugin_page_get_action (page, "SxListRunAction");
328  selection_state = gtk_tree_selection_count_selected_rows (selection) == 0
329  ? false
330  : true;
331  g_simple_action_set_enabled (G_SIMPLE_ACTION(edit_action), selection_state);
332  g_simple_action_set_enabled (G_SIMPLE_ACTION(delete_action), selection_state);
333  g_simple_action_set_enabled (G_SIMPLE_ACTION(run_action), selection_state);
334 }
335 
336 
337 static void
338 gppsl_update_selected_list (GncPluginPageSxList *page, gboolean reset, SchedXaction *sx)
339 {
340  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
341 
342  if (reset && priv->selected_list)
343  {
344  g_list_free (priv->selected_list);
345  priv->selected_list = nullptr;
346  }
347  if (sx)
348  priv->selected_list = g_list_prepend (priv->selected_list, sx);
349 }
350 
351 
352 static void
353 gppsl_model_populated_cb (GtkTreeModel *tree_model, GncPluginPageSxList *page)
354 {
355  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
356  GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->tree_view));
357  gboolean found = false;
358 
359  if (priv->selected_list)
360  {
361  // walk the list to see if we can reselect the sx
362  for (GList *list = priv->selected_list; list != nullptr; list = list->next)
363  {
364  SchedXaction *sx = GNC_SCHEDXACTION(list->data);
365  GtkTreePath *path = gtk_tree_path_new_first ();
366 
367  // loop through the model trying to find selected sx's
368  while (gnc_tree_view_path_is_valid (GNC_TREE_VIEW(priv->tree_view), path))
369  {
370  SchedXaction *sx_tmp = gnc_tree_view_sx_list_get_sx_from_path (
371  GNC_TREE_VIEW_SX_LIST(priv->tree_view), path);
372  if (sx_tmp == sx)
373  {
374  found = true;
375  break;
376  }
377  gtk_tree_path_next (path);
378  }
379  if (found)
380  gtk_tree_selection_select_path (selection, path);
381 
382  gtk_tree_path_free (path);
383  }
384  }
385  // this could be on load or if sx is deleted
386  if (!found)
387  {
388  GtkTreePath *path = gtk_tree_path_new_first ();
389  gtk_tree_selection_select_path (selection, path);
390  gtk_tree_path_free (path);
391  }
392 }
393 
394 
395 static void
396 treeview_popup (GtkTreeView *treeview, GdkEvent *event, GncPluginPageSxList *page)
397 {
398  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
399  GtkWidget *menu, *menuitem;
400  gchar *full_action_name;
401  const gchar *group_name = gnc_plugin_page_get_simple_action_group_name (GNC_PLUGIN_PAGE(page));
402 
403  menu = gtk_menu_new();
404 
405  menuitem = gtk_menu_item_new_with_mnemonic (_("_New Schedule"));
406  full_action_name = g_strconcat (group_name, ".SxListNewAction", nullptr);
407  gtk_actionable_set_action_name (GTK_ACTIONABLE(menuitem), full_action_name);
408  g_free (full_action_name);
409  gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
410 
411  menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit Schedule"));
412  full_action_name = g_strconcat (group_name, ".SxListEditAction", nullptr);
413  gtk_actionable_set_action_name (GTK_ACTIONABLE(menuitem), full_action_name);
414  g_free (full_action_name);
415  gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
416 
417  menuitem = gtk_menu_item_new_with_mnemonic (_("_Delete Schedule"));
418  full_action_name = g_strconcat (group_name, ".SxListDeleteAction", nullptr);
419  gtk_actionable_set_action_name (GTK_ACTIONABLE(menuitem), full_action_name);
420  g_free (full_action_name);
421  gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
422 
423  menuitem = gtk_menu_item_new_with_mnemonic (_("_Run Schedule"));
424  full_action_name = g_strconcat (group_name, ".SxListRunAction", nullptr);
425  gtk_actionable_set_action_name (GTK_ACTIONABLE(menuitem), full_action_name);
426  g_free (full_action_name);
427  gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
428 
429  gtk_menu_attach_to_widget (GTK_MENU(menu), GTK_WIDGET(priv->tree_view), nullptr);
430  gtk_widget_show_all (menu);
431  gtk_menu_popup_at_pointer (GTK_MENU(menu), event);
432 }
433 
434 static gboolean
435 treeview_button_press (GtkTreeView *treeview, GdkEvent *event,
436  GncPluginPageSxList *page)
437 {
438  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
439  GtkTreeView *tree_view = GTK_TREE_VIEW(priv->tree_view);
440 
441  if (event->type == GDK_BUTTON_PRESS)
442  {
443  GdkEventButton *event_button = (GdkEventButton*)event;
444  if (event_button->button == GDK_BUTTON_SECONDARY)
445  {
446  GtkTreePath *path = nullptr;
447  if (gtk_tree_view_get_path_at_pos (priv->tree_view, event_button->x, event_button->y,
448  &path, nullptr, nullptr, nullptr))
449  {
450  GtkTreeSelection *selection = gtk_tree_view_get_selection (priv->tree_view);
451 
452  if (!gtk_tree_selection_path_is_selected (selection, path))
453  {
454  gtk_tree_selection_unselect_all (selection);
455  gtk_tree_selection_select_path (selection, path);
456  }
457  }
458  gtk_tree_path_free (path);
459 
460  treeview_popup (tree_view, event, page);
461  return true;
462  }
463  }
464  return false;
465 }
466 
467 static gboolean
468 treeview_popup_menu (GtkTreeView *treeview, GncPluginPageSxList *page)
469 {
470  treeview_popup (treeview, nullptr, page);
471  return true;
472 }
473 
474 static GtkWidget *
475 gnc_plugin_page_sx_list_create_widget (GncPluginPage *plugin_page)
476 {
477  GncPluginPageSxList *page;
479  GtkWidget *widget;
480  GtkWidget *vbox;
481  GtkWidget *label;
482  GtkWidget *swin;
483  GtkWindow *window;
484 
485  page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
486  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
487  if (priv->widget != nullptr)
488  return priv->widget;
489 
490  window = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page)));
491 
492  /* Create Vpaned widget for top level */
493  widget = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
494  priv->widget = widget;
495  gtk_widget_show (priv->widget);
496 
497  // Set the name for this widget so it can be easily manipulated with css
498  gtk_widget_set_name (GTK_WIDGET(priv->widget), "gnc-id-sx-page");
499 
500  /* Add vbox and label */
501  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
502  gtk_box_set_homogeneous (GTK_BOX(vbox), false);
503  gtk_paned_pack1 (GTK_PANED(widget), vbox, true, false);
504 
505  label = gtk_label_new (_("Transactions"));
506  gnc_widget_style_context_add_class (GTK_WIDGET(label), "gnc-class-strong");
507  gtk_widget_set_margin_start (GTK_WIDGET(label), 6);
508  gnc_label_set_alignment (label, 0.0, 0);
509  gtk_widget_show (label);
510  gtk_box_pack_start (GTK_BOX(vbox), label, false, false, 0);
511  gtk_widget_show (vbox);
512 
513  /* Create scrolled window for top area */
514  swin = gtk_scrolled_window_new (nullptr, nullptr);
515  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(swin),
516  GTK_POLICY_AUTOMATIC,
517  GTK_POLICY_AUTOMATIC);
518  gtk_box_pack_start (GTK_BOX(vbox), swin, true, true, 5);
519  gtk_widget_show (swin);
520 
521  /* Set the paned position from the preferences, default 160 */
522  gtk_paned_set_position (GTK_PANED(priv->widget),
523  gnc_prefs_get_int (GNC_PREFS_GROUP_SXED,
524  GNC_PREF_DIVIDER_POS));
525 
526  {
527  GDate end;
528  g_date_clear (&end, 1);
529  gnc_gdate_set_today (&end);
530  g_date_add_years (&end, 1);
531  priv->instances = GNC_SX_INSTANCE_MODEL(gnc_sx_get_instances (&end, true));
532  }
533 
534  {
535  GAction *edit_action, *delete_action, *run_action;
536  edit_action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "SxListEditAction");
537  delete_action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "SxListDeleteAction");
538  run_action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "SxListRunAction");
539  g_simple_action_set_enabled (G_SIMPLE_ACTION(edit_action), false);
540  g_simple_action_set_enabled (G_SIMPLE_ACTION(delete_action), false);
541  g_simple_action_set_enabled (G_SIMPLE_ACTION(run_action), false);
542  }
543 
544  {
545  GtkTreeSelection *selection;
546  GtkTreePath *path = gtk_tree_path_new_first ();
547 
548  priv->tree_view = GTK_TREE_VIEW(gnc_tree_view_sx_list_new (priv->instances));
549  g_object_set (G_OBJECT(priv->tree_view),
550  "state-section", STATE_SECTION,
551  "show-column-menu", true,
552  nullptr);
553  gtk_container_add (GTK_CONTAINER(swin), GTK_WIDGET(priv->tree_view));
554 
555  selection = gtk_tree_view_get_selection (priv->tree_view);
556  gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
557 
558  g_signal_connect (G_OBJECT(selection), "changed",
559  (GCallback)gppsl_selection_changed_cb, (gpointer)page);
560  g_signal_connect (G_OBJECT(priv->tree_view), "key-press-event",
561  (GCallback)gppsl_key_press_cb, (gpointer)page);
562  g_signal_connect (G_OBJECT(priv->tree_view), "row-activated",
563  (GCallback)gppsl_row_activated_cb, (gpointer)page);
564  g_signal_connect (G_OBJECT(gtk_tree_view_get_model (GTK_TREE_VIEW(priv->tree_view))),
565  "model-populated", (GCallback)gppsl_model_populated_cb, (gpointer)page);
566 
567  gtk_tree_selection_select_path (selection, path);
568  gtk_tree_path_free (path);
569  }
570 
571  g_signal_connect (G_OBJECT(priv->tree_view), "button-press-event",
572  G_CALLBACK(treeview_button_press), page);
573  g_signal_connect (G_OBJECT(priv->tree_view), "popup-menu",
574  G_CALLBACK(treeview_popup_menu), page);
575 
576  /* Add vbox and label */
577  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
578  gtk_box_set_homogeneous (GTK_BOX(vbox), false);
579  gtk_paned_pack2 (GTK_PANED(widget), vbox, true, false);
580 
581  label = gtk_label_new (_("Upcoming Transactions"));
582  gnc_widget_style_context_add_class (GTK_WIDGET(label), "gnc-class-strong");
583  gtk_widget_set_margin_start (GTK_WIDGET(label), 6);
584  gnc_label_set_alignment (label, 0.0, 0);
585  gtk_widget_show (label);
586 
587  gtk_box_pack_start (GTK_BOX(vbox), label, false, false, 0);
588  gtk_widget_show (vbox);
589 
590  /* Create scrolled window for bottom area */
591  swin = gtk_scrolled_window_new (nullptr, nullptr);
592  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(swin),
593  GTK_POLICY_AUTOMATIC,
594  GTK_POLICY_AUTOMATIC);
595  gtk_box_pack_start (GTK_BOX(vbox), swin, true, true, 5);
596  gtk_widget_show (swin);
597 
598  {
599  priv->dense_cal_model = gnc_sx_instance_dense_cal_adapter_new (GNC_SX_INSTANCE_MODEL(priv->instances));
600  priv->gdcal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model (window, GNC_DENSE_CAL_MODEL(priv->dense_cal_model)));
601  g_object_ref_sink (priv->gdcal);
602 
603  /* Set number of months from preference, default 12 */
604  auto num_months = gnc_prefs_get_int (GNC_PREFS_GROUP_SXED, GNC_PREF_NUM_OF_MONTHS);
605  if (num_months == 0)
606  {
607  PWARN ("Got invalid value '0' for number of months to display. This suggests a gsettings configuration issue. Continuing with a default value of 12 instead.");
608  num_months = 12;
609  }
610  gnc_dense_cal_set_num_months (priv->gdcal, num_months);
611 
612  gtk_container_add (GTK_CONTAINER(swin), GTK_WIDGET(priv->gdcal));
613  }
614 
615  priv->gnc_component_id = gnc_register_gui_component ("plugin-page-sx-list",
616  gnc_plugin_page_sx_list_refresh_cb,
617  gnc_plugin_page_sx_list_close_cb,
618  page);
619  gnc_gui_component_set_session (priv->gnc_component_id,
620  gnc_get_current_session ());
621 
622  g_signal_connect (G_OBJECT(plugin_page), "inserted",
623  G_CALLBACK(gnc_plugin_page_inserted_cb),
624  nullptr);
625 
626  return priv->widget;
627 }
628 
629 
630 static void
631 gnc_plugin_page_sx_list_destroy_widget (GncPluginPage *plugin_page)
632 {
633  GncPluginPageSxList *page;
635 
636  page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
637  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
638 
639  // Remove the page_changed signal callback
640  gnc_plugin_page_disconnect_page_changed (GNC_PLUGIN_PAGE(plugin_page));
641 
642  // Remove the page focus idle function if present
643  g_idle_remove_by_data (plugin_page);
644 
645  if (priv->widget)
646  {
647  g_object_unref (G_OBJECT(priv->widget));
648  priv->widget = nullptr;
649  }
650 
651  if (priv->selected_list)
652  g_list_free (priv->selected_list);
653 
654  if (priv->gnc_component_id)
655  {
656  gnc_unregister_gui_component (priv->gnc_component_id);
657  priv->gnc_component_id = 0;
658  }
659 }
660 
661 
669 static void
670 gnc_plugin_page_sx_list_save_page (GncPluginPage *plugin_page,
671  GKeyFile *key_file,
672  const gchar *group_name)
673 {
674  GncPluginPageSxList *page;
676 
677  g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(plugin_page));
678  g_return_if_fail (key_file != nullptr);
679  g_return_if_fail (group_name != nullptr);
680 
681  page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
682  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
683 
684  g_key_file_set_integer (key_file, group_name, "dense_cal_num_months",
685  gnc_dense_cal_get_num_months (priv->gdcal));
686 
687  g_key_file_set_integer (key_file, group_name, "paned_position",
688  gtk_paned_get_position (GTK_PANED(priv->widget)));
689 }
690 
691 
700 static GncPluginPage *
701 gnc_plugin_page_sx_list_recreate_page (GtkWidget *window,
702  GKeyFile *key_file,
703  const gchar *group_name)
704 {
705  GncPluginPageSxList *page;
707 
708  g_return_val_if_fail (key_file, nullptr);
709  g_return_val_if_fail (group_name, nullptr);
710 
711  /* Create the new page. */
712  page = GNC_PLUGIN_PAGE_SX_LIST(gnc_plugin_page_sx_list_new ());
713  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
714 
715  /* Install it now so we can them manipulate the created widget */
716  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), GNC_PLUGIN_PAGE(page));
717 
718  {
719  GError *err = nullptr;
720  gint num_months = g_key_file_get_integer (key_file, group_name, "dense_cal_num_months", &err);
721  if (err == nullptr)
722  gnc_dense_cal_set_num_months (priv->gdcal, num_months);
723  else
724  g_error_free (err);
725  }
726 
727  {
728  GError *err = nullptr;
729  gint paned_position = g_key_file_get_integer (key_file, group_name,
730  "paned_position", &err);
731  if (err == nullptr)
732  gtk_paned_set_position (GTK_PANED(priv->widget), paned_position);
733  else
734  g_error_free (err);
735  }
736 
737  return GNC_PLUGIN_PAGE(page);
738 }
739 
740 
741 static void
742 gnc_plugin_page_sx_list_cmd_new (GSimpleAction *simple,
743  GVariant *parameter,
744  gpointer user_data)
745 {
746  auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
747  GtkWindow *window = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(plugin_page)));
748  SchedXaction *new_sx;
749  gboolean new_sx_flag = true;
750 
751  new_sx = xaccSchedXactionMalloc (gnc_get_current_book());
752  {
753  GDate now;
754  Recurrence *r = g_new0 (Recurrence, 1);
755  GList *schedule;
756 
757  g_date_clear (&now, 1);
758  gnc_gdate_set_today (&now);
759  recurrenceSet (r, 1, PERIOD_MONTH, &now, WEEKEND_ADJ_NONE);
760  schedule = gnc_sx_get_schedule (new_sx);
761  schedule = g_list_append (schedule, r);
762  gnc_sx_set_schedule (new_sx, schedule);
763  }
764  gnc_ui_scheduled_xaction_editor_dialog_create (window, new_sx, new_sx_flag);
765  gppsl_update_selected_list (plugin_page, true, new_sx);
766 }
767 
768 static void
769 gnc_plugin_page_sx_list_cmd_refresh (GSimpleAction *simple,
770  GVariant *parameter,
771  gpointer user_data)
772 {
773  auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
775 
776  g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(plugin_page));
777 
778  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(plugin_page);
779  gtk_widget_queue_draw (priv->widget);
780 }
781 
782 static void
783 gnc_plugin_page_sx_list_cmd_save_layout (GSimpleAction *simple,
784  GVariant *parameter,
785  gpointer user_data)
786 {
787  auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
789  gint paned_position;
790 
791  g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(plugin_page));
792 
793  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(plugin_page);
794 
795  paned_position = gtk_paned_get_position (GTK_PANED(priv->widget));
796 
797  gnc_prefs_set_int (GNC_PREFS_GROUP_SXED, GNC_PREF_DIVIDER_POS,
798  paned_position);
799 
800  gnc_prefs_set_int (GNC_PREFS_GROUP_SXED, GNC_PREF_NUM_OF_MONTHS,
801  gnc_dense_cal_get_num_months (priv->gdcal));
802 }
803 
804 static void
805 _edit_sx(gpointer data, gpointer user_data)
806 {
807  gnc_ui_scheduled_xaction_editor_dialog_create (GTK_WINDOW(user_data),
808  GNC_SCHEDXACTION(data), false);
809 }
810 
811 static SchedXaction*
812 _argument_reorder_fn (GtkTreePath* list_path_data, GncTreeViewSxList* user_tree_view)
813 {
814  return gnc_tree_view_sx_list_get_sx_from_path (user_tree_view, list_path_data);
815 }
816 
817 
818 static void
819 gnc_plugin_page_sx_list_cmd_edit (GSimpleAction *simple,
820  GVariant *parameter,
821  gpointer user_data)
822 {
823  auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
824  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(plugin_page);
825  GtkWindow *window = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(plugin_page)));
826  GtkTreeSelection *selection;
827  GList *selected_paths, *to_edit;
828  GtkTreeModel *model;
829 
830  selection = gtk_tree_view_get_selection (priv->tree_view);
831  selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
832  if (!gnc_list_length_cmp (selected_paths, 0))
833  {
834  g_warning ("no selection edit.");
835  return;
836  }
837 
838  to_edit = gnc_g_list_map (selected_paths,
839  (GncGMapFunc)_argument_reorder_fn,
840  priv->tree_view);
841 
842  gppsl_update_selected_list (plugin_page, true, nullptr);
843  for (GList *list = to_edit; list != nullptr; list = list->next)
844  {
845  DEBUG ("to-edit [%s]\n", xaccSchedXactionGetName (GNC_SCHEDXACTION(list->data)));
846  gppsl_update_selected_list (plugin_page, false, GNC_SCHEDXACTION(list->data));
847  }
848 
849  g_list_foreach (to_edit, (GFunc)_edit_sx, window);
850  g_list_free (to_edit);
851  g_list_foreach (selected_paths, (GFunc)gtk_tree_path_free, nullptr);
852  g_list_free (selected_paths);
853 }
854 
855 
856 static void
857 gnc_plugin_page_sx_list_cmd_edit_tax_options (GSimpleAction *simple,
858  GVariant *parameter,
859  gpointer user_data)
860 {
861  auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
862  GtkWidget *window = GTK_WIDGET(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(plugin_page)));
863 
864  ENTER ("(action %p, page %p)", simple, plugin_page);
865  gnc_tax_info_dialog (window, nullptr);
866  LEAVE (" ");
867 }
868 
869 static gboolean
870 gppsl_is_enable_column_visible (GtkTreeView *tree_view)
871 {
872  gboolean retval = FALSE;
873  GList *columns = gtk_tree_view_get_columns (tree_view);
874 
875  for (GList *node = columns; node; node = node->next)
876  {
877  GtkTreeViewColumn *col = GTK_TREE_VIEW_COLUMN(node->data);
878  gint id = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(col), MODEL_COLUMN));
879 
880  if (id == SXLTMA_COL_ENABLED)
881  {
882  retval = gtk_tree_view_column_get_visible(col);
883  break;
884  }
885  }
886  g_list_free (columns);
887  return retval;
888 }
889 
890 static gboolean
891 gppsl_set_toggle (GtkTreeView *tree_view)
892 {
893  GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
894  GtkTreeModel *model;
895  GList *sel_list = gtk_tree_selection_get_selected_rows (selection, &model);
896  gint num_selected = gtk_tree_selection_count_selected_rows (selection);
897  gint num_toggled = 0;
898 
899  for (GList *node = sel_list; node; node = node->next)
900  {
901  GtkTreePath *path = (GtkTreePath *)node->data;
902  GtkTreeIter iter;
903 
904  if (gtk_tree_model_get_iter (model, &iter, path))
905  {
906  gboolean toggled;
907 
908  gtk_tree_model_get (model, &iter, SXLTMA_COL_ENABLED, &toggled, -1);
909 
910  if (toggled)
911  {
912  num_toggled++;
913  }
914  }
915  gtk_tree_path_free (path);
916  }
917  g_list_free (sel_list);
918 
919  return num_toggled != num_selected;
920 }
921 
922 static void
923 gppsl_set_list (GncPluginPageSxList *sx_plugin_page, gboolean enable)
924 {
925  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(sx_plugin_page);
926  GtkTreeView *tree_view = priv->tree_view;
927  GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
928  GtkTreeModel *model;
929  GList *sel_list = gtk_tree_selection_get_selected_rows (selection, &model);
930  GList *sx_list = nullptr;
931 
932  gppsl_update_selected_list (sx_plugin_page, true, nullptr);
933 
934  for (GList *node = sel_list; node; node = node->next)
935  {
936  GtkTreePath *path = (GtkTreePath *)node->data;
937  GncTreeViewSxList *view = GNC_TREE_VIEW_SX_LIST(tree_view);
938  SchedXaction *sx = gnc_tree_view_sx_list_get_sx_from_path (view, path);
939 
940  if (sx)
941  {
942  GtkTreeIter iter;
943 
944  gppsl_update_selected_list (sx_plugin_page, false, sx);
945 
946  if (gtk_tree_model_get_iter (model, &iter, path))
947  {
948  gboolean toggled;
949 
950  gtk_tree_model_get (model, &iter, SXLTMA_COL_ENABLED, &toggled, -1);
951  if (enable != toggled)
952  {
953  sx_list = g_list_prepend (sx_list, sx);
954  }
955  }
956  }
957 
958  gtk_tree_path_free (path);
959  }
960  g_list_free (sel_list);
961 
962  for (GList *node = sx_list; node; node = node->next)
963  {
964  if (node == sx_list)
965  {
966  if (node->next)
967  {
969  }
970  }
971  else if (!node->next)
972  {
973  qof_event_resume ();
974  }
975 
976  SchedXaction *sx = GNC_SCHEDXACTION(node->data);
977 
978  xaccSchedXactionSetEnabled (sx, enable);
979  }
980  g_list_free (sx_list);
981 }
982 
983 static gboolean
984 gppsl_key_press_cb (GtkTreeView *tree_view, GdkEventKey *event, gpointer user_data)
985 {
986  if (event->keyval != GDK_KEY_space || !gppsl_is_enable_column_visible (tree_view))
987  {
988  return FALSE;
989  }
990 
991  g_signal_stop_emission_by_name (G_OBJECT(tree_view), "key-press-event");
992 
993  gboolean enable = gppsl_set_toggle (tree_view);
994 
995  gppsl_set_list (GNC_PLUGIN_PAGE_SX_LIST(user_data), enable);
996 
997  return TRUE;
998 }
999 
1000 
1001 static void
1002 gppsl_row_activated_cb (GtkTreeView *tree_view,
1003  GtkTreePath *path,
1004  GtkTreeViewColumn *column,
1005  gpointer user_data)
1006 {
1007  GncPluginPageSxList *page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
1008  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
1009  GtkWindow *window = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page)));
1010 
1011  SchedXaction *sx = gnc_tree_view_sx_list_get_sx_from_path (
1012  GNC_TREE_VIEW_SX_LIST(priv->tree_view), path);
1013  gnc_ui_scheduled_xaction_editor_dialog_create (window, sx, false);
1014  gppsl_update_selected_list (page, true, sx);
1015 }
1016 
1017 
1018 static void
1019 _destroy_sx(gpointer data, gpointer user_data)
1020 {
1021  SchedXactions *sxes;
1022  auto sx = GNC_SCHEDXACTION(data);
1023  QofBook *book;
1024  book = gnc_get_current_book ();
1025  sxes = gnc_book_get_schedxactions (book);
1026 
1027  DEBUG("deleting sx [%s]", xaccSchedXactionGetName (sx));
1028 
1029  gnc_sxes_del_sx (sxes, sx);
1030  gnc_sx_begin_edit (sx);
1032 }
1033 
1034 
1035 static void
1036 _destroy_sx_names (gpointer data, gpointer user_data)
1037 {
1038  auto sx = GNC_SCHEDXACTION(data);
1039  GList **to_delete_names = (GList**)user_data;
1040  *to_delete_names = g_list_append (*to_delete_names, xaccSchedXactionGetName (sx));
1041 }
1042 
1043 
1044 static void
1045 gnc_plugin_page_sx_list_cmd_delete (GSimpleAction *simple,
1046  GVariant *parameter,
1047  gpointer user_data)
1048 {
1049  auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
1050  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(plugin_page);
1051  GtkTreeSelection *selection = gtk_tree_view_get_selection (priv->tree_view);
1052  GList *selected_paths, *to_delete = nullptr, *to_delete_names = nullptr;
1053  GtkTreeModel *model;
1054  GtkWindow *window;
1055  gchar *message = nullptr;
1056  gint length;
1057  gchar *text_list_of_scheduled_transaction_names = nullptr;
1058 
1059  selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
1060  if (!gnc_list_length_cmp (selected_paths, 0))
1061  {
1062  g_warning ("no selection for delete.");
1063  return;
1064  }
1065 
1066  to_delete = gnc_g_list_map (selected_paths,
1067  (GncGMapFunc)_argument_reorder_fn,
1068  priv->tree_view);
1069 
1070  g_list_foreach (to_delete, (GFunc)_destroy_sx_names, &to_delete_names);
1071 
1072  window = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(plugin_page)));
1073 
1074  length = g_list_length (to_delete);
1075 
1076  text_list_of_scheduled_transaction_names = gnc_g_list_stringjoin (to_delete_names, "\n");
1077 
1078  /* Translators: This is a ngettext(3) message, question followed by list of scheduled transactions to be deleted */
1079  message = g_strdup_printf ("%s\n\n%s",
1080  ngettext ("Do you really want to delete this scheduled transaction?",
1081  "Do you really want to delete these scheduled transactions?",
1082  length),
1083  text_list_of_scheduled_transaction_names);
1084 
1085  g_free (text_list_of_scheduled_transaction_names);
1086  g_list_free (to_delete_names);
1087 
1088  if (gnc_verify_dialog (window, false, "%s", message))
1089  {
1090  gppsl_update_selected_list (plugin_page, true, nullptr);
1091 
1092  g_list_foreach (to_delete, (GFunc)_destroy_sx, nullptr);
1093  }
1094 
1095  g_free (message);
1096  g_list_free (to_delete);
1097  g_list_foreach (selected_paths, (GFunc)gtk_tree_path_free, nullptr);
1098  g_list_free (selected_paths);
1099 }
1100 
1101 static void
1102 gnc_plugin_page_sx_list_cmd_run (GSimpleAction *simple,
1103  GVariant *parameter,
1104  gpointer user_data)
1105 {
1106  auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
1107  auto priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(plugin_page);
1108  auto selection = gtk_tree_view_get_selection (priv->tree_view);
1109  GtkTreeModel *model;
1110  auto selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
1111 
1112  if (!selected_paths)
1113  {
1114  PWARN ("no selection for run.");
1115  return;
1116  }
1117 
1118  auto to_run = gnc_g_list_map (selected_paths, (GncGMapFunc)_argument_reorder_fn, priv->tree_view);
1119 
1120  gnc_ui_sx_since_last_run_dialog (gnc_sx_get_select_instances (to_run));
1121 
1122  g_list_free (to_run);
1123  g_list_foreach (selected_paths, (GFunc)gtk_tree_path_free, nullptr);
1124  g_list_free (selected_paths);
1125 }
1126 
GtkWidget * gnc_plugin_page_get_window(GncPluginPage *page)
Retrieve a pointer to the GncMainWindow (GtkWindow) containing this page.
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
GList * gnc_g_list_map(GList *list, GncGMapFunc fn, gpointer user_data)
const gchar * tab_icon
The relative name of the icon that should be shown on the tab for this page.
gboolean(* focus_page_function)(GncPluginPage *plugin_page)
This function performs specific actions to set the focus on a specific widget.
GList * gnc_sx_get_schedule(const SchedXaction *sx)
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...
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.
Date and Time handling routines.
gchar * gnc_g_list_stringjoin(GList *list_of_strings, const gchar *sep)
Return a string joining a GList whose elements are gchar* strings.
utility functions for the GnuCash UI
GncTreeView implementation for Scheduled Transaction List.
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...
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
Functions that are supported by all types of windows.
void gnc_gdate_set_today(GDate *gd)
Set a GDate to the current day.
Definition: gnc-date.cpp:1306
gboolean gnc_prefs_set_int(const gchar *group, const gchar *pref_name, gint value)
Store an integer value into the preferences backend.
Definition: gnc-prefs.cpp:288
GtkWidget * window
The window that contains the display widget for this plugin.
API for Transactions and Splits (journal entries)
GSimpleActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GSimpleActionGroup object associated with this page.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
gint gnc_prefs_get_int(const gchar *group, const gchar *pref_name)
Get an integer value from the preferences backend.
Functions for adding content to a window.
void(* destroy_widget)(GncPluginPage *plugin_page)
Function called to destroy the display widget for a particular type of plugin.
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
The class data structure for a content plugin.
Gobject helper routines.
GAction * gnc_main_window_find_action(GncMainWindow *window, const gchar *action_name)
Find the GAction in the main window.
void gnc_plugin_page_disconnect_page_changed(GncPluginPage *page)
Disconnect the page_changed_id signal callback.
Anchor Scheduled Transaction info in a book.
const gchar * plugin_name
The textual name of this plugin.
GtkWidget *(* create_widget)(GncPluginPage *plugin_page)
Function called to create the display widget for a particular type of plugin.
const gchar * gnc_plugin_page_get_simple_action_group_name(GncPluginPage *page)
Retrieve the simple action group name associated with this plugin page.
Additional event handling code.
All type declarations for the whole Gnucash engine.
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...
GLib helper routines.
Generic api to store and retrieve preferences.
QofBook reference.
Definition: qofbook-p.hpp:46
GncSxInstanceModel * gnc_sx_get_select_instances(GList *sel_sxes)
Allocates a new SxInstanceModel and fills it with generated instances for the given scheduled transac...
GncSxInstanceModel * gnc_sx_get_instances(const GDate *range_end, gboolean include_disabled)
Allocates a new SxInstanceModel and fills it with generated instances for all scheduled transactions ...
void qof_event_suspend(void)
Suspend all engine events.
Definition: qofevent.cpp:145
void qof_event_resume(void)
Resume engine event generation.
Definition: qofevent.cpp:156
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.
Functions for adding plugins to a GnuCash window.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
#define GNC_TYPE_PLUGIN_PAGE_SX_LIST
Functions providing a list of scheduled transactions as a plugin page.
GncPluginPage * gnc_plugin_page_sx_list_new(void)
void gnc_plugin_page_add_book(GncPluginPage *page, QofBook *book)
Add a book reference to the specified page.
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
Creates and initializes a scheduled transaction.
gint gnc_list_length_cmp(const GList *list, size_t len)
Scans the GList elements the minimum number of iterations required to test it against a specified siz...
API for Transactions and Splits (journal entries)
GAction * gnc_plugin_page_get_action(GncPluginPage *page, const gchar *name)
Retrieve a GAction object associated with this page.
void xaccSchedXactionDestroy(SchedXaction *sx)
Cleans up and frees a SchedXaction and its associated data.
Commodity handling public routines.