00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00041 #include "config.h"
00042
00043 #include <gtk/gtk.h>
00044 #include <glib.h>
00045 #include <glib/gi18n.h>
00046 #include "glib-compat.h"
00047 #include <glade/glade-xml.h>
00048 #include "SX-book.h"
00049 #include "Split.h"
00050 #include "Transaction.h"
00051 #include "dialog-sx-editor.h"
00052 #include "dialog-utils.h"
00053 #include "gnc-book.h"
00054 #include "gnc-commodity.h"
00055 #include "gnc-component-manager.h"
00056 #include "gnc-dense-cal.h"
00057 #include "gnc-engine.h"
00058 #include "gnc-event.h"
00059 #include "gnc-exp-parser.h"
00060 #include "gnc-glib-utils.h"
00061 #include "gnc-icons.h"
00062 #include "gnc-main-window.h"
00063 #include "gnc-plugin-page-sx-list.h"
00064 #include "gnc-sx-instance-dense-cal-adapter.h"
00065 #include "gnc-sx-instance-model.h"
00066 #include "gnc-sx-list-tree-model-adapter.h"
00067 #include "gnc-tree-view-sx-list.h"
00068 #include "gnc-ui-util.h"
00069 #include "gnc-ui.h"
00070
00071 #undef G_LOG_DOMAIN
00072 #define G_LOG_DOMAIN "gnc.gui.plugin-page.sx-list"
00073
00074 #define PLUGIN_PAGE_SX_LIST_CM_CLASS "plugin-page-sx-list"
00075 #define GCONF_SECTION "window/pages/sx_list"
00076
00077 typedef struct GncPluginPageSxListPrivate
00078 {
00079 gboolean disposed;
00080
00081 GtkWidget* widget;
00082 gint gnc_component_id;
00083
00084 GladeXML* gxml;
00085 GncSxInstanceDenseCalAdapter *dense_cal_model;
00086 GncDenseCal* gdcal;
00087
00088 GncSxInstanceModel* instances;
00089 GtkTreeView* tree_view;
00090 } GncPluginPageSxListPrivate;
00091
00092 #define GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(o) \
00093 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_PLUGIN_PAGE_SX_LIST, GncPluginPageSxListPrivate))
00094
00095 static GObjectClass *parent_class = NULL;
00096
00097
00098
00099
00100
00101 static void gnc_plugin_page_sx_list_class_init (GncPluginPageSxListClass *klass);
00102 static void gnc_plugin_page_sx_list_init (GncPluginPageSxList *plugin_page);
00103 static void gnc_plugin_page_sx_list_dispose(GObject *object);
00104 static void gnc_plugin_page_sx_list_finalize(GObject *object);
00105
00106 static GtkWidget *gnc_plugin_page_sx_list_create_widget (GncPluginPage *plugin_page);
00107 static void gnc_plugin_page_sx_list_destroy_widget (GncPluginPage *plugin_page);
00108 static void gnc_plugin_page_sx_list_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
00109 static GncPluginPage *gnc_plugin_page_sx_list_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
00110
00111 static void gppsl_row_activated_cb(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data);
00112
00113 static void gnc_plugin_page_sx_list_cmd_new(GtkAction *action, GncPluginPageSxList *page);
00114 static void gnc_plugin_page_sx_list_cmd_edit(GtkAction *action, GncPluginPageSxList *page);
00115 static void gnc_plugin_page_sx_list_cmd_delete(GtkAction *action, GncPluginPageSxList *page);
00116
00117
00118 static GtkActionEntry gnc_plugin_page_sx_list_actions [] = {
00119 { "SxListAction", NULL, N_("_Scheduled"), NULL, NULL, NULL },
00120 { "SxListNewAction", GNC_STOCK_NEW_ACCOUNT, N_("_New"), NULL,
00121 N_("Create a new scheduled transaction"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_new) },
00122 { "SxListEditAction", GNC_STOCK_EDIT_ACCOUNT, N_("_Edit"), NULL,
00123 N_("Edit the selected scheduled transaction"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_edit) },
00124 { "SxListDeleteAction", GNC_STOCK_DELETE_ACCOUNT, N_("_Delete"), NULL,
00125 N_("Delete the selected scheduled transaction"), G_CALLBACK(gnc_plugin_page_sx_list_cmd_delete) },
00126 };
00128 static guint gnc_plugin_page_sx_list_n_actions = G_N_ELEMENTS (gnc_plugin_page_sx_list_actions);
00129
00130 GType
00131 gnc_plugin_page_sx_list_get_type (void)
00132 {
00133 static GType gnc_plugin_page_sx_list_type = 0;
00134
00135 if (gnc_plugin_page_sx_list_type == 0) {
00136 static const GTypeInfo our_info = {
00137 sizeof (GncPluginPageSxListClass),
00138 NULL,
00139 NULL,
00140 (GClassInitFunc) gnc_plugin_page_sx_list_class_init,
00141 NULL,
00142 NULL,
00143 sizeof (GncPluginPageSxList),
00144 0,
00145 (GInstanceInitFunc) gnc_plugin_page_sx_list_init
00146 };
00147
00148 gnc_plugin_page_sx_list_type = g_type_register_static (GNC_TYPE_PLUGIN_PAGE,
00149 GNC_PLUGIN_PAGE_SX_LIST_NAME,
00150 &our_info, 0);
00151 }
00152
00153 return gnc_plugin_page_sx_list_type;
00154 }
00155
00156 GncPluginPage *
00157 gnc_plugin_page_sx_list_new (void)
00158 {
00159 GncPluginPageSxList *plugin_page;
00160 plugin_page = g_object_new(GNC_TYPE_PLUGIN_PAGE_SX_LIST, NULL);
00161 return GNC_PLUGIN_PAGE(plugin_page);
00162 }
00163
00164 static void
00165 gnc_plugin_page_sx_list_class_init (GncPluginPageSxListClass *klass)
00166 {
00167 GObjectClass *object_class = G_OBJECT_CLASS(klass);
00168 GncPluginPageClass *gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS(klass);
00169
00170 parent_class = g_type_class_peek_parent(klass);
00171
00172 object_class->dispose = gnc_plugin_page_sx_list_dispose;
00173 object_class->finalize = gnc_plugin_page_sx_list_finalize;
00174
00175 gnc_plugin_class->tab_icon = GNC_STOCK_ACCOUNT;
00176 gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_SX_LIST_NAME;
00177 gnc_plugin_class->create_widget = gnc_plugin_page_sx_list_create_widget;
00178 gnc_plugin_class->destroy_widget = gnc_plugin_page_sx_list_destroy_widget;
00179 gnc_plugin_class->save_page = gnc_plugin_page_sx_list_save_page;
00180 gnc_plugin_class->recreate_page = gnc_plugin_page_sx_list_recreate_page;
00181
00182 g_type_class_add_private(klass, sizeof(GncPluginPageSxListPrivate));
00183 }
00184
00185 static void
00186 gnc_plugin_page_sx_list_init (GncPluginPageSxList *plugin_page)
00187 {
00188 GtkActionGroup *action_group;
00189 GncPluginPageSxListPrivate *priv;
00190 GncPluginPage *parent;
00191
00192 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(plugin_page);
00193
00194
00195 parent = GNC_PLUGIN_PAGE(plugin_page);
00196 g_object_set(G_OBJECT(plugin_page),
00197 "page-name", _("Scheduled Transactions"),
00198 "page-uri", "default:",
00199 "ui-description", "gnc-plugin-page-sx-list-ui.xml",
00200 NULL);
00201
00202 gnc_plugin_page_add_book(parent, gnc_get_current_book());
00203 action_group =
00204 gnc_plugin_page_create_action_group(parent,
00205 "GncPluginPageSxListActions");
00206 gtk_action_group_add_actions(action_group,
00207 gnc_plugin_page_sx_list_actions,
00208 gnc_plugin_page_sx_list_n_actions,
00209 plugin_page);
00210
00211 }
00212
00213 static void
00214 gnc_plugin_page_sx_list_dispose(GObject *object)
00215 {
00216 GncPluginPageSxList *page;
00217 GncPluginPageSxListPrivate *priv;
00218
00219 page = GNC_PLUGIN_PAGE_SX_LIST (object);
00220 g_return_if_fail(GNC_IS_PLUGIN_PAGE_SX_LIST (page));
00221 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
00222 g_return_if_fail(priv != NULL);
00223
00224 g_return_if_fail(!priv->disposed);
00225 priv->disposed = TRUE;
00226
00227 g_object_unref(G_OBJECT(priv->dense_cal_model));
00228 priv->dense_cal_model = NULL;
00229 gtk_widget_unref(GTK_WIDGET(priv->gdcal));
00230 priv->gdcal = NULL;
00231 g_object_unref(G_OBJECT(priv->instances));
00232 priv->instances = NULL;
00233
00234 G_OBJECT_CLASS (parent_class)->dispose(object);
00235 }
00236
00237 static void
00238 gnc_plugin_page_sx_list_finalize (GObject *object)
00239 {
00240 GncPluginPageSxList *page;
00241 GncPluginPageSxListPrivate *priv;
00242
00243 page = GNC_PLUGIN_PAGE_SX_LIST (object);
00244 g_return_if_fail(GNC_IS_PLUGIN_PAGE_SX_LIST (page));
00245 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
00246 g_return_if_fail(priv != NULL);
00247
00248 G_OBJECT_CLASS (parent_class)->finalize (object);
00249 }
00250
00251
00252 static void
00253 gnc_plugin_page_sx_list_refresh_cb (GHashTable *changes, gpointer user_data)
00254 {
00255 GncPluginPageSxList *page = user_data;
00256 GncPluginPageSxListPrivate *priv;
00257
00258 g_return_if_fail(GNC_IS_PLUGIN_PAGE_SX_LIST(page));
00259
00260
00261 if (changes)
00262 return;
00263
00264 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
00265 gtk_widget_queue_draw(priv->widget);
00266 }
00267
00268 static void
00269 gnc_plugin_page_sx_list_close_cb (gpointer user_data)
00270 {
00271 GncPluginPage *plugin_page;
00272 GncPluginPageSxList *page;
00273
00274 plugin_page = GNC_PLUGIN_PAGE(user_data);
00275 page = GNC_PLUGIN_PAGE_SX_LIST (plugin_page);
00276 gnc_main_window_close_page(plugin_page);
00277 }
00278
00279 static void
00280 gppsl_selection_changed_cb(GtkTreeSelection *selection, gpointer user_data)
00281 {
00282 GncPluginPage *page;
00283 GtkAction *edit_action, *delete_action;
00284 gboolean selection_state = TRUE;
00285
00286 page = GNC_PLUGIN_PAGE(user_data);
00287 edit_action = gnc_plugin_page_get_action(page, "SxListEditAction");
00288 delete_action = gnc_plugin_page_get_action(page, "SxListDeleteAction");
00289 selection_state
00290 = gtk_tree_selection_count_selected_rows(selection) == 0
00291 ? FALSE
00292 : TRUE;
00293 gtk_action_set_sensitive(edit_action, selection_state);
00294 gtk_action_set_sensitive(delete_action, selection_state);
00295 }
00296
00297 static GtkWidget *
00298 gnc_plugin_page_sx_list_create_widget (GncPluginPage *plugin_page)
00299 {
00300 GncPluginPageSxList *page;
00301 GncPluginPageSxListPrivate *priv;
00302
00303 page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
00304 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
00305 if (priv->widget != NULL)
00306 return priv->widget;
00307
00308 priv->gxml = gnc_glade_xml_new("sched-xact.glade", "sx-list-vbox");
00309 priv->widget = glade_xml_get_widget(priv->gxml, "sx-list-vbox");
00310
00311 {
00312
00313
00314
00315 gtk_paned_set_position(GTK_PANED(priv->widget), 160);
00316 }
00317
00318 {
00319 GDate end;
00320 g_date_clear(&end, 1);
00321 g_date_set_time_t(&end, time(NULL));
00322 g_date_add_years(&end, 1);
00323 priv->instances = GNC_SX_INSTANCE_MODEL(gnc_sx_get_instances(&end, TRUE));
00324 }
00325
00326 {
00327 GtkAction *edit_action, *delete_action;
00328 edit_action = gnc_plugin_page_get_action(GNC_PLUGIN_PAGE(page), "SxListEditAction");
00329 delete_action = gnc_plugin_page_get_action(GNC_PLUGIN_PAGE(page), "SxListDeleteAction");
00330 gtk_action_set_sensitive(edit_action, FALSE);
00331 gtk_action_set_sensitive(delete_action, FALSE);
00332 }
00333
00334 {
00335 GtkContainer *tree_view_container;
00336 GtkTreeSelection *selection;
00337
00338 tree_view_container = GTK_CONTAINER(glade_xml_get_widget(priv->gxml, "sx-list-tree-view-container"));
00339 priv->tree_view = GTK_TREE_VIEW(gnc_tree_view_sx_list_new(priv->instances));
00340 g_object_set(G_OBJECT(priv->tree_view),
00341 "gconf-section", GCONF_SECTION,
00342 "show-column-menu", TRUE,
00343 NULL);
00344 gtk_container_add(tree_view_container, GTK_WIDGET(priv->tree_view));
00345
00346 selection = gtk_tree_view_get_selection(priv->tree_view);
00347 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
00348 g_signal_connect(G_OBJECT(selection), "changed", (GCallback)gppsl_selection_changed_cb, (gpointer)page);
00349 g_signal_connect(G_OBJECT(priv->tree_view), "row-activated", (GCallback)gppsl_row_activated_cb, (gpointer)page);
00350 }
00351
00352 {
00353 GtkWidget *w;
00354
00355 priv->dense_cal_model = gnc_sx_instance_dense_cal_adapter_new(GNC_SX_INSTANCE_MODEL(priv->instances));
00356 priv->gdcal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model(GNC_DENSE_CAL_MODEL(priv->dense_cal_model)));
00357 #ifdef HAVE_GTK_2_10
00358 g_object_ref_sink(priv->gdcal);
00359 #else
00360 g_object_ref(G_OBJECT(priv->gdcal));
00361 gtk_object_sink(GTK_OBJECT(priv->gdcal));
00362 #endif
00363
00364 gnc_dense_cal_set_months_per_col(priv->gdcal, 4);
00365 gnc_dense_cal_set_num_months(priv->gdcal, 12);
00366
00367 w = glade_xml_get_widget(priv->gxml, "upcoming_cal_hbox");
00368 gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(priv->gdcal));
00369 gtk_widget_show_all(w);
00370 }
00371
00372 priv->gnc_component_id = gnc_register_gui_component("plugin-page-sx-list",
00373 gnc_plugin_page_sx_list_refresh_cb,
00374 gnc_plugin_page_sx_list_close_cb,
00375 page);
00376
00377 return priv->widget;
00378 }
00379
00380 static void
00381 gnc_plugin_page_sx_list_destroy_widget (GncPluginPage *plugin_page)
00382 {
00383 GncPluginPageSxList *page;
00384 GncPluginPageSxListPrivate *priv;
00385
00386 page = GNC_PLUGIN_PAGE_SX_LIST (plugin_page);
00387 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
00388
00389 if (priv->widget) {
00390 g_object_unref(G_OBJECT(priv->widget));
00391 priv->widget = NULL;
00392 }
00393
00394 if (priv->gnc_component_id) {
00395 gnc_unregister_gui_component(priv->gnc_component_id);
00396 priv->gnc_component_id = 0;
00397 }
00398 }
00399
00408 static void
00409 gnc_plugin_page_sx_list_save_page (GncPluginPage *plugin_page,
00410 GKeyFile *key_file,
00411 const gchar *group_name)
00412 {
00413 GncPluginPageSxList *page;
00414 GncPluginPageSxListPrivate *priv;
00415
00416 g_return_if_fail(GNC_IS_PLUGIN_PAGE_SX_LIST(plugin_page));
00417 g_return_if_fail(key_file != NULL);
00418 g_return_if_fail(group_name != NULL);
00419
00420 page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
00421 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
00422
00423 g_key_file_set_integer(key_file, group_name, "dense_cal_num_months",
00424 gnc_dense_cal_get_num_months(priv->gdcal));
00425
00426 g_key_file_set_integer(key_file, group_name, "paned_position",
00427 gtk_paned_get_position(GTK_PANED(priv->widget)));
00428 }
00429
00438 static GncPluginPage *
00439 gnc_plugin_page_sx_list_recreate_page (GtkWidget *window,
00440 GKeyFile *key_file,
00441 const gchar *group_name)
00442 {
00443 GncPluginPageSxList *page;
00444 GncPluginPageSxListPrivate *priv;
00445
00446 g_return_val_if_fail(key_file, NULL);
00447 g_return_val_if_fail(group_name, NULL);
00448
00449
00450 page = GNC_PLUGIN_PAGE_SX_LIST(gnc_plugin_page_sx_list_new());
00451 priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
00452
00453
00454 gnc_main_window_open_page(GNC_MAIN_WINDOW(window), GNC_PLUGIN_PAGE(page));
00455
00456 {
00457 GError *err = NULL;
00458 gint num_months = g_key_file_get_integer(key_file, group_name, "dense_cal_num_months", &err);
00459 if (err == NULL)
00460 gnc_dense_cal_set_num_months(priv->gdcal, num_months);
00461 else
00462 g_error_free(err);
00463 }
00464
00465 {
00466 GError *err = NULL;
00467 gint paned_position = g_key_file_get_integer(key_file, group_name,
00468 "paned_position", &err);
00469 if (err == NULL)
00470 gtk_paned_set_position(GTK_PANED(priv->widget), paned_position);
00471 else
00472 g_error_free(err);
00473 }
00474
00475 return GNC_PLUGIN_PAGE(page);
00476 }
00477
00478 static void
00479 gnc_plugin_page_sx_list_cmd_new(GtkAction *action, GncPluginPageSxList *page)
00480 {
00481 SchedXaction *new_sx;
00482 gboolean new_sx_flag = TRUE;
00483
00484 new_sx = xaccSchedXactionMalloc(gnc_get_current_book());
00485 {
00486 GDate now;
00487 Recurrence *r = g_new0(Recurrence, 1);
00488 GList *schedule;
00489
00490 g_date_clear(&now, 1);
00491 g_date_set_time_t(&now, time(NULL));
00492 recurrenceSet(r, 1, PERIOD_MONTH, &now);
00493 schedule = gnc_sx_get_schedule(new_sx);
00494 schedule = g_list_append(schedule, r);
00495 gnc_sx_set_schedule(new_sx, schedule);
00496 }
00497 gnc_ui_scheduled_xaction_editor_dialog_create(new_sx, new_sx_flag);
00498 }
00499
00500 static void
00501 _edit_sx(gpointer data, gpointer user_data)
00502 {
00503 gnc_ui_scheduled_xaction_editor_dialog_create((SchedXaction*)data, FALSE);
00504 }
00505
00506 static SchedXaction*
00507 _argument_reorder_fn(GtkTreePath* list_path_data, GncTreeViewSxList* user_tree_view)
00508 {
00509 return gnc_tree_view_sx_list_get_sx_from_path(user_tree_view, list_path_data);
00510 }
00511
00512 static void
00513 gnc_plugin_page_sx_list_cmd_edit(GtkAction *action, GncPluginPageSxList *page)
00514 {
00515 GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
00516 GtkTreeSelection *selection;
00517 GList *selected_paths, *to_edit;
00518 GtkTreeModel *model;
00519
00520 selection = gtk_tree_view_get_selection(priv->tree_view);
00521 selected_paths = gtk_tree_selection_get_selected_rows(selection, &model);
00522 if (g_list_length(selected_paths) == 0)
00523 {
00524 g_warning("no selection edit.");
00525 return;
00526 }
00527
00528 to_edit = gnc_g_list_map(selected_paths,
00529 (GncGMapFunc)_argument_reorder_fn,
00530 priv->tree_view);
00531 g_list_foreach(to_edit, (GFunc)_edit_sx, NULL);
00532 g_list_free(to_edit);
00533 g_list_foreach(selected_paths, (GFunc)gtk_tree_path_free, NULL);
00534 g_list_free(selected_paths);
00535 }
00536
00537 static void
00538 gppsl_row_activated_cb(GtkTreeView *tree_view,
00539 GtkTreePath *path,
00540 GtkTreeViewColumn *column,
00541 gpointer user_data)
00542 {
00543 GncPluginPageSxList *page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
00544 GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
00545
00546 SchedXaction *sx = gnc_tree_view_sx_list_get_sx_from_path(GNC_TREE_VIEW_SX_LIST(priv->tree_view), path);
00547 gnc_ui_scheduled_xaction_editor_dialog_create(sx, FALSE);
00548 }
00549
00550
00551 static void
00552 _destroy_sx(gpointer data, gpointer user_data)
00553 {
00554 SchedXactions *sxes;
00555 SchedXaction *sx = (SchedXaction*)data;
00556 GNCBook *book;
00557 book = gnc_get_current_book();
00558 sxes = gnc_book_get_schedxactions(book);
00559 gnc_sxes_del_sx(sxes, sx);
00560 xaccSchedXactionFree(sx);
00561 }
00562
00563 static void
00564 gnc_plugin_page_sx_list_cmd_delete(GtkAction *action, GncPluginPageSxList *page)
00565 {
00566 GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
00567 GtkTreeSelection *selection;
00568 GList *selected_paths, *to_delete = NULL;
00569 GtkTreeModel *model;
00570
00571 selection = gtk_tree_view_get_selection(priv->tree_view);
00572 selected_paths = gtk_tree_selection_get_selected_rows(selection, &model);
00573 if (g_list_length(selected_paths) == 0)
00574 {
00575 g_warning("no selection for delete.");
00576 return;
00577 }
00578
00579 to_delete = gnc_g_list_map(selected_paths,
00580 (GncGMapFunc)_argument_reorder_fn,
00581 priv->tree_view);
00582 {
00583 GList *list;
00584 for (list = to_delete; list != NULL; list = list->next)
00585 {
00586 g_debug("to-delete [%s]\n", xaccSchedXactionGetName((SchedXaction*)list->data));
00587 }
00588 }
00589
00590
00591
00592
00593
00594 if (gnc_verify_dialog(NULL, FALSE, _("Do you really want to delete this scheduled transaction?")))
00595 {
00596 g_list_foreach(to_delete, (GFunc)_destroy_sx, NULL);
00597 }
00598
00599 g_list_free(to_delete);
00600 g_list_foreach(selected_paths, (GFunc)gtk_tree_path_free, NULL);
00601 g_list_free(selected_paths);
00602 }
00603