GnuCash  4.11-137-g155922540d+
gnc-plugin-page-sx-list.c
1 /********************************************************************\
2  * gnc-plugin-page-sx-list.c : 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 /*################## Added for Reg2 #################*/
56 #include "dialog-sx-editor2.h"
57 /*################## Added for Reg2 #################*/
58 #include "dialog-utils.h"
59 #include "gnc-commodity.h"
60 #include "gnc-component-manager.h"
61 #include "gnc-date.h"
62 #include "gnc-dense-cal.h"
63 #include "gnc-engine.h"
64 #include "gnc-event.h"
65 #include "gnc-glib-utils.h"
66 #include "gnc-icons.h"
67 #include "gnc-main-window.h"
68 #include "gnc-plugin-page-sx-list.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 
87 {
88  gboolean disposed;
89 
90  GtkWidget* widget;
91  gint gnc_component_id;
92 
93  GncSxInstanceDenseCalAdapter *dense_cal_model;
94  GncDenseCal* gdcal;
95 
96  GncSxInstanceModel* instances;
97  GtkTreeView* tree_view;
98  GList *selected_list;
99 
101 
102 G_DEFINE_TYPE_WITH_PRIVATE(GncPluginPageSxList, gnc_plugin_page_sx_list, GNC_TYPE_PLUGIN_PAGE)
103 
104 #define GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(o) \
105  ((GncPluginPageSxListPrivate*)gnc_plugin_page_sx_list_get_instance_private((GncPluginPageSxList*)o))
106 
107 static GObjectClass *parent_class = NULL;
108 
109 /************************************************************
110  * Prototypes *
111  ************************************************************/
112 /* Plugin Actions */
113 static void gnc_plugin_page_sx_list_class_init (GncPluginPageSxListClass *klass);
114 static void gnc_plugin_page_sx_list_init (GncPluginPageSxList *plugin_page);
115 static void gnc_plugin_page_sx_list_dispose (GObject *object);
116 static void gnc_plugin_page_sx_list_finalize (GObject *object);
117 
118 static GtkWidget *gnc_plugin_page_sx_list_create_widget (GncPluginPage *plugin_page);
119 static void gnc_plugin_page_sx_list_destroy_widget (GncPluginPage *plugin_page);
120 static void gnc_plugin_page_sx_list_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
121 static GncPluginPage *gnc_plugin_page_sx_list_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
122 
123 static void gppsl_row_activated_cb (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data);
124 
125 static void gnc_plugin_page_sx_list_cmd_new (GtkAction *action, GncPluginPageSxList *page);
126 static void gnc_plugin_page_sx_list_cmd_edit (GtkAction *action, GncPluginPageSxList *page);
127 #ifdef REGISTER2_ENABLED
128 /*################## Added for Reg2 #################*/
129 static void gnc_plugin_page_sx_list_cmd_new2 (GtkAction *action, GncPluginPageSxList *page);
130 static void gnc_plugin_page_sx_list_cmd_edit2 (GtkAction *action, GncPluginPageSxList *page);
131 /*################## Added for Reg2 #################*/
132 #endif
133 static void gnc_plugin_page_sx_list_cmd_delete (GtkAction *action, GncPluginPageSxList *page);
134 static void gnc_plugin_page_sx_list_cmd_refresh (GtkAction *action, GncPluginPageSxList *page);
135 
136 /* Command callbacks */
137 static GtkActionEntry gnc_plugin_page_sx_list_actions [] =
138 {
139  { "SxListAction", NULL, N_("_Scheduled"), NULL, NULL, NULL },
140  {
141  "SxListNewAction", GNC_ICON_NEW_ACCOUNT, N_("_New"), NULL,
142  N_("Create a new scheduled transaction"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_new)
143  },
144 #ifdef REGISTER2_ENABLED
145 /*################## Added for Reg2 #################*/
146  {
147  "SxListNewAction2", GNC_ICON_NEW_ACCOUNT, N_("_New 2"), NULL,
148  N_("Create a new scheduled transaction 2"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_new2)
149  },
150 /*################## Added for Reg2 #################*/
151 #endif
152  {
153  "SxListEditAction", GNC_ICON_EDIT_ACCOUNT, N_("_Edit"), NULL,
154  N_("Edit the selected scheduled transaction"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_edit)
155  },
156 #ifdef REGISTER2_ENABLED
157 /*################## Added for Reg2 #################*/
158  {
159  "SxListEditAction2", GNC_ICON_EDIT_ACCOUNT, N_("_Edit 2"), NULL,
160  N_("Edit the selected scheduled transaction 2"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_edit2)
161  },
162 /*################## Added for Reg2 #################*/
163 #endif
164  {
165  "SxListDeleteAction", GNC_ICON_DELETE_ACCOUNT, N_("_Delete"), NULL,
166  N_("Delete the selected scheduled transaction"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_delete)
167  },
168 
169  /* View menu */
170 
171  {
172  "ViewRefreshAction", "view-refresh", N_("_Refresh"), "<primary>r",
173  N_("Refresh this window"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_refresh)
174  },
175 };
177 static guint gnc_plugin_page_sx_list_n_actions = G_N_ELEMENTS(gnc_plugin_page_sx_list_actions);
178 
181 {
182  GncPluginPageSxList *plugin_page;
183  const GList *object = gnc_gobject_tracking_get_list (GNC_PLUGIN_PAGE_SX_LIST_NAME);
184  if (object && GNC_IS_PLUGIN_PAGE_SX_LIST (object->data))
185  plugin_page = GNC_PLUGIN_PAGE_SX_LIST (object->data);
186  else
187  {
188  plugin_page = g_object_new (GNC_TYPE_PLUGIN_PAGE_SX_LIST, NULL);
189  }
190  return GNC_PLUGIN_PAGE(plugin_page);
191 }
192 
193 
198 static gboolean
199 gnc_plugin_page_sx_list_focus_widget (GncPluginPage *sx_plugin_page)
200 {
201  if (GNC_IS_PLUGIN_PAGE_SX_LIST(sx_plugin_page))
202  {
203  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(sx_plugin_page);
204  GtkTreeView *tree_view = priv->tree_view;
205 
206  if (GTK_IS_TREE_VIEW(tree_view))
207  {
208  if (!gtk_widget_is_focus (GTK_WIDGET(tree_view)))
209  gtk_widget_grab_focus (GTK_WIDGET(tree_view));
210  }
211  }
212  return FALSE;
213 }
214 
215 static void
216 gnc_plugin_page_sx_list_class_init (GncPluginPageSxListClass *klass)
217 {
218  GObjectClass *object_class = G_OBJECT_CLASS(klass);
219  GncPluginPageClass *gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS(klass);
220 
221  parent_class = g_type_class_peek_parent(klass);
222 
223  object_class->dispose = gnc_plugin_page_sx_list_dispose;
224  object_class->finalize = gnc_plugin_page_sx_list_finalize;
225 
226  gnc_plugin_class->tab_icon = GNC_ICON_ACCOUNT;
227  gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_SX_LIST_NAME;
228  gnc_plugin_class->create_widget = gnc_plugin_page_sx_list_create_widget;
229  gnc_plugin_class->destroy_widget = gnc_plugin_page_sx_list_destroy_widget;
230  gnc_plugin_class->save_page = gnc_plugin_page_sx_list_save_page;
231  gnc_plugin_class->recreate_page = gnc_plugin_page_sx_list_recreate_page;
232  gnc_plugin_class->focus_page_function = gnc_plugin_page_sx_list_focus_widget;
233 }
234 
235 
236 static void
237 gnc_plugin_page_sx_list_init (GncPluginPageSxList *plugin_page)
238 {
239  GtkActionGroup *action_group;
240  GncPluginPage *parent;
241 
242  /* Init parent declared variables */
243  parent = GNC_PLUGIN_PAGE(plugin_page);
244 #ifdef REGISTER2_ENABLED
245  g_object_set(G_OBJECT(plugin_page),
246  "page-name", _("Scheduled Transactions"),
247  "page-uri", "default:",
248  "ui-description", "gnc-plugin-page-sx-list2-ui.xml",
249  NULL);
250 #else
251  g_object_set(G_OBJECT(plugin_page),
252  "page-name", _("Scheduled Transactions"),
253  "page-uri", "default:",
254  "ui-description", "gnc-plugin-page-sx-list-ui.xml",
255  NULL);
256 #endif
257 
258  gnc_plugin_page_add_book (parent, gnc_get_current_book());
259  action_group =
261  "GncPluginPageSxListActions");
262  gtk_action_group_add_actions (action_group,
263  gnc_plugin_page_sx_list_actions,
264  gnc_plugin_page_sx_list_n_actions,
265  plugin_page);
266  /* gnc_plugin_init_short_names (action_group, toolbar_labels); */
267 }
268 
269 
270 static void
271 gnc_plugin_page_sx_list_dispose (GObject *object)
272 {
273  GncPluginPageSxList *page;
275 
276  page = GNC_PLUGIN_PAGE_SX_LIST(object);
277  g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(page));
278  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
279  g_return_if_fail (priv != NULL);
280 
281  g_return_if_fail (!priv->disposed);
282  priv->disposed = TRUE;
283 
284  g_object_unref (G_OBJECT(priv->dense_cal_model));
285  priv->dense_cal_model = NULL;
286  g_object_unref (GTK_WIDGET(priv->gdcal));
287  priv->gdcal = NULL;
288  g_object_unref (G_OBJECT(priv->instances));
289  priv->instances = NULL;
290 
291  G_OBJECT_CLASS(parent_class)->dispose (object);
292 }
293 
294 
295 static void
296 gnc_plugin_page_sx_list_finalize (GObject *object)
297 {
298  GncPluginPageSxList *page;
300 
301  page = GNC_PLUGIN_PAGE_SX_LIST(object);
302  g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(page));
303  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
304  g_return_if_fail (priv != NULL);
305 
306  G_OBJECT_CLASS(parent_class)->finalize (object);
307 }
308 
309 
310 /* Virtual Functions */
311 static void
312 gnc_plugin_page_sx_list_refresh_cb (GHashTable *changes, gpointer user_data)
313 {
314  GncPluginPageSxList *page = user_data;
316 
317  g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(page));
318 
319  /* We're only looking for forced updates here. */
320  if (changes)
321  return;
322 
323  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
324  gtk_widget_queue_draw (priv->widget);
325 }
326 
327 
328 static void
329 gnc_plugin_page_sx_list_close_cb (gpointer user_data)
330 {
331  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(user_data);
332  gnc_main_window_close_page (plugin_page);
333 }
334 
335 
336 static void
337 gppsl_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
338 {
339  GncPluginPage *page;
340  GtkAction *edit_action, *delete_action;
341  gboolean selection_state = TRUE;
342 
343  page = GNC_PLUGIN_PAGE(user_data);
344  edit_action = gnc_plugin_page_get_action (page, "SxListEditAction");
345  delete_action = gnc_plugin_page_get_action (page, "SxListDeleteAction");
346  selection_state
347  = gtk_tree_selection_count_selected_rows (selection) == 0
348  ? FALSE
349  : TRUE;
350  gtk_action_set_sensitive (edit_action, selection_state);
351  gtk_action_set_sensitive (delete_action, selection_state);
352 }
353 
354 
355 static void
356 gppsl_update_selected_list (GncPluginPageSxList *page, gboolean reset, SchedXaction *sx)
357 {
358  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
359 
360  if (reset && priv->selected_list)
361  {
362  g_list_free (priv->selected_list);
363  priv->selected_list = NULL;
364  }
365  if (sx)
366  priv->selected_list = g_list_prepend (priv->selected_list, sx);
367 }
368 
369 
370 static void
371 gppsl_model_populated_cb (GtkTreeModel *tree_model, GncPluginPageSxList *page)
372 {
373  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
374  GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->tree_view));
375  gboolean found = FALSE;
376 
377  if (priv->selected_list)
378  {
379  // walk the list to see if we can reselect the sx
380  for (GList *list = priv->selected_list; list != NULL; list = list->next)
381  {
382  SchedXaction *sx = list->data;
383  GtkTreePath *path = gtk_tree_path_new_first ();
384 
385  // loop through the model trying to find selected sx's
386  while (gnc_tree_view_path_is_valid (GNC_TREE_VIEW(priv->tree_view), path))
387  {
388  SchedXaction *sx_tmp = gnc_tree_view_sx_list_get_sx_from_path (
389  GNC_TREE_VIEW_SX_LIST(priv->tree_view), path);
390  if (sx_tmp == sx)
391  {
392  found = TRUE;
393  break;
394  }
395  gtk_tree_path_next (path);
396  }
397  if (found)
398  gtk_tree_selection_select_path (selection, path);
399 
400  gtk_tree_path_free (path);
401  }
402  }
403  // this could be on load or if sx is deleted
404  if (!found)
405  {
406  GtkTreePath *path = gtk_tree_path_new_first ();
407  gtk_tree_selection_select_path (selection, path);
408  gtk_tree_path_free (path);
409  }
410 }
411 
412 
413 static GtkWidget *
414 gnc_plugin_page_sx_list_create_widget (GncPluginPage *plugin_page)
415 {
416  GncPluginPageSxList *page;
418  GtkWidget *widget;
419  GtkWidget *vbox;
420  GtkWidget *label;
421  GtkWidget *swin;
422 
423  page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
424  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
425  if (priv->widget != NULL)
426  return priv->widget;
427 
428  /* Create Vpaned widget for top level */
429  widget = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
430  priv->widget = widget;
431  gtk_widget_show (priv->widget);
432 
433  // Set the name for this widget so it can be easily manipulated with css
434  gtk_widget_set_name (GTK_WIDGET(priv->widget), "gnc-id-sx-page");
435 
436  /* Add vbox and label */
437  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
438  gtk_box_set_homogeneous (GTK_BOX(vbox), FALSE);
439  gtk_paned_pack1 (GTK_PANED(widget), vbox, TRUE, FALSE);
440 
441  label = gtk_label_new (_("Transactions"));
442  gnc_widget_style_context_add_class (GTK_WIDGET(label), "gnc-class-strong");
443  gtk_widget_set_margin_start (GTK_WIDGET(label), 6);
444  gnc_label_set_alignment (label, 0.0, 0);
445  gtk_widget_show (label);
446  gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
447  gtk_widget_show (vbox);
448 
449  /* Create scrolled window for top area */
450  swin = gtk_scrolled_window_new (NULL, NULL);
451  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(swin),
452  GTK_POLICY_AUTOMATIC,
453  GTK_POLICY_AUTOMATIC);
454  gtk_box_pack_start (GTK_BOX(vbox), swin, TRUE, TRUE, 5);
455  gtk_widget_show (swin);
456 
457  {
458  // gint half_way;
459  // half_way = plugin_page->notebook_page->allocation.height * 0.5;
460  // fixme; get a real value:
461  gtk_paned_set_position (GTK_PANED(priv->widget), 160);
462  }
463 
464  {
465  GDate end;
466  g_date_clear (&end, 1);
467  gnc_gdate_set_today (&end);
468  g_date_add_years (&end, 1);
469  priv->instances = GNC_SX_INSTANCE_MODEL(gnc_sx_get_instances (&end, TRUE));
470  }
471 
472  {
473  GtkAction *edit_action, *delete_action;
474  edit_action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "SxListEditAction");
475  delete_action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page), "SxListDeleteAction");
476  gtk_action_set_sensitive (edit_action, FALSE);
477  gtk_action_set_sensitive (delete_action, FALSE);
478  }
479 
480  {
481  GtkTreeSelection *selection;
482  GtkTreePath *path = gtk_tree_path_new_first ();
483 
484  priv->tree_view = GTK_TREE_VIEW(gnc_tree_view_sx_list_new (priv->instances));
485  g_object_set (G_OBJECT(priv->tree_view),
486  "state-section", STATE_SECTION,
487  "show-column-menu", TRUE,
488  NULL);
489  gtk_container_add (GTK_CONTAINER( swin ), GTK_WIDGET(priv->tree_view));
490 
491  selection = gtk_tree_view_get_selection (priv->tree_view);
492  gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
493  gtk_tree_selection_select_path (selection, path);
494  gtk_tree_path_free (path);
495 
496  g_signal_connect (G_OBJECT(selection), "changed", (GCallback)gppsl_selection_changed_cb, (gpointer)page);
497  g_signal_connect (G_OBJECT(priv->tree_view), "row-activated", (GCallback)gppsl_row_activated_cb, (gpointer)page);
498  g_signal_connect (G_OBJECT(gtk_tree_view_get_model (GTK_TREE_VIEW(priv->tree_view))),
499  "model-populated", (GCallback)gppsl_model_populated_cb, (gpointer)page);
500  }
501 
502  /* Add vbox and label */
503  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
504  gtk_box_set_homogeneous (GTK_BOX(vbox), FALSE);
505  gtk_paned_pack2 (GTK_PANED(widget), vbox, TRUE, FALSE);
506 
507  label = gtk_label_new (_("Upcoming Transactions"));
508  gnc_widget_style_context_add_class (GTK_WIDGET(label), "gnc-class-strong");
509  gtk_widget_set_margin_start (GTK_WIDGET(label), 6);
510  gnc_label_set_alignment (label, 0.0, 0);
511  gtk_widget_show (label);
512 
513  gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
514  gtk_widget_show (vbox);
515 
516  /* Create scrolled window for bottom area */
517  swin = gtk_scrolled_window_new (NULL, NULL);
518  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(swin),
519  GTK_POLICY_AUTOMATIC,
520  GTK_POLICY_AUTOMATIC);
521  gtk_box_pack_start (GTK_BOX(vbox), swin, TRUE, TRUE, 5);
522  gtk_widget_show (swin);
523 
524  {
525  priv->dense_cal_model = gnc_sx_instance_dense_cal_adapter_new (GNC_SX_INSTANCE_MODEL(priv->instances));
526  priv->gdcal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model (GNC_DENSE_CAL_MODEL(priv->dense_cal_model)));
527  g_object_ref_sink (priv->gdcal);
528 
529  gnc_dense_cal_set_months_per_col (priv->gdcal, 4);
530  gnc_dense_cal_set_num_months (priv->gdcal, 12);
531 
532  gtk_container_add (GTK_CONTAINER(swin), GTK_WIDGET(priv->gdcal));
533  }
534 
535  priv->gnc_component_id = gnc_register_gui_component ("plugin-page-sx-list",
536  gnc_plugin_page_sx_list_refresh_cb,
537  gnc_plugin_page_sx_list_close_cb,
538  page);
539  gnc_gui_component_set_session (priv->gnc_component_id,
540  gnc_get_current_session ());
541 
542  g_signal_connect (G_OBJECT(plugin_page), "inserted",
543  G_CALLBACK(gnc_plugin_page_inserted_cb),
544  NULL);
545 
546  return priv->widget;
547 }
548 
549 
550 static void
551 gnc_plugin_page_sx_list_destroy_widget (GncPluginPage *plugin_page)
552 {
553  GncPluginPageSxList *page;
555 
556  page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
557  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
558 
559  // Remove the page_changed signal callback
560  gnc_plugin_page_disconnect_page_changed (GNC_PLUGIN_PAGE(plugin_page));
561 
562  // Remove the page focus idle function if present
563  g_idle_remove_by_data (plugin_page);
564 
565  if (priv->widget)
566  {
567  g_object_unref (G_OBJECT(priv->widget));
568  priv->widget = NULL;
569  }
570 
571  if (priv->selected_list)
572  g_list_free (priv->selected_list);
573 
574  if (priv->gnc_component_id)
575  {
576  gnc_unregister_gui_component (priv->gnc_component_id);
577  priv->gnc_component_id = 0;
578  }
579 }
580 
581 
589 static void
590 gnc_plugin_page_sx_list_save_page (GncPluginPage *plugin_page,
591  GKeyFile *key_file,
592  const gchar *group_name)
593 {
594  GncPluginPageSxList *page;
596 
597  g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(plugin_page));
598  g_return_if_fail (key_file != NULL);
599  g_return_if_fail (group_name != NULL);
600 
601  page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
602  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
603 
604  g_key_file_set_integer (key_file, group_name, "dense_cal_num_months",
605  gnc_dense_cal_get_num_months (priv->gdcal));
606 
607  g_key_file_set_integer (key_file, group_name, "paned_position",
608  gtk_paned_get_position (GTK_PANED(priv->widget)));
609 }
610 
611 
620 static GncPluginPage *
621 gnc_plugin_page_sx_list_recreate_page (GtkWidget *window,
622  GKeyFile *key_file,
623  const gchar *group_name)
624 {
625  GncPluginPageSxList *page;
627 
628  g_return_val_if_fail (key_file, NULL);
629  g_return_val_if_fail (group_name, NULL);
630 
631  /* Create the new page. */
632  page = GNC_PLUGIN_PAGE_SX_LIST(gnc_plugin_page_sx_list_new ());
633  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
634 
635  /* Install it now so we can them manipulate the created widget */
636  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), GNC_PLUGIN_PAGE(page));
637 
638  {
639  GError *err = NULL;
640  gint num_months = g_key_file_get_integer (key_file, group_name, "dense_cal_num_months", &err);
641  if (err == NULL)
642  gnc_dense_cal_set_num_months (priv->gdcal, num_months);
643  else
644  g_error_free (err);
645  }
646 
647  {
648  GError *err = NULL;
649  gint paned_position = g_key_file_get_integer (key_file, group_name,
650  "paned_position", &err);
651  if (err == NULL)
652  gtk_paned_set_position (GTK_PANED(priv->widget), paned_position);
653  else
654  g_error_free (err);
655  }
656 
657  return GNC_PLUGIN_PAGE(page);
658 }
659 
660 
661 static void
662 gnc_plugin_page_sx_list_cmd_new (GtkAction *action, GncPluginPageSxList *page)
663 {
664  GtkWindow *window = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page)));
665  SchedXaction *new_sx;
666  gboolean new_sx_flag = TRUE;
667 
668  new_sx = xaccSchedXactionMalloc (gnc_get_current_book());
669  {
670  GDate now;
671  Recurrence *r = g_new0 (Recurrence, 1);
672  GList *schedule;
673 
674  g_date_clear (&now, 1);
675  gnc_gdate_set_today (&now);
676  recurrenceSet (r, 1, PERIOD_MONTH, &now, WEEKEND_ADJ_NONE);
677  schedule = gnc_sx_get_schedule (new_sx);
678  schedule = g_list_append (schedule, r);
679  gnc_sx_set_schedule (new_sx, schedule);
680  }
681  gnc_ui_scheduled_xaction_editor_dialog_create (window, new_sx, new_sx_flag);
682  gppsl_update_selected_list (page, TRUE, new_sx);
683 }
684 
685 #ifdef REGISTER2_ENABLED
686 /*################## Added for Reg2 #################*/
687 static void
688 gnc_plugin_page_sx_list_cmd_new2 (GtkAction *action, GncPluginPageSxList *page)
689 {
690  GtkWindow *window = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page)));
691  SchedXaction *new_sx;
692  gboolean new_sx_flag = TRUE;
693 
694  new_sx = xaccSchedXactionMalloc (gnc_get_current_book());
695  {
696  GDate now;
697  Recurrence *r = g_new0 (Recurrence, 1);
698  GList *schedule;
699 
700  g_date_clear (&now, 1);
701  gnc_gdate_set_today (&now);
702  recurrenceSet (r, 1, PERIOD_MONTH, &now, WEEKEND_ADJ_NONE);
703  schedule = gnc_sx_get_schedule (new_sx);
704  schedule = g_list_append (schedule, r);
705  gnc_sx_set_schedule (new_sx, schedule);
706  }
707  gnc_ui_scheduled_xaction_editor_dialog_create2 (window, new_sx, new_sx_flag);
708 }
709 /*################## Added for Reg2 #################*/
710 #endif
711 
712 static void
713 gnc_plugin_page_sx_list_cmd_refresh (GtkAction *action, GncPluginPageSxList *page)
714 {
716 
717  g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(page));
718 
719  priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
720  gtk_widget_queue_draw (priv->widget);
721 }
722 
723 static void
724 _edit_sx(gpointer data, gpointer user_data)
725 {
726  gnc_ui_scheduled_xaction_editor_dialog_create (GTK_WINDOW(user_data),
727  (SchedXaction*)data, FALSE);
728 }
729 
730 #ifdef REGISTER2_ENABLED
731 /*################## Added for Reg2 #################*/
732 static void
733 _edit_sx2 (gpointer data, gpointer user_data)
734 {
735  gnc_ui_scheduled_xaction_editor_dialog_create2 (GTK_WINDOW(user_data),
736  (SchedXaction*)data, FALSE);
737 }
738 /*################## Added for Reg2 #################*/
739 #endif
740 
741 static SchedXaction*
742 _argument_reorder_fn (GtkTreePath* list_path_data, GncTreeViewSxList* user_tree_view)
743 {
744  return gnc_tree_view_sx_list_get_sx_from_path (user_tree_view, list_path_data);
745 }
746 
747 
748 static void
749 gnc_plugin_page_sx_list_cmd_edit (GtkAction *action, GncPluginPageSxList *page)
750 {
751  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
752  GtkWindow *window = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page)));
753  GtkTreeSelection *selection;
754  GList *selected_paths, *to_edit;
755  GtkTreeModel *model;
756 
757  selection = gtk_tree_view_get_selection (priv->tree_view);
758  selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
759  if (!gnc_list_length_cmp (selected_paths, 0))
760  {
761  g_warning ("no selection edit.");
762  return;
763  }
764 
765  to_edit = gnc_g_list_map (selected_paths,
766  (GncGMapFunc)_argument_reorder_fn,
767  priv->tree_view);
768 
769  gppsl_update_selected_list (page, TRUE, NULL);
770  for (GList *list = to_edit; list != NULL; list = list->next)
771  {
772  DEBUG ("to-edit [%s]\n", xaccSchedXactionGetName ((SchedXaction*)list->data));
773  gppsl_update_selected_list (page, FALSE, list->data);
774  }
775 
776  g_list_foreach (to_edit, (GFunc)_edit_sx, window);
777  g_list_free (to_edit);
778  g_list_foreach (selected_paths, (GFunc)gtk_tree_path_free, NULL);
779  g_list_free (selected_paths);
780 }
781 
782 #ifdef REGISTER2_ENABLED
783 /*################## Added for Reg2 #################*/
784 static void
785 gnc_plugin_page_sx_list_cmd_edit2 (GtkAction *action, GncPluginPageSxList *page)
786 {
787  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
788  GtkWindow *window = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page)));
789  GtkTreeSelection *selection;
790  GList *selected_paths, *to_edit;
791  GtkTreeModel *model;
792 
793  selection = gtk_tree_view_get_selection (priv->tree_view);
794  selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
795  if (!gnc_list_length_cmp (selected_paths, 0))
796  {
797  g_warning ("no selection edit.");
798  return;
799  }
800 
801  to_edit = gnc_g_list_map (selected_paths,
802  (GncGMapFunc)_argument_reorder_fn,
803  priv->tree_view);
804  g_list_foreach (to_edit, (GFunc)_edit_sx2, window);
805  g_list_free (to_edit);
806  g_list_foreach (selected_paths, (GFunc)gtk_tree_path_free, NULL);
807  g_list_free (selected_paths);
808 }
809 /*################## Added for Reg2 #################*/
810 #endif
811 
812 static void
813 gppsl_row_activated_cb (GtkTreeView *tree_view,
814  GtkTreePath *path,
815  GtkTreeViewColumn *column,
816  gpointer user_data)
817 {
818  GncPluginPageSxList *page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
819  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
820  GtkWindow *window = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page)));
821 
822  SchedXaction *sx = gnc_tree_view_sx_list_get_sx_from_path (
823  GNC_TREE_VIEW_SX_LIST(priv->tree_view), path);
824  gnc_ui_scheduled_xaction_editor_dialog_create (window, sx, FALSE);
825  gppsl_update_selected_list (page, TRUE, sx);
826 }
827 
828 
829 static void
830 _destroy_sx(gpointer data, gpointer user_data)
831 {
832  SchedXactions *sxes;
833  SchedXaction *sx = (SchedXaction*)data;
834  QofBook *book;
835  book = gnc_get_current_book ();
836  sxes = gnc_book_get_schedxactions (book);
837  gnc_sxes_del_sx (sxes, sx);
838  gnc_sx_begin_edit (sx);
840 }
841 
842 
843 static void
844 gnc_plugin_page_sx_list_cmd_delete (GtkAction *action, GncPluginPageSxList *page)
845 {
846  GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
847  GtkTreeSelection *selection;
848  GList *selected_paths, *to_delete = NULL;
849  GtkTreeModel *model;
850  GtkWindow *window;
851  gchar *message = NULL;
852  gint length;
853 
854  selection = gtk_tree_view_get_selection (priv->tree_view);
855  selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
856  if (!gnc_list_length_cmp (selected_paths, 0))
857  {
858  g_warning ("no selection for delete.");
859  return;
860  }
861 
862  to_delete = gnc_g_list_map (selected_paths,
863  (GncGMapFunc)_argument_reorder_fn,
864  priv->tree_view);
865 
866  window = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page)));
867 
868  length = g_list_length (to_delete);
869 
870  /* Translators: This is a ngettext(3) message, %d is the number of scheduled transactions deleted */
871  message = g_strdup_printf (ngettext ("Do you really want to delete this scheduled transaction?",
872  "Do you really want to delete %d scheduled transactions?",
873  length), length);
874 
875  if (gnc_verify_dialog (window, FALSE, "%s", message))
876  {
877  gppsl_update_selected_list (page, TRUE, NULL);
878  for (GList *list = to_delete; list != NULL; list = list->next)
879  {
880  DEBUG("to-delete [%s]\n", xaccSchedXactionGetName ((SchedXaction*)list->data));
881  gppsl_update_selected_list (page, FALSE, list->data);
882  }
883  g_list_foreach (to_delete, (GFunc)_destroy_sx, NULL);
884  }
885 
886  g_free (message);
887  g_list_free (to_delete);
888  g_list_foreach (selected_paths, (GFunc)gtk_tree_path_free, NULL);
889  g_list_free (selected_paths);
890 }
891 
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)
Definition: SchedXaction.c:570
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)
Definition: SchedXaction.c:564
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.
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:1239
API for Transactions and Splits (journal entries)
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
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.
The class data structure for a content plugin.
Gobject helper routines.
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.
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.
GtkAction * gnc_plugin_page_get_action(GncPluginPage *page, const gchar *name)
Retrieve a GtkAction object associated with this page.
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 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.
#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.
Definition: SchedXaction.c:405
GtkActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GtkActionGroup object associated with this page.
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)
void xaccSchedXactionDestroy(SchedXaction *sx)
Cleans up and frees a SchedXaction and its associated data.
Definition: SchedXaction.c:475
Commodity handling public routines.