29 #include <glib/gi18n.h>
30 #include <gdk/gdkkeysyms.h>
37 #include "reconcile-view.h"
38 #include "search-param.h"
39 #include "gnc-component-manager.h"
41 #define GNC_PREF_CHECK_CLEARED "check-cleared"
55 static guint reconcile_view_signals[LAST_SIGNAL] = {0};
60 static void gnc_reconcile_view_finalize (GObject *
object);
61 static gpointer gnc_reconcile_view_is_reconciled (gpointer item, gpointer user_data);
62 static void gnc_reconcile_view_line_toggled (
GNCQueryView *qview, gpointer item, gpointer user_data);
63 static void gnc_reconcile_view_double_click_entry (
GNCQueryView *qview, gpointer item, gpointer user_data);
64 static void gnc_reconcile_view_row_selected (
GNCQueryView *qview, gpointer item, gpointer user_data);
65 static gboolean gnc_reconcile_view_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
66 static gboolean gnc_reconcile_view_tooltip_cb (
GNCQueryView *qview, gint x, gint y, gboolean keyboard_mode,
67 GtkTooltip* tooltip, gpointer* user_data);
70 gnc_reconcile_view_get_type (
void)
72 static GType gnc_reconcile_view_type = 0;
74 if (gnc_reconcile_view_type == 0)
76 static const GTypeInfo gnc_reconcile_view_info =
81 (GClassInitFunc) gnc_reconcile_view_class_init,
86 (GInstanceInitFunc) gnc_reconcile_view_init
89 gnc_reconcile_view_type = g_type_register_static (GNC_TYPE_QUERY_VIEW,
91 &gnc_reconcile_view_info, 0);
93 return gnc_reconcile_view_type;
98 gnc_reconcile_view_tooltip_cb (
GNCQueryView *qview, gint x, gint y,
99 gboolean keyboard_mode, GtkTooltip *tooltip, gpointer *user_data)
104 if (gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (qview), &x, &y, keyboard_mode, &model, NULL, &iter))
106 GtkTreeViewColumn *col;
108 gint col_pos, col_width;
109 gchar* desc_text = NULL;
112 if (keyboard_mode == FALSE)
114 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (qview), x, y, NULL, &col, NULL, NULL) == FALSE)
118 gtk_tree_view_get_cursor (GTK_TREE_VIEW (qview), NULL, &col);
120 cols = gtk_tree_view_get_columns (GTK_TREE_VIEW (qview));
121 col_width = gtk_tree_view_column_get_width (col);
122 col_pos = g_list_index (cols, col);
129 gtk_tree_model_get (model, &iter, 3, &desc_text, -1);
138 layout = gtk_widget_create_pango_layout (GTK_WIDGET (qview), desc_text);
139 pango_layout_get_pixel_size (layout, &text_width, NULL);
140 g_object_unref (layout);
143 if ((text_width + 10) <= col_width)
149 if (keyboard_mode == FALSE)
152 GtkWindow *tip_win = NULL;
153 GdkWindow *parent_window, *temp_window;
154 GList *win_list, *node;
156 parent_window = gtk_widget_get_parent_window (GTK_WIDGET (qview));
157 temp_window = gdk_window_get_pointer (parent_window, &cur_x, &cur_y, NULL);
158 gdk_window_get_origin (parent_window, &root_x, &root_y);
160 screen = gtk_widget_get_screen (GTK_WIDGET (qview));
163 win_list = gtk_window_list_toplevels ();
167 for (node = win_list; node != NULL; node = node->next)
169 if (g_strcmp0 (gtk_widget_get_name (node->data),
"gtk-tooltip") == 0)
170 tip_win = node->data;
172 g_list_free (win_list);
174 gtk_tooltip_set_text (tooltip, desc_text);
176 if (GTK_IS_WINDOW (tip_win))
178 GdkRectangle monitor;
179 GtkRequisition requisition;
183 gtk_widget_size_request (GTK_WIDGET (tip_win), &requisition);
185 x = root_x + cur_x + 10;
186 y = root_y + cur_y + 10;
188 monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
189 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
191 if (x + requisition.width > monitor.x + monitor.width)
192 x -= x - (monitor.x + monitor.width) + requisition.width;
193 else if (x < monitor.x)
196 if (y + requisition.height > monitor.y + monitor.height)
197 y -= y - (monitor.y + monitor.height) + requisition.height;
199 gtk_window_move (tip_win, x, y);
202 gtk_tooltip_set_text (tooltip, desc_text);
224 GtkTreeViewColumn *col;
225 GtkTreeSelection *selection;
227 GtkCellRenderer *cr0;
228 gboolean inv_sort = FALSE;
230 if (view->view_type == RECLIST_CREDIT)
234 gnc_query_view_construct (qview, view->column_list, query);
235 gnc_query_view_set_numerics (qview, TRUE, inv_sort);
238 col = gtk_tree_view_get_column (GTK_TREE_VIEW (qview), 2);
239 gtk_tree_view_column_set_expand (col, TRUE);
242 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (col));
243 cr0 = g_list_nth_data (renderers, 0);
244 g_list_free (renderers);
245 g_object_set (cr0,
"ellipsize", PANGO_ELLIPSIZE_END, NULL );
247 gtk_widget_set_has_tooltip (GTK_WIDGET (qview), TRUE);
250 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (qview));
251 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
254 g_signal_connect (G_OBJECT (qview),
"column_toggled",
255 G_CALLBACK (gnc_reconcile_view_line_toggled), view);
256 g_signal_connect (G_OBJECT (qview),
"double_click_entry",
257 G_CALLBACK (gnc_reconcile_view_double_click_entry), view);
258 g_signal_connect (G_OBJECT (qview),
"row_selected",
259 G_CALLBACK (gnc_reconcile_view_row_selected), view);
260 g_signal_connect (G_OBJECT (qview),
"key_press_event",
261 G_CALLBACK (gnc_reconcile_view_key_press_cb), view);
262 g_signal_connect (G_OBJECT (qview),
"query-tooltip",
263 G_CALLBACK (gnc_reconcile_view_tooltip_cb), view);
268 gnc_reconcile_view_new (
Account *account, GNCReconcileViewType type,
272 GtkListStore *liststore;
273 gboolean include_children, auto_check;
274 GList *accounts = NULL;
278 g_return_val_if_fail (account, NULL);
279 g_return_val_if_fail ((type == RECLIST_DEBIT) ||
280 (type == RECLIST_CREDIT), NULL);
282 view = g_object_new (GNC_TYPE_RECONCILE_VIEW, NULL);
286 liststore = gtk_list_store_new (6, G_TYPE_POINTER, G_TYPE_STRING,
287 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN );
288 gtk_tree_view_set_model (GTK_TREE_VIEW (view), GTK_TREE_MODEL (liststore));
289 g_object_unref (liststore);
291 view->account = account;
292 view->view_type = type;
293 view->statement_date = statement_date;
295 query = qof_query_create_for (GNC_ID_SPLIT);
299 if (include_children)
303 accounts = g_list_prepend (accounts, account);
307 g_list_free (accounts);
310 if (type == RECLIST_CREDIT)
311 xaccQueryAddValueMatch(query, gnc_numeric_zero (),
312 QOF_NUMERIC_MATCH_CREDIT,
313 QOF_COMPARE_GTE, QOF_QUERY_AND);
315 xaccQueryAddValueMatch(query, gnc_numeric_zero (),
316 QOF_NUMERIC_MATCH_DEBIT,
317 QOF_COMPARE_GTE, QOF_QUERY_AND);
320 xaccQueryAddClearedMatch (query, CLEARED_NO | CLEARED_CLEARED, QOF_QUERY_AND);
323 gnc_reconcile_view_construct (view, query);
330 for (splits =
qof_query_run (query); splits; splits = splits->next)
332 Split *split = splits->data;
337 g_assert (recn ==
NREC || recn ==
CREC);
341 g_hash_table_insert (view->reconciled, split, split);
348 return GTK_WIDGET (view);
356 GList *columns = NULL;
358 view->reconciled = g_hash_table_new (NULL, NULL);
359 view->account = NULL;
360 view->sibling = NULL;
362 param = gnc_search_param_new();
363 gnc_search_param_set_param_fcn (param, QOF_TYPE_BOOLEAN,
364 gnc_reconcile_view_is_reconciled, view);
365 gnc_search_param_set_title (param, _(
"Reconciled:R") + 11);
366 gnc_search_param_set_justify (param, GTK_JUSTIFY_CENTER);
367 gnc_search_param_set_passive (param, TRUE);
368 gnc_search_param_set_non_resizeable (param, TRUE);
369 columns = g_list_prepend (columns, param);
370 columns = gnc_search_param_prepend_with_justify (columns, _(
"Amount"),
374 columns = gnc_search_param_prepend (columns, _(
"Description"), NULL,
375 GNC_ID_SPLIT, SPLIT_TRANS,
376 TRANS_DESCRIPTION, NULL);
377 columns = gnc_search_param_prepend_with_justify (columns, _(
"Num"),
380 SPLIT_TRANS, TRANS_NUM, NULL);
381 columns = gnc_search_param_prepend (columns, _(
"Date"), NULL, GNC_ID_SPLIT,
382 SPLIT_TRANS, TRANS_DATE_POSTED, NULL);
384 view->column_list = columns;
391 GObjectClass *object_class;
393 object_class = G_OBJECT_CLASS (klass);
395 parent_class = g_type_class_peek_parent (klass);
397 reconcile_view_signals[TOGGLE_RECONCILED] =
398 g_signal_new(
"toggle_reconciled",
399 G_OBJECT_CLASS_TYPE (object_class),
404 g_cclosure_marshal_VOID__POINTER,
408 reconcile_view_signals[LINE_SELECTED] =
409 g_signal_new(
"line_selected",
410 G_OBJECT_CLASS_TYPE (object_class),
415 g_cclosure_marshal_VOID__POINTER,
419 reconcile_view_signals[DOUBLE_CLICK_SPLIT] =
420 g_signal_new(
"double_click_split",
421 G_OBJECT_CLASS_TYPE (object_class),
426 g_cclosure_marshal_VOID__POINTER,
430 object_class->finalize = gnc_reconcile_view_finalize;
432 klass->toggle_reconciled = NULL;
433 klass->line_selected = NULL;
434 klass->double_click_split = NULL;
443 g_return_if_fail (GNC_IS_RECONCILE_VIEW (view));
444 g_return_if_fail (view->reconciled != NULL);
446 current = g_hash_table_lookup (view->reconciled, split);
449 g_hash_table_insert (view->reconciled, split, split);
451 g_hash_table_remove (view->reconciled, split);
458 GList *child_accounts, *node;
469 child_accounts = g_list_prepend (child_accounts, account);
482 other_split = node->data;
484 if (other_split == split)
487 if (!g_list_find (child_accounts, other_account))
492 current_view = view->sibling;
493 if (!gnc_query_view_item_in_view (GNC_QUERY_VIEW (current_view), other_split))
497 if (!gnc_query_view_item_in_view (GNC_QUERY_VIEW (current_view), other_split))
503 model = gtk_tree_view_get_model (GTK_TREE_VIEW (current_view));
504 valid = gtk_tree_model_get_iter_first (model, &iter);
509 gtk_tree_model_get (model, &iter, 0, &pointer, -1);
511 if(pointer == other_split)
514 gtk_tree_model_get (model, &iter, 5, &toggled, -1);
515 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 5, !toggled, -1);
519 valid = gtk_tree_model_iter_next (model, &iter);
523 gnc_reconcile_view_toggle_split (current_view, other_split);
525 g_list_free (child_accounts);
532 gboolean include_children;
534 g_return_if_fail (GNC_IS_RECONCILE_VIEW (view));
535 g_return_if_fail (view->reconciled != NULL);
537 gnc_reconcile_view_toggle_split (view, split);
540 if (include_children)
541 gnc_reconcile_view_toggle_children (view->account, view, split);
543 g_signal_emit (G_OBJECT (view),
544 reconcile_view_signals[TOGGLE_RECONCILED], 0, split);
558 g_return_if_fail (user_data);
559 g_return_if_fail (GNC_IS_QUERY_VIEW (qview));
563 model = gtk_tree_view_get_model (GTK_TREE_VIEW (qview));
564 gtk_tree_model_iter_nth_child (model, &iter, NULL, qview->toggled_row);
565 gtk_list_store_set (GTK_LIST_STORE (model), &iter, qview->toggled_column, GPOINTER_TO_INT(item), -1);
566 gtk_tree_model_get (model, &iter, 0, &entry, -1);
568 gnc_reconcile_view_toggle (view, entry);
573 gnc_reconcile_view_double_click_entry (
GNCQueryView *qview,
579 g_return_if_fail (user_data);
580 g_return_if_fail (GNC_IS_QUERY_VIEW (qview));
584 g_signal_emit(G_OBJECT (view),
585 reconcile_view_signals[DOUBLE_CLICK_SPLIT], 0, item);
596 g_return_if_fail(user_data);
597 g_return_if_fail(GNC_IS_QUERY_VIEW(qview));
601 g_signal_emit(G_OBJECT(view),
602 reconcile_view_signals[LINE_SELECTED], 0, item);
610 GtkTreeSelection *selection;
618 model = gtk_tree_view_get_model (GTK_TREE_VIEW (qview));
619 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (qview));
620 list_of_rows = gtk_tree_selection_get_selected_rows (selection, &model);
623 for(node = list_of_rows; node; node = node->next)
626 if(gtk_tree_model_get_iter(model, &iter, node->data))
629 gtk_tree_model_get (model, &iter, 0, &entry, -1);
630 gtk_tree_model_get (model, &iter, 5, &toggled, -1);
632 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 5, reconcile, -1);
634 if(reconcile != toggled)
635 gnc_reconcile_view_toggle (view, entry);
637 gtk_tree_path_free(node->data);
639 g_list_free(list_of_rows);
647 GtkTreeSelection *selection;
649 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (qview));
650 return gtk_tree_selection_count_selected_rows (selection);
658 GtkTreeSelection *selection;
664 gint num_toggled = 0;
665 gint num_selected = 0;
667 model = gtk_tree_view_get_model (GTK_TREE_VIEW (qview));
668 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (qview));
669 list_of_rows = gtk_tree_selection_get_selected_rows (selection, &model);
670 num_selected = gtk_tree_selection_count_selected_rows (selection);
673 for(node = list_of_rows; node; node = node->next)
677 if(gtk_tree_model_get_iter(model, &iter, node->data))
680 gtk_tree_model_get (model, &iter, 5, &toggled, -1);
685 gtk_tree_path_free(node->data);
687 g_list_free(list_of_rows);
689 if(num_toggled == num_selected)
697 gnc_reconcile_view_key_press_cb (GtkWidget *widget, GdkEventKey *event,
704 gpointer entry, pointer;
705 gboolean valid, toggle;
707 switch (event->keyval)
710 g_signal_stop_emission_by_name (widget,
"key_press_event");
712 toggle = gnc_reconcile_view_set_toggle (view);
713 gnc_reconcile_view_set_list (view, toggle);
724 gnc_reconcile_view_finalize (GObject *
object)
728 if (view->reconciled != NULL)
730 g_hash_table_destroy (view->reconciled);
731 view->reconciled = NULL;
733 G_OBJECT_CLASS (parent_class)->finalize (
object);
740 g_return_val_if_fail (view != NULL, 0);
741 g_return_val_if_fail (GNC_IS_RECONCILE_VIEW (view), 0);
743 return gnc_query_view_get_num_entries (GNC_QUERY_VIEW (view));
750 g_return_val_if_fail (view != NULL, NULL);
751 g_return_val_if_fail (GNC_IS_RECONCILE_VIEW (view), NULL);
753 return gnc_query_view_get_selected_entry (GNC_QUERY_VIEW (view));
766 gnc_reconcile_view_is_reconciled (gpointer item, gpointer user_data)
771 g_return_val_if_fail (item, NULL);
772 g_return_val_if_fail (view, NULL);
773 g_return_val_if_fail (GNC_IS_RECONCILE_VIEW (view), NULL);
775 if (!view->reconciled)
778 current = g_hash_table_lookup (view->reconciled, item);
779 return GINT_TO_POINTER (current != NULL);
791 grv_refresh_helper (gpointer key, gpointer value, gpointer user_data)
796 if (!gnc_query_view_item_in_view (qview, key))
797 g_hash_table_remove (view->reconciled, key);
805 g_return_if_fail (view != NULL);
806 g_return_if_fail (GNC_IS_RECONCILE_VIEW (view));
808 qview = GNC_QUERY_VIEW (view);
809 gnc_query_view_refresh (qview);
812 if (view->reconciled)
813 g_hash_table_foreach (view->reconciled, grv_refresh_helper, view);
825 grv_balance_hash_helper (gpointer key, gpointer value, gpointer user_data)
838 g_return_val_if_fail (view != NULL, total);
839 g_return_val_if_fail (GNC_IS_RECONCILE_VIEW (view), total);
841 if (view->reconciled == NULL)
844 g_hash_table_foreach (view->reconciled, grv_balance_hash_helper, &total);
861 grv_commit_hash_helper (gpointer key, gpointer value, gpointer user_data)
873 g_return_if_fail (view != NULL);
874 g_return_if_fail (GNC_IS_RECONCILE_VIEW (view));
876 if (view->reconciled == NULL)
879 gnc_suspend_gui_refresh();
880 g_hash_table_foreach (view->reconciled, grv_commit_hash_helper, &date);
881 gnc_resume_gui_refresh();
900 gpointer entry = NULL;
902 g_return_if_fail (view != NULL);
903 g_return_if_fail (GNC_IS_RECONCILE_VIEW (view));
905 if (view->reconciled == NULL)
908 model = gtk_tree_view_get_model (GTK_TREE_VIEW (GNC_QUERY_VIEW (view)));
909 gtk_tree_model_get_iter_first (model, &iter);
911 num_splits = gnc_query_view_get_num_entries (GNC_QUERY_VIEW (view));
913 gnc_suspend_gui_refresh();
914 for (i = 0; i < num_splits; i++)
918 gtk_tree_model_get (model, &iter, 0, &entry, -1);
924 g_hash_table_lookup (view->reconciled, entry))
926 recn = g_hash_table_lookup (view->reconciled, entry) ?
CREC :
NREC;
929 gtk_tree_model_iter_next (model, &iter);
931 gnc_resume_gui_refresh();
945 g_return_if_fail (view != NULL);
946 g_return_if_fail (GNC_IS_RECONCILE_VIEW (view));
948 gnc_query_view_unselect_all (GNC_QUERY_VIEW (view));
962 g_return_val_if_fail (view != NULL, FALSE);
963 g_return_val_if_fail (GNC_IS_RECONCILE_VIEW (view), FALSE);
965 return g_hash_table_size (view->reconciled) != 0;
time64 xaccTransGetDate(const Transaction *trans)
Date and Time handling routines.
utility functions for the GnuCash UI
char xaccSplitGetReconcile(const Split *split)
void xaccSplitSetReconcile(Split *split, char recn)
Transaction * xaccSplitGetParent(const Split *split)
void qof_query_destroy(QofQuery *q)
void qof_query_set_book(QofQuery *q, QofBook *book)
gnc_numeric gnc_numeric_abs(gnc_numeric a)
gdouble gnc_difftime(const time64 secs1, const time64 secs2)
Find the difference in seconds between two time values.
Generic api to store and retrieve preferences.
GList * gnc_account_get_descendants(const Account *account)
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
gboolean xaccAccountGetReconcileChildrenStatus(const Account *acc)
GList * qof_query_run(QofQuery *query)
Account * xaccSplitGetAccount(const Split *s)
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
API for Transactions and Splits (journal entries)
SplitList * xaccTransGetSplitList(const Transaction *trans)
gnc_numeric xaccSplitGetAmount(const Split *split)