134{
135 { "SxListAction", nullptr, nullptr, nullptr, nullptr },
136 { "SxListNewAction", gnc_plugin_page_sx_list_cmd_new, nullptr, nullptr, nullptr },
137 { "SxListEditAction", gnc_plugin_page_sx_list_cmd_edit, nullptr, nullptr, nullptr },
138 { "SxListDeleteAction", gnc_plugin_page_sx_list_cmd_delete, nullptr, nullptr, nullptr },
139 { "SxListRunAction", gnc_plugin_page_sx_list_cmd_run, nullptr, nullptr, nullptr },
140 { "ViewRefreshAction", gnc_plugin_page_sx_list_cmd_refresh, nullptr, nullptr, nullptr },
141 { "ViewSaveLayoutAction", gnc_plugin_page_sx_list_cmd_save_layout, nullptr, nullptr, nullptr },
142 { "EditTaxOptionsAction", gnc_plugin_page_sx_list_cmd_edit_tax_options, nullptr, nullptr, nullptr },
143};
145static guint gnc_plugin_page_sx_list_n_actions = G_N_ELEMENTS(gnc_plugin_page_sx_list_actions);
146
148static const gchar *gnc_plugin_load_ui_items [] =
149{
150 "FilePlaceholder3",
151 "EditPlaceholder3",
152 "EditPlaceholder5",
153 "ViewPlaceholder4",
154 "SchedulePlaceholder0",
155 nullptr,
156};
157
158
161{
164 if (object && GNC_IS_PLUGIN_PAGE_SX_LIST(object->data))
165 plugin_page = GNC_PLUGIN_PAGE_SX_LIST(object->data);
166 else
167 {
169 }
170 return GNC_PLUGIN_PAGE(plugin_page);
171}
172
173
178static gboolean
179gnc_plugin_page_sx_list_focus_widget (
GncPluginPage *sx_plugin_page)
180{
181 if (GNC_IS_PLUGIN_PAGE_SX_LIST(sx_plugin_page))
182 {
184 GtkTreeView *tree_view = priv->tree_view;
185
186
188 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), false);
189
191 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), true);
192
194 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), false);
195
197 sx_plugin_page,
198 gnc_plugin_load_ui_items);
199
200 if (GTK_IS_TREE_VIEW(tree_view))
201 {
202 if (!gtk_widget_is_focus (GTK_WIDGET(tree_view)))
203 gtk_widget_grab_focus (GTK_WIDGET(tree_view));
204 }
205 }
206 return false;
207}
208
209static void
211{
212 GObjectClass *object_class = G_OBJECT_CLASS(klass);
214
215 object_class->dispose = gnc_plugin_page_sx_list_dispose;
216 object_class->finalize = gnc_plugin_page_sx_list_finalize;
217
218 gnc_plugin_class->
tab_icon = GNC_ICON_ACCOUNT;
219 gnc_plugin_class->
plugin_name = GNC_PLUGIN_PAGE_SX_LIST_NAME;
220 gnc_plugin_class->
create_widget = gnc_plugin_page_sx_list_create_widget;
221 gnc_plugin_class->
destroy_widget = gnc_plugin_page_sx_list_destroy_widget;
222 gnc_plugin_class->
save_page = gnc_plugin_page_sx_list_save_page;
223 gnc_plugin_class->
recreate_page = gnc_plugin_page_sx_list_recreate_page;
225}
226
227
228static void
230{
231 GSimpleActionGroup *simple_action_group;
233
234
235 parent = GNC_PLUGIN_PAGE(plugin_page);
236 g_object_set(G_OBJECT(plugin_page),
237 "page-name",
_(
"Scheduled Transactions"),
238 "ui-description", "gnc-plugin-page-sx-list.ui",
239 nullptr);
240
243 g_action_map_add_action_entries (G_ACTION_MAP(simple_action_group),
244 gnc_plugin_page_sx_list_actions,
245 gnc_plugin_page_sx_list_n_actions,
246 plugin_page);
247}
248
249
250static void
251gnc_plugin_page_sx_list_dispose (GObject *object)
252{
255
256 page = GNC_PLUGIN_PAGE_SX_LIST(object);
257 g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(page));
258 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
259 g_return_if_fail (priv != nullptr);
260
261 g_return_if_fail (!priv->disposed);
262 priv->disposed = true;
263
264 g_object_unref (G_OBJECT(priv->dense_cal_model));
265 priv->dense_cal_model = nullptr;
266 g_object_unref (GTK_WIDGET(priv->gdcal));
267 priv->gdcal = nullptr;
268 g_object_unref (G_OBJECT(priv->instances));
269 priv->instances = nullptr;
270
271 G_OBJECT_CLASS(gnc_plugin_page_sx_list_parent_class)->dispose (object);
272}
273
274
275static void
276gnc_plugin_page_sx_list_finalize (GObject *object)
277{
280
281 page = GNC_PLUGIN_PAGE_SX_LIST(object);
282 g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(page));
283 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
284 g_return_if_fail (priv != nullptr);
285
286 G_OBJECT_CLASS(gnc_plugin_page_sx_list_parent_class)->finalize (object);
287}
288
289
290
291static void
292gnc_plugin_page_sx_list_refresh_cb (GHashTable *changes, gpointer user_data)
293{
294 auto page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
296
297 g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(page));
298
299
300 if (changes)
301 return;
302
303 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
304 gtk_widget_queue_draw (priv->widget);
305}
306
307
308static void
309gnc_plugin_page_sx_list_close_cb (gpointer user_data)
310{
313}
314
315
316static void
317gppsl_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
318{
320 GAction *edit_action, *delete_action, *run_action;
321 gboolean selection_state = true;
322
323 page = GNC_PLUGIN_PAGE(user_data);
327 selection_state = gtk_tree_selection_count_selected_rows (selection) == 0
328 ? false
329 : true;
330 g_simple_action_set_enabled (G_SIMPLE_ACTION(edit_action), selection_state);
331 g_simple_action_set_enabled (G_SIMPLE_ACTION(delete_action), selection_state);
332 g_simple_action_set_enabled (G_SIMPLE_ACTION(run_action), selection_state);
333}
334
335
336static void
338{
340
341 if (reset && priv->selected_list)
342 {
343 g_list_free (priv->selected_list);
344 priv->selected_list = nullptr;
345 }
346 if (sx)
347 priv->selected_list = g_list_prepend (priv->selected_list, sx);
348}
349
350
351static void
353{
355 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->tree_view));
356 gboolean found = false;
357
358 if (priv->selected_list)
359 {
360
361 for (GList *list = priv->selected_list; list != nullptr; list = list->next)
362 {
363 SchedXaction *sx = GNC_SCHEDXACTION(list->data);
364 GtkTreePath *path = gtk_tree_path_new_first ();
365
366
367 while (gnc_tree_view_path_is_valid (GNC_TREE_VIEW(priv->tree_view), path))
368 {
369 SchedXaction *sx_tmp = gnc_tree_view_sx_list_get_sx_from_path (
370 GNC_TREE_VIEW_SX_LIST(priv->tree_view), path);
371 if (sx_tmp == sx)
372 {
373 found = true;
374 break;
375 }
376 gtk_tree_path_next (path);
377 }
378 if (found)
379 gtk_tree_selection_select_path (selection, path);
380
381 gtk_tree_path_free (path);
382 }
383 }
384
385 if (!found)
386 {
387 GtkTreePath *path = gtk_tree_path_new_first ();
388 gtk_tree_selection_select_path (selection, path);
389 gtk_tree_path_free (path);
390 }
391}
392
393
394static void
396{
398 GtkWidget *menu, *menuitem;
399 gchar *full_action_name;
401
402 menu = gtk_menu_new();
403
404 menuitem = gtk_menu_item_new_with_mnemonic (
_(
"_New Schedule"));
405 full_action_name = g_strconcat (group_name, ".SxListNewAction", nullptr);
406 gtk_actionable_set_action_name (GTK_ACTIONABLE(menuitem), full_action_name);
407 g_free (full_action_name);
408 gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
409
410 menuitem = gtk_menu_item_new_with_mnemonic (
_(
"_Edit Schedule"));
411 full_action_name = g_strconcat (group_name, ".SxListEditAction", nullptr);
412 gtk_actionable_set_action_name (GTK_ACTIONABLE(menuitem), full_action_name);
413 g_free (full_action_name);
414 gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
415
416 menuitem = gtk_menu_item_new_with_mnemonic (
_(
"_Delete Schedule"));
417 full_action_name = g_strconcat (group_name, ".SxListDeleteAction", nullptr);
418 gtk_actionable_set_action_name (GTK_ACTIONABLE(menuitem), full_action_name);
419 g_free (full_action_name);
420 gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
421
422 menuitem = gtk_menu_item_new_with_mnemonic (
_(
"_Run Schedule"));
423 full_action_name = g_strconcat (group_name, ".SxListRunAction", nullptr);
424 gtk_actionable_set_action_name (GTK_ACTIONABLE(menuitem), full_action_name);
425 g_free (full_action_name);
426 gtk_menu_shell_append (GTK_MENU_SHELL(menu), menuitem);
427
428 gtk_menu_attach_to_widget (GTK_MENU(menu), GTK_WIDGET(priv->tree_view), nullptr);
429 gtk_widget_show_all (menu);
430 gtk_menu_popup_at_pointer (GTK_MENU(menu), event);
431}
432
433static gboolean
434treeview_button_press (GtkTreeView *treeview, GdkEvent *event,
436{
438 GtkTreeView *tree_view = GTK_TREE_VIEW(priv->tree_view);
439
440 if (event->type == GDK_BUTTON_PRESS)
441 {
442 GdkEventButton *event_button = (GdkEventButton*)event;
443 if (event_button->button == GDK_BUTTON_SECONDARY)
444 {
445 GtkTreePath *path = nullptr;
446 if (gtk_tree_view_get_path_at_pos (priv->tree_view, event_button->x, event_button->y,
447 &path, nullptr, nullptr, nullptr))
448 {
449 GtkTreeSelection *selection = gtk_tree_view_get_selection (priv->tree_view);
450
451 if (!gtk_tree_selection_path_is_selected (selection, path))
452 {
453 gtk_tree_selection_unselect_all (selection);
454 gtk_tree_selection_select_path (selection, path);
455 }
456 }
457 gtk_tree_path_free (path);
458
459 treeview_popup (tree_view, event, page);
460 return true;
461 }
462 }
463 return false;
464}
465
466static gboolean
468{
469 treeview_popup (treeview, nullptr, page);
470 return true;
471}
472
473static GtkWidget *
474gnc_plugin_page_sx_list_create_widget (
GncPluginPage *plugin_page)
475{
478 GtkWidget *widget;
479 GtkWidget *vbox;
480 GtkWidget *label;
481 GtkWidget *swin;
482 GtkWindow *window;
483
484 page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
485 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
486 if (priv->widget != nullptr)
487 return priv->widget;
488
490
491
492 widget = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
493 priv->widget = widget;
494 gtk_widget_show (priv->widget);
495
496
497 gtk_widget_set_name (GTK_WIDGET(priv->widget), "gnc-id-sx-page");
498
499
500 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
501 gtk_box_set_homogeneous (GTK_BOX(vbox), false);
502 gtk_paned_pack1 (GTK_PANED(widget), vbox, true, false);
503
504 label = gtk_label_new (
_(
"Transactions"));
505 gnc_widget_style_context_add_class (GTK_WIDGET(label), "gnc-class-strong");
506 gtk_widget_set_margin_start (GTK_WIDGET(label), 6);
507 gnc_label_set_alignment (label, 0.0, 0);
508 gtk_widget_show (label);
509 gtk_box_pack_start (GTK_BOX(vbox), label, false, false, 0);
510 gtk_widget_show (vbox);
511
512
513 swin = gtk_scrolled_window_new (nullptr, nullptr);
514 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(swin),
515 GTK_POLICY_AUTOMATIC,
516 GTK_POLICY_AUTOMATIC);
517 gtk_box_pack_start (GTK_BOX(vbox), swin, true, true, 5);
518 gtk_widget_show (swin);
519
520
521 gtk_paned_set_position (GTK_PANED(priv->widget),
523 GNC_PREF_DIVIDER_POS));
524
525 {
526 GDate end;
527 g_date_clear (&end, 1);
529 g_date_add_years (&end, 1);
530 priv->instances = GNC_SX_INSTANCE_MODEL(gnc_sx_get_instances (&end, true));
531 }
532
533 {
534 GAction *edit_action, *delete_action, *run_action;
538 g_simple_action_set_enabled (G_SIMPLE_ACTION(edit_action), false);
539 g_simple_action_set_enabled (G_SIMPLE_ACTION(delete_action), false);
540 g_simple_action_set_enabled (G_SIMPLE_ACTION(run_action), false);
541 }
542
543 {
544 GtkTreeSelection *selection;
545 GtkTreePath *path = gtk_tree_path_new_first ();
546
547 priv->tree_view = GTK_TREE_VIEW(gnc_tree_view_sx_list_new (priv->instances));
548 g_object_set (G_OBJECT(priv->tree_view),
549 "state-section", STATE_SECTION,
550 "show-column-menu", true,
551 nullptr);
552 gtk_container_add (GTK_CONTAINER(swin), GTK_WIDGET(priv->tree_view));
553
554 selection = gtk_tree_view_get_selection (priv->tree_view);
555 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
556
557 g_signal_connect (G_OBJECT(selection), "changed",
558 (GCallback)gppsl_selection_changed_cb, (gpointer)page);
559 g_signal_connect (G_OBJECT(priv->tree_view), "key-press-event",
560 (GCallback)gppsl_key_press_cb, (gpointer)page);
561 g_signal_connect (G_OBJECT(priv->tree_view), "row-activated",
562 (GCallback)gppsl_row_activated_cb, (gpointer)page);
563 g_signal_connect (G_OBJECT(gtk_tree_view_get_model (GTK_TREE_VIEW(priv->tree_view))),
564 "model-populated", (GCallback)gppsl_model_populated_cb, (gpointer)page);
565
566 gtk_tree_selection_select_path (selection, path);
567 gtk_tree_path_free (path);
568 }
569
570 g_signal_connect (G_OBJECT(priv->tree_view), "button-press-event",
571 G_CALLBACK(treeview_button_press), page);
572 g_signal_connect (G_OBJECT(priv->tree_view), "popup-menu",
573 G_CALLBACK(treeview_popup_menu), page);
574
575
576 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
577 gtk_box_set_homogeneous (GTK_BOX(vbox), false);
578 gtk_paned_pack2 (GTK_PANED(widget), vbox, true, false);
579
580 label = gtk_label_new (
_(
"Upcoming Transactions"));
581 gnc_widget_style_context_add_class (GTK_WIDGET(label), "gnc-class-strong");
582 gtk_widget_set_margin_start (GTK_WIDGET(label), 6);
583 gnc_label_set_alignment (label, 0.0, 0);
584 gtk_widget_show (label);
585
586 gtk_box_pack_start (GTK_BOX(vbox), label, false, false, 0);
587 gtk_widget_show (vbox);
588
589
590 swin = gtk_scrolled_window_new (nullptr, nullptr);
591 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(swin),
592 GTK_POLICY_AUTOMATIC,
593 GTK_POLICY_AUTOMATIC);
594 gtk_box_pack_start (GTK_BOX(vbox), swin, true, true, 5);
595 gtk_widget_show (swin);
596
597 {
598 priv->dense_cal_model = gnc_sx_instance_dense_cal_adapter_new (GNC_SX_INSTANCE_MODEL(priv->instances));
599 priv->gdcal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model (window, GNC_DENSE_CAL_MODEL(priv->dense_cal_model)));
600 g_object_ref_sink (priv->gdcal);
601
602
603 auto num_months =
gnc_prefs_get_int (GNC_PREFS_GROUP_SXED, GNC_PREF_NUM_OF_MONTHS);
604 if (num_months == 0)
605 {
606 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.");
607 num_months = 12;
608 }
609 gnc_dense_cal_set_num_months (priv->gdcal, num_months);
610
611 gtk_container_add (GTK_CONTAINER(swin), GTK_WIDGET(priv->gdcal));
612 }
613
614 priv->gnc_component_id = gnc_register_gui_component ("plugin-page-sx-list",
615 gnc_plugin_page_sx_list_refresh_cb,
616 gnc_plugin_page_sx_list_close_cb,
617 page);
618 gnc_gui_component_set_session (priv->gnc_component_id,
619 gnc_get_current_session ());
620
621 g_signal_connect (G_OBJECT(plugin_page), "inserted",
623 nullptr);
624
625 return priv->widget;
626}
627
628
629static void
630gnc_plugin_page_sx_list_destroy_widget (
GncPluginPage *plugin_page)
631{
634
635 page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
636 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
637
638
640
641
642 g_idle_remove_by_data (plugin_page);
643
644 if (priv->widget)
645 {
646 g_object_unref (G_OBJECT(priv->widget));
647 priv->widget = nullptr;
648 }
649
650 if (priv->selected_list)
651 g_list_free (priv->selected_list);
652
653 if (priv->gnc_component_id)
654 {
655 gnc_unregister_gui_component (priv->gnc_component_id);
656 priv->gnc_component_id = 0;
657 }
658}
659
660
668static void
669gnc_plugin_page_sx_list_save_page (
GncPluginPage *plugin_page,
670 GKeyFile *key_file,
671 const gchar *group_name)
672{
675
676 g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(plugin_page));
677 g_return_if_fail (key_file != nullptr);
678 g_return_if_fail (group_name != nullptr);
679
680 page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
681 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
682
683 g_key_file_set_integer (key_file, group_name, "dense_cal_num_months",
684 gnc_dense_cal_get_num_months (priv->gdcal));
685
686 g_key_file_set_integer (key_file, group_name, "paned_position",
687 gtk_paned_get_position (GTK_PANED(priv->widget)));
688}
689
690
700gnc_plugin_page_sx_list_recreate_page (GtkWidget *window,
701 GKeyFile *key_file,
702 const gchar *group_name)
703{
706
707 g_return_val_if_fail (key_file, nullptr);
708 g_return_val_if_fail (group_name, nullptr);
709
710
712 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
713
714
716
717 {
718 GError *err = nullptr;
719 gint num_months = g_key_file_get_integer (key_file, group_name, "dense_cal_num_months", &err);
720 if (err == nullptr)
721 gnc_dense_cal_set_num_months (priv->gdcal, num_months);
722 else
723 g_error_free (err);
724 }
725
726 {
727 GError *err = nullptr;
728 gint paned_position = g_key_file_get_integer (key_file, group_name,
729 "paned_position", &err);
730 if (err == nullptr)
731 gtk_paned_set_position (GTK_PANED(priv->widget), paned_position);
732 else
733 g_error_free (err);
734 }
735
736 return GNC_PLUGIN_PAGE(page);
737}
738
739
740static void
741gnc_plugin_page_sx_list_cmd_new (GSimpleAction *simple,
742 GVariant *parameter,
743 gpointer user_data)
744{
745 auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
747 SchedXaction *new_sx;
748 gboolean new_sx_flag = true;
749
751 {
752 GDate now;
754 GList *schedule;
755
756 g_date_clear (&now, 1);
758 recurrenceSet (r, 1, PERIOD_MONTH, &now, WEEKEND_ADJ_NONE);
760 schedule = g_list_append (schedule, r);
762 }
763 gnc_ui_scheduled_xaction_editor_dialog_create (window, new_sx, new_sx_flag);
764 gppsl_update_selected_list (plugin_page, true, new_sx);
765}
766
767static void
768gnc_plugin_page_sx_list_cmd_refresh (GSimpleAction *simple,
769 GVariant *parameter,
770 gpointer user_data)
771{
772 auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
774
775 g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(plugin_page));
776
777 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(plugin_page);
778 gtk_widget_queue_draw (priv->widget);
779}
780
781static void
782gnc_plugin_page_sx_list_cmd_save_layout (GSimpleAction *simple,
783 GVariant *parameter,
784 gpointer user_data)
785{
786 auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
788 gint paned_position;
789
790 g_return_if_fail (GNC_IS_PLUGIN_PAGE_SX_LIST(plugin_page));
791
792 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(plugin_page);
793
794 paned_position = gtk_paned_get_position (GTK_PANED(priv->widget));
795
797 paned_position);
798
800 gnc_dense_cal_get_num_months (priv->gdcal));
801}
802
803static void
804_edit_sx(gpointer data, gpointer user_data)
805{
806 gnc_ui_scheduled_xaction_editor_dialog_create (GTK_WINDOW(user_data),
807 GNC_SCHEDXACTION(data), false);
808}
809
810static SchedXaction*
811_argument_reorder_fn (GtkTreePath* list_path_data, GncTreeViewSxList* user_tree_view)
812{
813 return gnc_tree_view_sx_list_get_sx_from_path (user_tree_view, list_path_data);
814}
815
816
817static void
818gnc_plugin_page_sx_list_cmd_edit (GSimpleAction *simple,
819 GVariant *parameter,
820 gpointer user_data)
821{
822 auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
825 GtkTreeSelection *selection;
826 GList *selected_paths, *to_edit;
827 GtkTreeModel *model;
828
829 selection = gtk_tree_view_get_selection (priv->tree_view);
830 selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
832 {
833 g_warning ("no selection edit.");
834 return;
835 }
836
838 (GncGMapFunc)_argument_reorder_fn,
839 priv->tree_view);
840
841 gppsl_update_selected_list (plugin_page, true, nullptr);
842 for (GList *list = to_edit; list != nullptr; list = list->next)
843 {
844 DEBUG (
"to-edit [%s]\n", xaccSchedXactionGetName (GNC_SCHEDXACTION(list->data)));
845 gppsl_update_selected_list (plugin_page, false, GNC_SCHEDXACTION(list->data));
846 }
847
848 g_list_foreach (to_edit, (GFunc)_edit_sx, window);
849 g_list_free (to_edit);
850 g_list_foreach (selected_paths, (GFunc)gtk_tree_path_free, nullptr);
851 g_list_free (selected_paths);
852}
853
854
855static void
856gnc_plugin_page_sx_list_cmd_edit_tax_options (GSimpleAction *simple,
857 GVariant *parameter,
858 gpointer user_data)
859{
860 auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
862
863 ENTER (
"(action %p, page %p)", simple, plugin_page);
864 gnc_tax_info_dialog (window, nullptr);
866}
867
868static gboolean
869gppsl_is_enable_column_visible (GtkTreeView *tree_view)
870{
871 gboolean retval = FALSE;
872 GList *columns = gtk_tree_view_get_columns (tree_view);
873
874 for (GList *node = columns; node; node = node->next)
875 {
876 GtkTreeViewColumn *col = GTK_TREE_VIEW_COLUMN(node->data);
877 gint id = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(col), MODEL_COLUMN));
878
879 if (id == SXLTMA_COL_ENABLED)
880 {
881 retval = gtk_tree_view_column_get_visible(col);
882 break;
883 }
884 }
885 g_list_free (columns);
886 return retval;
887}
888
889static gboolean
890gppsl_set_toggle (GtkTreeView *tree_view)
891{
892 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
893 GtkTreeModel *model;
894 GList *sel_list = gtk_tree_selection_get_selected_rows (selection, &model);
895 gint num_selected = gtk_tree_selection_count_selected_rows (selection);
896 gint num_toggled = 0;
897
898 for (GList *node = sel_list; node; node = node->next)
899 {
900 GtkTreePath *path = (GtkTreePath *)node->data;
901 GtkTreeIter iter;
902
903 if (gtk_tree_model_get_iter (model, &iter, path))
904 {
905 gboolean toggled;
906
907 gtk_tree_model_get (model, &iter, SXLTMA_COL_ENABLED, &toggled, -1);
908
909 if (toggled)
910 {
911 num_toggled++;
912 }
913 }
914 gtk_tree_path_free (path);
915 }
916 g_list_free (sel_list);
917
918 return num_toggled != num_selected;
919}
920
921static void
923{
925 GtkTreeView *tree_view = priv->tree_view;
926 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
927 GtkTreeModel *model;
928 GList *sel_list = gtk_tree_selection_get_selected_rows (selection, &model);
929 GList *sx_list = nullptr;
930
931 gppsl_update_selected_list (sx_plugin_page, true, nullptr);
932
933 for (GList *node = sel_list; node; node = node->next)
934 {
935 GtkTreePath *path = (GtkTreePath *)node->data;
936 GncTreeViewSxList *view = GNC_TREE_VIEW_SX_LIST(tree_view);
937 SchedXaction *sx = gnc_tree_view_sx_list_get_sx_from_path (view, path);
938
939 if (sx)
940 {
941 GtkTreeIter iter;
942
943 gppsl_update_selected_list (sx_plugin_page, false, sx);
944
945 if (gtk_tree_model_get_iter (model, &iter, path))
946 {
947 gboolean toggled;
948
949 gtk_tree_model_get (model, &iter, SXLTMA_COL_ENABLED, &toggled, -1);
950 if (enable != toggled)
951 {
952 sx_list = g_list_prepend (sx_list, sx);
953 }
954 }
955 }
956
957 gtk_tree_path_free (path);
958 }
959 g_list_free (sel_list);
960
961 for (GList *node = sx_list; node; node = node->next)
962 {
963 if (node == sx_list)
964 {
965 if (node->next)
966 {
968 }
969 }
970 else if (!node->next)
971 {
973 }
974
975 SchedXaction *sx = GNC_SCHEDXACTION(node->data);
976
977 xaccSchedXactionSetEnabled (sx, enable);
978 }
979 g_list_free (sx_list);
980}
981
982static gboolean
983gppsl_key_press_cb (GtkTreeView *tree_view, GdkEventKey *event, gpointer user_data)
984{
985 if (event->keyval != GDK_KEY_space || !gppsl_is_enable_column_visible (tree_view))
986 {
987 return FALSE;
988 }
989
990 g_signal_stop_emission_by_name (G_OBJECT(tree_view), "key-press-event");
991
992 gboolean enable = gppsl_set_toggle (tree_view);
993
994 gppsl_set_list (GNC_PLUGIN_PAGE_SX_LIST(user_data), enable);
995
996 return TRUE;
997}
998
999
1000static void
1001gppsl_row_activated_cb (GtkTreeView *tree_view,
1002 GtkTreePath *path,
1003 GtkTreeViewColumn *column,
1004 gpointer user_data)
1005{
1009
1010 SchedXaction *sx = gnc_tree_view_sx_list_get_sx_from_path (
1011 GNC_TREE_VIEW_SX_LIST(priv->tree_view), path);
1012 gnc_ui_scheduled_xaction_editor_dialog_create (window, sx, false);
1013 gppsl_update_selected_list (page, true, sx);
1014}
1015
1016
1017static void
1018_destroy_sx(gpointer data, gpointer user_data)
1019{
1020 SchedXactions *sxes;
1021 auto sx = GNC_SCHEDXACTION(data);
1023 book = gnc_get_current_book ();
1024 sxes = gnc_book_get_schedxactions (book);
1025
1026 DEBUG(
"deleting sx [%s]", xaccSchedXactionGetName (sx));
1027
1028 gnc_sxes_del_sx (sxes, sx);
1029 gnc_sx_begin_edit (sx);
1031}
1032
1033
1034static void
1035_destroy_sx_names (gpointer data, gpointer user_data)
1036{
1037 auto sx = GNC_SCHEDXACTION(data);
1038 GList **to_delete_names = (GList**)user_data;
1039 *to_delete_names = g_list_append (*to_delete_names, xaccSchedXactionGetName (sx));
1040}
1041
1042
1043static void
1044gnc_plugin_page_sx_list_cmd_delete (GSimpleAction *simple,
1045 GVariant *parameter,
1046 gpointer user_data)
1047{
1048 auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
1050 GtkTreeSelection *selection = gtk_tree_view_get_selection (priv->tree_view);
1051 GList *selected_paths, *to_delete = nullptr, *to_delete_names = nullptr;
1052 GtkTreeModel *model;
1053 GtkWindow *window;
1054 gchar *message = nullptr;
1055 gint length;
1056 gchar *text_list_of_scheduled_transaction_names = nullptr;
1057
1058 selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
1060 {
1061 g_warning ("no selection for delete.");
1062 return;
1063 }
1064
1066 (GncGMapFunc)_argument_reorder_fn,
1067 priv->tree_view);
1068
1069 g_list_foreach (to_delete, (GFunc)_destroy_sx_names, &to_delete_names);
1070
1072
1073 length = g_list_length (to_delete);
1074
1076
1077
1078 message = g_strdup_printf ("%s\n\n%s",
1079 ngettext ("Do you really want to delete this scheduled transaction?",
1080 "Do you really want to delete these scheduled transactions?",
1081 length),
1082 text_list_of_scheduled_transaction_names);
1083
1084 g_free (text_list_of_scheduled_transaction_names);
1085 g_list_free (to_delete_names);
1086
1087 if (gnc_verify_dialog (window, false, "%s", message))
1088 {
1089 gppsl_update_selected_list (plugin_page, true, nullptr);
1090
1091 g_list_foreach (to_delete, (GFunc)_destroy_sx, nullptr);
1092 }
1093
1094 g_free (message);
1095 g_list_free (to_delete);
1096 g_list_foreach (selected_paths, (GFunc)gtk_tree_path_free, nullptr);
1097 g_list_free (selected_paths);
1098}
1099
1100static void
1101gnc_plugin_page_sx_list_cmd_run (GSimpleAction *simple,
1102 GVariant *parameter,
1103 gpointer user_data)
1104{
1105 auto plugin_page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
1106 auto priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(plugin_page);
1107 auto selection = gtk_tree_view_get_selection (priv->tree_view);
1108 GtkTreeModel *model;
1109 auto selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
1110
1111 if (!selected_paths)
1112 {
1113 PWARN (
"no selection for run.");
1114 return;
1115 }
1116
1117 auto to_run =
gnc_g_list_map (selected_paths, (GncGMapFunc)_argument_reorder_fn, priv->tree_view);
1118
1119 gnc_ui_sx_since_last_run_dialog (gnc_sx_get_select_instances (to_run));
1120
1121 g_list_free (to_run);
1122 g_list_foreach (selected_paths, (GFunc)gtk_tree_path_free, nullptr);
1123 g_list_free (selected_paths);
1124}
1125
const gchar * gnc_plugin_page_get_simple_action_group_name(GncPluginPage *page)
Retrieve the simple action group name associated with this plugin page.
GSimpleActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GSimpleActionGroup object associated with this page.
GtkWidget * gnc_plugin_page_get_window(GncPluginPage *page)
Retrieve a pointer to the GncMainWindow (GtkWindow) containing this page.
void gnc_plugin_page_disconnect_page_changed(GncPluginPage *page)
Disconnect the page_changed_id signal callback.
GAction * gnc_plugin_page_get_action(GncPluginPage *page, const gchar *name)
Retrieve a GAction object associated with this page.
void gnc_plugin_page_add_book(GncPluginPage *page, QofBook *book)
Add a book reference to the specified 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_gdate_set_today(GDate *gd)
Set a GDate to the current day.
void qof_event_resume(void)
Resume engine event generation.
void qof_event_suspend(void)
Suspend all engine events.
GAction * gnc_main_window_find_action(GncMainWindow *window, const gchar *action_name)
Find the GAction in the main window.
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
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 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)
const GList * gnc_gobject_tracking_get_list(const gchar *name)
Get a list of all known objects of a specified type.
gchar * gnc_g_list_stringjoin(GList *list_of_strings, const gchar *sep)
Return a string joining a GList whose elements are gchar* strings.
GList * gnc_g_list_map(GList *list, GncGMapFunc fn, gpointer user_data)
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...
#define DEBUG(format, args...)
Print a debugging message.
#define LEAVE(format, args...)
Print a function exit debugging message.
#define PWARN(format, args...)
Log a warning.
#define ENTER(format, args...)
Print a function entry debugging message.
gint gnc_prefs_get_int(const gchar *group, const gchar *pref_name)
Get an integer value from the preferences backend.
gboolean gnc_prefs_set_int(const gchar *group, const gchar *pref_name, gint value)
Store an integer value into the preferences backend.
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
Creates and initializes a scheduled transaction.
GList * gnc_sx_get_schedule(const SchedXaction *sx)
void xaccSchedXactionDestroy(SchedXaction *sx)
Cleans up and frees a SchedXaction and its associated data.
The class data structure for a content plugin.
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...
const gchar * tab_icon
The relative name of the icon that should be shown on the tab for this page.
const gchar * plugin_name
The textual name of this plugin.
void(* destroy_widget)(GncPluginPage *plugin_page)
Function called to destroy the display widget for a particular type of plugin.
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.
GtkWidget *(* create_widget)(GncPluginPage *plugin_page)
Function called to create the display widget for a particular type of plugin.
gboolean(* focus_page_function)(GncPluginPage *plugin_page)
This function performs specific actions to set the focus on a specific widget.
The instance data structure for a content plugin.
GtkWidget * window
The window that contains the display widget for this plugin.