1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 Maxime DOYEN
4 * This file is part of HomeBank.
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "list-operation.h"
25 /****************************************************************************/
27 /****************************************************************************/
36 /* our global datas */
37 extern struct HomeBank
*GLOBALS
;
38 extern struct Preferences
*PREFS
;
42 //extern gboolean minor_active;
45 /* This is not pretty. Of course you can also use a
46 * separate compare function for each sort ID value */
48 static gint
list_txn_sort_iter_compare_strings(gchar
*s1
, gchar
*s2
)
50 return hb_string_utf8_compare(s1
, s2
);
55 list_txn_sort_iter_compare_func (GtkTreeModel
*model
,
60 gint sortcol
= GPOINTER_TO_INT(userdata
);
62 Transaction
*ope1
, *ope2
;
65 gtk_tree_model_get(model
, a
, MODEL_TXN_POINTER
, &ope1
, -1);
66 gtk_tree_model_get(model
, b
, MODEL_TXN_POINTER
, &ope2
, -1);
70 case LST_DSPOPE_STATUS
:
71 if(!(retval
= (ope1
->flags
& OF_ADDED
) - (ope2
->flags
& OF_ADDED
) ) )
73 retval
= (ope1
->flags
& OF_CHANGED
) - (ope2
->flags
& OF_CHANGED
);
78 if(! (retval
= ope1
->date
- ope2
->date
) )
80 //g_print("sort on balance d1=%d, d2=%d %f %f\n", ope1->date, ope2->date, ope1->balance , ope2->balance);
82 tmpval
= ope1
->pos
- ope2
->pos
;
83 retval
= tmpval
> 0 ? 1 : -1;
85 //g_print("ret=%d\n", ret);
88 case LST_DSPOPE_ACCOUNT
:
92 a1
= da_acc_get(ope1
->kacc
);
93 a2
= da_acc_get(ope2
->kacc
);
94 retval
= list_txn_sort_iter_compare_strings((a1
!= NULL
) ? a1
->name
: NULL
, (a2
!= NULL
) ? a2
->name
: NULL
);
99 if(!(retval
= ope1
->paymode
- ope2
->paymode
))
101 retval
= list_txn_sort_iter_compare_strings(ope1
->info
, ope2
->info
);
105 case LST_DSPOPE_PAYEE
:
111 if( ope1
->paymode
== PAYMODE_INTXFER
)
113 Account
*acc
= da_acc_get(ope1
->kxferacc
);
114 name1
= (acc
!= NULL
) ? acc
->name
: NULL
;
118 Payee
*pay
= da_pay_get(ope1
->kpay
);
119 name1
= (pay
!= NULL
) ? pay
->name
: NULL
;
122 if( ope2
->paymode
== PAYMODE_INTXFER
)
124 Account
*acc
= da_acc_get(ope2
->kxferacc
);
125 name2
= (acc
!= NULL
) ? acc
->name
: NULL
;
129 Payee
*pay
= da_pay_get(ope2
->kpay
);
130 name2
= (pay
!= NULL
) ? pay
->name
: NULL
;
133 retval
= list_txn_sort_iter_compare_strings(name1
, name2
);
137 case LST_DSPOPE_MEMO
:
138 retval
= list_txn_sort_iter_compare_strings(ope1
->memo
, ope2
->memo
);
142 retval
= ope1
->status
- ope2
->status
;
145 case LST_DSPOPE_AMOUNT
:
146 case LST_DSPOPE_EXPENSE
:
147 case LST_DSPOPE_INCOME
:
148 tmpval
= ope1
->amount
- ope2
->amount
;
149 retval
= tmpval
> 0 ? 1 : -1;
152 case LST_DSPOPE_CATEGORY
:
156 c1
= da_cat_get(ope1
->kcat
);
157 c2
= da_cat_get(ope2
->kcat
);
158 if( c1
!= NULL
&& c2
!= NULL
)
160 retval
= list_txn_sort_iter_compare_strings(c1
->fullname
, c2
->fullname
);
165 case LST_DSPOPE_TAGS
:
169 t1
= tags_tostring(ope1
->tags
);
170 t2
= tags_tostring(ope2
->tags
);
171 retval
= list_txn_sort_iter_compare_strings(t1
, t2
);
178 g_return_val_if_reached(0);
185 static void list_txn_eval_future(GtkCellRenderer
*renderer
, Transaction
*txn
)
187 if(txn
->date
> GLOBALS
->today
)
189 g_object_set(renderer
,
190 // "scale-set", TRUE,
192 // "style-set", TRUE,
193 "style", PANGO_STYLE_OBLIQUE
,
198 g_object_set(renderer
, "scale-set", FALSE
, "style-set", FALSE
,
202 if( txn
->marker
== TXN_MARK_DUPDST
)
204 g_object_set(renderer
,
205 // "strikethrough-set", TRUE,
206 "strikethrough", TRUE
,
211 g_object_set(renderer
, "strikethrough-set", FALSE
,
215 if( txn
->marker
== TXN_MARK_DUPSRC
)
217 g_object_set(renderer
,
218 // "weight-set", TRUE,
219 "weight", PANGO_WEIGHT_BOLD
,
224 g_object_set(renderer
, "weight-set", FALSE
,
234 ** date cell function
236 static void list_txn_status_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
239 gchar
*iconname
= NULL
;
241 gtk_tree_model_get(model
, iter
, MODEL_TXN_POINTER
, &txn
, -1);
244 stat[0] = ( entry->ope_Flags & OF_ADDED ) ? data->istatus[2] : data->istatus[0];
245 stat[1] = ( entry->ope_Flags & OF_CHANGED) ? data->istatus[3] : data->istatus[0];
246 stat[2] = ( entry->ope_Flags & OF_VALID ) ? data->istatus[4] : data->istatus[0];
247 if( entry->ope_Flags & OF_REMIND ) stat[2] = data->istatus[1];
250 switch(GPOINTER_TO_INT(user_data
))
253 iconname
= ( txn
->flags
& OF_AUTO
) ? ICONNAME_HB_OPE_AUTO
: ( txn
->flags
& OF_ADDED
) ? ICONNAME_HB_OPE_NEW
: NULL
;
256 iconname
= ( txn
->flags
& OF_CHANGED
) ? ICONNAME_HB_OPE_EDIT
: NULL
;
259 iconname
= ( txn
->marker
== TXN_MARK_DUPDST
) ? ICONNAME_HB_OPE_SIMILAR
: NULL
;
262 if( entry->flags & OF_VALID )
263 iconname = ICONNAME_HB_OPE_VALID;
266 if( entry->flags & OF_REMIND )
267 iconname = ICONNAME_HB_OPE_REMIND;
271 g_object_set(renderer
, "icon-name", iconname
, NULL
);
276 ** account cell function
278 static void list_txn_account_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
283 gtk_tree_model_get(model
, iter
, MODEL_TXN_POINTER
, &ope
, -1);
285 acc
= da_acc_get(ope
->kacc
);
288 g_object_set(renderer
, "text", acc
->name
, NULL
);
291 g_object_set(renderer
, "text", "", NULL
);
295 ** date cell function
297 static void list_txn_date_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
303 gtk_tree_model_get(model
, iter
, MODEL_TXN_POINTER
, &ope
, -1);
304 list_txn_eval_future(renderer
, ope
);
308 g_date_set_julian (&date
, ope
->date
);
309 g_date_strftime (buffer
, 256-1, PREFS
->date_format
, &date
);
311 gchar
*ds
= g_strdup_printf ("%s [%02d]", buffer
, ope
->pos
);
312 g_object_set(renderer
, "text", ds
, NULL
);
315 g_object_set(renderer
, "text", buffer
, NULL
);
319 g_object_set(renderer
, "text", "????", NULL
);
323 ** info cell function
325 static void list_txn_info_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
329 gtk_tree_model_get(model
, iter
, MODEL_TXN_POINTER
, &ope
, -1);
331 switch(GPOINTER_TO_INT(user_data
))
334 g_object_set(renderer
, "icon-name", get_paymode_icon_name(ope
->paymode
), NULL
);
337 list_txn_eval_future(renderer
, ope
);
338 g_object_set(renderer
, "text", ope
->info
, NULL
);
344 ** payee cell function
346 static void list_txn_payee_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
350 gtk_tree_model_get(model
, iter
, MODEL_TXN_POINTER
, &ope
, -1);
351 list_txn_eval_future(renderer
, ope
);
354 if(ope
->paymode
== PAYMODE_INTXFER
)
356 Account
*acc
= da_acc_get(ope
->kxferacc
);
358 g_object_set(renderer
, "text", (acc
!= NULL
) ? acc
->name
: "", NULL
);
362 Payee
*pay
= da_pay_get(ope
->kpay
);
364 g_object_set(renderer
, "text", pay
!= NULL
? pay
->name
: "", NULL
);
370 ** tags cell function
372 static void list_txn_tags_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
377 gtk_tree_model_get(model
, iter
, MODEL_TXN_POINTER
, &ope
, -1);
378 list_txn_eval_future(renderer
, ope
);
380 if(ope
->tags
!= NULL
)
382 str
= tags_tostring(ope
->tags
);
383 g_object_set(renderer
, "text", str
, NULL
);
387 g_object_set(renderer
, "text", "", NULL
);
394 ** memo cell function
396 static void list_txn_memo_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
400 gtk_tree_model_get(model
, iter
, MODEL_TXN_POINTER
, &ope
, -1);
401 list_txn_eval_future(renderer
, ope
);
403 g_object_set(renderer
, "text", ope
->memo
, NULL
);
410 static void list_txn_clr_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
413 gchar
*iconname
= NULL
;
414 //const gchar *c = "";
416 gtk_tree_model_get(model
, iter
, MODEL_TXN_POINTER
, &ope
, -1);
419 /*case TXN_STATUS_CLEARED: c = "c"; break;
420 case TXN_STATUS_RECONCILED: c = "R"; break;
421 case TXN_STATUS_REMIND: c = "!"; break;*/
422 case TXN_STATUS_CLEARED
: iconname
= ICONNAME_HB_OPE_CLEARED
; break;
423 case TXN_STATUS_RECONCILED
: iconname
= ICONNAME_HB_OPE_RECONCILED
; break;
424 case TXN_STATUS_REMIND
: iconname
= ICONNAME_HB_OPE_REMIND
; break;
428 //g_object_set(renderer, "text", c, NULL);
429 g_object_set(renderer
, "icon-name", iconname
, NULL
);
435 ** amount cell function
437 static void list_txn_amount_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
439 struct list_txn_data
*data
= NULL
;
442 gint column
= GPOINTER_TO_INT(user_data
);
443 gchar buf
[G_ASCII_DTOSTR_BUF_SIZE
];
445 gdouble amount
, samount
;
448 widget
= gtk_tree_view_column_get_tree_view(col
);
450 data
= g_object_get_data(G_OBJECT(widget
), "inst_data");
452 // get the transaction
453 gtk_tree_model_get(model
, iter
, MODEL_TXN_POINTER
, &ope
, MODEL_TXN_SPLITAMT
, &samount
, -1);
454 list_txn_eval_future(renderer
, ope
);
456 if(column
== LST_DSPOPE_BALANCE
)
457 amount
= ope
->balance
;
459 amount
= ope
->amount
;
461 //for detail display the split part (if any)
462 if( data
&& (data
->list_type
== LIST_TXN_TYPE_DETAIL
) )
465 if(column
== LST_DSPOPE_INCOME
|| column
== LST_DSPOPE_EXPENSE
)
467 type
= (ope
->flags
& OF_INCOME
) ? LST_DSPOPE_INCOME
: LST_DSPOPE_EXPENSE
;
470 g_object_set(renderer
, "markup", NULL
, NULL
);
477 hb_strfmon(buf
, G_ASCII_DTOSTR_BUF_SIZE
-1, amount
, ope
->kcur
, GLOBALS
->minor
);
479 color
= get_normal_color_amount(amount
);
480 if( (column
== LST_DSPOPE_BALANCE
) && (ope
->overdraft
== TRUE
) && (PREFS
->custom_colors
== TRUE
) )
482 color
= PREFS
->color_warn
;
485 g_object_set(renderer
,
496 ** category cell function
498 static void list_txn_category_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
503 gtk_tree_model_get(model
, iter
, MODEL_TXN_POINTER
, &ope
, -1);
504 list_txn_eval_future(renderer
, ope
);
506 if(ope
->flags
& OF_SPLIT
)
508 g_object_set(renderer
, "text", _("- split -"), NULL
);
512 cat
= da_cat_get(ope
->kcat
);
515 g_object_set(renderer
, "text", cat
->fullname
, NULL
);
518 g_object_set(renderer
, "text", "", NULL
);
525 /* = = = = = = = = = = = = = = = = */
527 GString
*list_txn_to_string(GtkTreeView
*treeview
, gboolean clipboard
)
529 struct list_txn_data
*data
= NULL
;
537 gchar
*info
, *payeename
, *categoryname
;
538 gdouble amount
, samount
;
542 char amountbuf
[G_ASCII_DTOSTR_BUF_SIZE
];
544 data
= g_object_get_data(G_OBJECT(treeview
), "inst_data");
546 node
= g_string_new(NULL
);
550 g_string_append (node
, "date\tpaymode\tinfo\tpayee\tmemo\tamount\tcategory\ttags\n");
552 g_string_append (node
, "date;paymode;info;payee;memo;amount;category;tags\n");
554 model
= gtk_tree_view_get_model(treeview
);
556 valid
= gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model
), &iter
);
559 gtk_tree_model_get (model
, &iter
,
560 MODEL_TXN_POINTER
, &ope
,
561 MODEL_TXN_SPLITAMT
, &samount
,
564 hb_sprint_date(datebuf
, ope
->date
);
567 if(info
== NULL
) info
= "";
568 payee
= da_pay_get(ope
->kpay
);
569 payeename
= (payee
->name
== NULL
) ? "" : payee
->name
;
570 category
= da_cat_get(ope
->kcat
);
571 categoryname
= (category
->name
== NULL
) ? NULL
: category
->fullname
;
572 tags
= tags_tostring(ope
->tags
);
574 amount
= ope
->amount
;
575 //for detail display the split part (if any)
576 if( data
&& (data
->list_type
== LIST_TXN_TYPE_DETAIL
) )
580 //g_ascii_dtostr (amountbuf, sizeof (amountbuf), ope->amount);
581 //#1750257 use locale numdigit
582 //g_ascii_formatd (amountbuf, sizeof (amountbuf), "%.2f", ope->amount);
583 g_snprintf(amountbuf
, sizeof (amountbuf
), "%.2f", amount
);
585 DB( g_print("amount = %f '%s'\n", amount
, amountbuf
) );
587 format
= (clipboard
== TRUE
) ? "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\n" : "%s;%d;%s;%s;%s;%s;%s;%s\n";
588 g_string_append_printf(node
, format
,
595 categoryname
!= NULL
? categoryname
: "",
596 tags
!= NULL
? tags
: ""
602 valid
= gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &iter
);
605 //DB( g_print("text is:\n%s", node->str) );
611 gboolean
list_txn_column_id_isvisible(GtkTreeView
*treeview
, gint sort_id
)
613 GtkTreeViewColumn
*column
;
616 for(n
=0; n
< NUM_LST_DSPOPE
-1 ; n
++ ) // -1 cause account not to be processed
618 column
= gtk_tree_view_get_column (treeview
, n
);
622 if( gtk_tree_view_column_get_visible(column
) )
624 id
= gtk_tree_view_column_get_sort_column_id (column
);
634 static GtkTreeViewColumn
*list_txn_get_column(GList
*list
, gint search_id
)
636 GtkTreeViewColumn
*column
= NULL
;
640 tmp
= g_list_first(list
);
643 id
= gtk_tree_view_column_get_sort_column_id(tmp
->data
);
644 if( search_id
== id
)
649 tmp
= g_list_next(tmp
);
655 guint
list_txn_get_quicksearch_column_mask(GtkTreeView
*treeview
)
657 GtkTreeViewColumn
*column
;
662 for(n
=0; n
< NUM_LST_DSPOPE
-1 ; n
++ ) // -1 cause account not to be processed
664 column
= gtk_tree_view_get_column (treeview
, n
);
668 if( gtk_tree_view_column_get_visible(column
) )
670 id
= gtk_tree_view_column_get_sort_column_id (column
);
673 case LST_DSPOPE_MEMO
: mask
|= FLT_QSEARCH_MEMO
; break;
674 case LST_DSPOPE_INFO
: mask
|= FLT_QSEARCH_INFO
; break;
675 case LST_DSPOPE_PAYEE
: mask
|= FLT_QSEARCH_PAYEE
; break;
676 case LST_DSPOPE_CATEGORY
: mask
|= FLT_QSEARCH_CATEGORY
; break;
677 case LST_DSPOPE_TAGS
: mask
|= FLT_QSEARCH_TAGS
; break;
678 case LST_DSPOPE_AMOUNT
:
679 case LST_DSPOPE_EXPENSE
:
680 case LST_DSPOPE_INCOME
: mask
|= FLT_QSEARCH_AMOUNT
; break;
689 void list_txn_set_save_column_width(GtkTreeView
*treeview
, gboolean save_column_width
)
691 struct list_txn_data
*data
;
693 data
= g_object_get_data(G_OBJECT(treeview
), "inst_data");
696 data
->save_column_width
= save_column_width
;
701 void list_txn_set_column_acc_visible(GtkTreeView
*treeview
, gboolean visible
)
703 struct list_txn_data
*data
;
705 GtkTreeViewColumn
*column
;
707 data
= g_object_get_data(G_OBJECT(treeview
), "inst_data");
709 data
->showall
= visible
;
711 list
= gtk_tree_view_get_columns( treeview
);
712 //if acc visible: balance must be invisible
713 column
= list_txn_get_column(list
, LST_DSPOPE_ACCOUNT
);
715 gtk_tree_view_column_set_visible (column
, visible
);
716 column
= list_txn_get_column(list
, LST_DSPOPE_BALANCE
);
718 gtk_tree_view_column_set_visible (column
, !visible
);
725 void list_txn_sort_force(GtkTreeSortable
*sortable
, gpointer user_data
)
730 DB( g_print("list_txn_sort_force\n") );
732 gtk_tree_sortable_get_sort_column_id(sortable
, &sort_column_id
, &order
);
733 DB( g_print(" - id %d order %d\n", sort_column_id
, order
) );
735 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(sortable
), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID
, order
);
736 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(sortable
), sort_column_id
, order
);
740 static void list_txn_get_columns(GtkTreeView
*treeview
)
742 struct list_txn_data
*data
;
743 GtkTreeViewColumn
*column
;
746 DB( g_print("\n[list_txn] get columns position/width\n") );
748 data
= g_object_get_data(G_OBJECT(treeview
), "inst_data");
750 DB( g_print(" nbcol=%d, nbsortid=%d\n", NUM_LST_DSPOPE
, gtk_tree_view_get_n_columns (treeview
)) );
752 for(i
=0 ; i
< NUM_LST_DSPOPE
-1 ; i
++ ) // -1 'caus: account and blank column
754 column
= gtk_tree_view_get_column(treeview
, i
);
757 col_id
= gtk_tree_view_column_get_sort_column_id (column
);
762 visible
= gtk_tree_view_column_get_visible (column
);
763 if( col_id
== LST_DSPOPE_BALANCE
) //keep initial state of balance
764 visible
= data
->tvc_is_visible
;
768 PREFS
->lst_ope_columns
[i
] = col_id
;
769 //5.2 moved here to keep old width in case not visible
770 PREFS
->lst_ope_col_width
[col_id
-1] = gtk_tree_view_column_get_width(column
);
773 PREFS
->lst_ope_columns
[i
] = -col_id
;
775 DB( g_print(" col-%2d => %2d '%s' w=%d\n", i
, col_id
, gtk_tree_view_column_get_title(column
), PREFS
->lst_ope_col_width
[col_id
-1] ) );
777 else //should not occurs
778 PREFS
->lst_ope_columns
[i
] = 0;
784 static void list_txn_set_columns(GtkTreeView
*treeview
, gint
*col_id
)
786 struct list_txn_data
*data
;
787 GtkTreeViewColumn
*column
, *base
;
793 DB( g_print("\n[list_txn] set columns order/width\n") );
795 data
= g_object_get_data(G_OBJECT(treeview
), "inst_data");
798 DB( g_print("\n debug column sortid\n") );
800 for(i
=0; i
< NUM_LST_DSPOPE
-1 ; i
++ ) // -1 cause account not to be processed
802 DB( g_print(" - pos:%2d sortid:%2d\n", i
, col_id
[i
]) );
807 DB( g_print("\n apply column prefs\n") );
809 list
= gtk_tree_view_get_columns( treeview
);
813 for(i
=0; i
< NUM_LST_DSPOPE
-1 ; i
++ ) // -1 cause account not to be processed
815 /* hidden are stored as col_id negative */
817 column
= list_txn_get_column(list
, id
);
819 //DB( g_print(" - get column %d %p\n", id, column) );
823 DB( g_print(" - pos:%2d sortid:%2d (%s)\n", i
, col_id
[i
], gtk_tree_view_column_get_title(column
)) );
825 gtk_tree_view_move_column_after(treeview
, column
, base
);
828 visible
= col_id
[i
] < 0 ? FALSE
: TRUE
;
830 /* display exception for detail/import list */
831 if(data
->list_type
!= LIST_TXN_TYPE_BOOK
)
833 if( id
== LST_DSPOPE_AMOUNT
)
836 if( id
== LST_DSPOPE_STATUS
|| id
== LST_DSPOPE_EXPENSE
|| id
== LST_DSPOPE_INCOME
)
840 gtk_tree_view_column_set_visible (column
, visible
);
841 if( id
== LST_DSPOPE_BALANCE
)
843 data
->tvc_is_visible
= visible
;
846 if( id
== LST_DSPOPE_INFO
847 || id
== LST_DSPOPE_PAYEE
848 || id
== LST_DSPOPE_MEMO
849 || id
== LST_DSPOPE_CATEGORY
850 || id
== LST_DSPOPE_TAGS
851 || id
== LST_DSPOPE_ACCOUNT
)
853 gtk_tree_view_column_set_fixed_width( column
, PREFS
->lst_ope_col_width
[id
- 1]);
863 static void list_txn_sort_column_changed(GtkTreeSortable
*sortable
, gpointer user_data
)
865 struct list_txn_data
*data
= user_data
;
868 gboolean showBalance
;
870 gtk_tree_sortable_get_sort_column_id(sortable
, &id
, &order
);
872 DB( g_print("list_txn_columns_changed %d %d\n", id
, order
) );
874 //here save the transaction list columnid and sort order
875 PREFS
->lst_ope_sort_id
= id
;
876 PREFS
->lst_ope_sort_order
= order
;
878 //manage visibility of balance column
879 //showBalance = (id == LST_DSPOPE_DATE && order == GTK_SORT_ASCENDING) ? data->tvc_is_visible : FALSE;
880 showBalance
= (id
== LST_DSPOPE_DATE
) ? data
->tvc_is_visible
: FALSE
;
881 if(data
->showall
== TRUE
) showBalance
= FALSE
;
882 gtk_tree_view_column_set_visible (data
->tvc_balance
, showBalance
);
887 list_txn_column_popup_menuitem_on_activate (GtkCheckMenuItem
*checkmenuitem
,
890 GtkTreeViewColumn
*column
= user_data
;
892 DB( g_print("toggled\n") );
894 gtk_tree_view_column_set_visible(column
, gtk_check_menu_item_get_active(checkmenuitem
) );
898 static gboolean
list_txn_column_popup_callback ( GtkWidget
*button
,
902 struct list_txn_data
*data
= user_data
;
903 GtkWidget
*menu
, *menuitem
;
904 GtkTreeViewColumn
*column
;
908 if( ev
->button
== 3 )
910 DB( g_print("should popup\n") );
912 menu
= gtk_menu_new ();
914 //note: deactive this disable any menuitem action
915 g_signal_connect (menu
, "selection-done", G_CALLBACK (gtk_widget_destroy
), NULL
);
917 for(i
=0 ; i
< NUM_LST_DSPOPE
-1 ; i
++ ) // -1 'caus: account and blank column
919 column
= gtk_tree_view_get_column(GTK_TREE_VIEW(data
->treeview
), i
);
922 col_id
= gtk_tree_view_column_get_sort_column_id (column
);
925 || (col_id
== LST_DSPOPE_STATUS
)
926 || (col_id
== LST_DSPOPE_ACCOUNT
)
927 || (col_id
== LST_DSPOPE_DATE
)
928 || (col_id
== LST_DSPOPE_BALANCE
)
931 //if( (data->tvc_is_visible == FALSE) && (col_id == LST_DSPOPE_BALANCE) )
934 if( (data
->list_type
== LIST_TXN_TYPE_DETAIL
) &&
935 ( (col_id
== LST_DSPOPE_AMOUNT
)
936 || (col_id
== LST_DSPOPE_EXPENSE
)
937 || (col_id
== LST_DSPOPE_INCOME
)
942 menuitem
= gtk_check_menu_item_new_with_label ( gtk_tree_view_column_get_title (column
) );
943 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
944 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem
), gtk_tree_view_column_get_visible (column
) );
945 gtk_widget_show (menuitem
);
947 g_signal_connect (menuitem
, "activate",
948 G_CALLBACK (list_txn_column_popup_menuitem_on_activate
), column
);
953 gtk_menu_attach_to_widget (GTK_MENU (menu
), button
, NULL
);
954 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
,
955 ev
->button
, ev
->time
);
962 static GtkTreeViewColumn
*
963 list_txn_column_amount_create(gint list_type
, gchar
*title
, gint sortcolumnid
, GtkTreeCellDataFunc func
)
965 GtkTreeViewColumn
*column
;
966 GtkCellRenderer
*renderer
;
968 renderer
= gtk_cell_renderer_text_new ();
969 g_object_set(renderer
, "xalign", 1.0, NULL
);
971 column
= gtk_tree_view_column_new_with_attributes(title
, renderer
, NULL
);
973 gtk_tree_view_column_set_alignment (column
, 0.5);
974 //gtk_tree_view_column_set_resizable(column, TRUE);
975 gtk_tree_view_column_set_sort_column_id (column
, sortcolumnid
);
976 if(list_type
== LIST_TXN_TYPE_BOOK
)
978 gtk_tree_view_column_set_reorderable(column
, TRUE
);
980 gtk_tree_view_column_set_cell_data_func(column
, renderer
, func
, GINT_TO_POINTER(sortcolumnid
), NULL
);
986 static GtkTreeViewColumn
*
987 list_txn_column_text_create(gint list_type
, gchar
*title
, gint sortcolumnid
, GtkTreeCellDataFunc func
, gpointer user_data
)
989 GtkTreeViewColumn
*column
;
990 GtkCellRenderer
*renderer
;
992 renderer
= gtk_cell_renderer_text_new ();
993 g_object_set(renderer
,
994 "ellipsize", PANGO_ELLIPSIZE_END
,
995 "ellipsize-set", TRUE
,
998 column
= gtk_tree_view_column_new_with_attributes(title
, renderer
, NULL
);
1000 gtk_tree_view_column_set_alignment (column
, 0.5);
1001 gtk_tree_view_column_set_resizable(column
, TRUE
);
1003 gtk_tree_view_column_set_sort_column_id (column
, sortcolumnid
);
1004 if(list_type
== LIST_TXN_TYPE_BOOK
)
1006 gtk_tree_view_column_set_reorderable(column
, TRUE
);
1007 gtk_tree_view_column_set_min_width (column
, HB_MINWIDTH_COLUMN
);
1008 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_FIXED
);
1010 gtk_tree_view_column_set_cell_data_func(column
, renderer
, func
, user_data
, NULL
);
1016 static GtkTreeViewColumn
*
1017 list_txn_column_info_create(gint list_type
)
1019 GtkTreeViewColumn
*column
;
1020 GtkCellRenderer
*renderer
;
1022 column
= gtk_tree_view_column_new();
1023 gtk_tree_view_column_set_title(column
, _("Info"));
1025 renderer
= gtk_cell_renderer_pixbuf_new ();
1026 gtk_tree_view_column_pack_start(column
, renderer
, FALSE
);
1027 gtk_tree_view_column_set_cell_data_func(column
, renderer
, list_txn_info_cell_data_function
, GINT_TO_POINTER(1), NULL
);
1029 renderer
= gtk_cell_renderer_text_new ();
1030 /*g_object_set(renderer,
1031 "ellipsize", PANGO_ELLIPSIZE_END,
1032 "ellipsize-set", TRUE,
1034 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1035 gtk_tree_view_column_set_cell_data_func(column
, renderer
, list_txn_info_cell_data_function
, GINT_TO_POINTER(2), NULL
);
1037 gtk_tree_view_column_set_alignment (column
, 0.5);
1038 gtk_tree_view_column_set_resizable(column
, TRUE
);
1039 gtk_tree_view_column_set_sort_column_id (column
, LST_DSPOPE_INFO
);
1040 if(list_type
== LIST_TXN_TYPE_BOOK
)
1042 gtk_tree_view_column_set_reorderable(column
, TRUE
);
1043 gtk_tree_view_column_set_min_width (column
, HB_MINWIDTH_COLUMN
);
1044 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_FIXED
);
1051 static void list_txn_destroy( GtkWidget
*widget
, gpointer user_data
)
1053 struct list_txn_data
*data
;
1055 data
= g_object_get_data(G_OBJECT(widget
), "inst_data");
1057 DB( g_print ("\n[list_transaction] destroy event occurred\n") );
1059 if( data
->save_column_width
)
1061 list_txn_get_columns(GTK_TREE_VIEW(data
->treeview
));
1064 DB( g_print(" - view=%p, inst_data=%p\n", widget
, data
) );
1069 Transaction
*list_txn_get_active_transaction(GtkTreeView
*treeview
)
1071 GtkTreeModel
*model
;
1077 model
= gtk_tree_view_get_model(treeview
);
1078 list
= gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(treeview
), &model
);
1084 gtk_tree_model_get_iter(model
, &iter
, list
->data
);
1085 gtk_tree_model_get(model
, &iter
, MODEL_TXN_POINTER
, &ope
, -1);
1088 g_list_foreach(list
, (GFunc
)gtk_tree_path_free
, NULL
);
1096 ** create our transaction list
1097 ** Status, Date, Info, Payee, Memo, (Amount), Expense, Income, Category
1099 GtkWidget
*create_list_transaction(gint list_type
, gboolean
*pref_columns
)
1101 struct list_txn_data
*data
;
1102 GtkListStore
*store
;
1103 GtkWidget
*treeview
;
1104 GtkCellRenderer
*renderer
;
1105 GtkTreeViewColumn
*column
, *col_acc
= NULL
, *col_status
= NULL
;
1108 data
= g_malloc0(sizeof(struct list_txn_data
));
1109 if(!data
) return NULL
;
1111 data
->list_type
= list_type
;
1112 data
->save_column_width
= FALSE
;
1114 /* create list store */
1115 store
= gtk_list_store_new(
1116 2, G_TYPE_POINTER
, // MODEL_TXN_POINTER
1117 G_TYPE_DOUBLE
// MODEL_TXN_SPLITAMT amount part of split for detail only
1121 treeview
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
1122 data
->treeview
= treeview
;
1123 g_object_unref(store
);
1125 //store our window private data
1126 g_object_set_data(G_OBJECT(treeview
), "inst_data", (gpointer
)data
);
1127 DB( g_print(" - treeview=%p, inst_data=%p\n", treeview
, data
) );
1129 // connect our dispose function
1130 g_signal_connect (treeview
, "destroy", G_CALLBACK (list_txn_destroy
), (gpointer
)data
);
1132 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (treeview
), PREFS
->grid_lines
);
1133 //gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview),
1134 // COLUMN_DESCRIPTION);
1136 if(list_type
== LIST_TXN_TYPE_BOOK
)
1137 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview
)), GTK_SELECTION_MULTIPLE
);
1139 /* column 1: Changes */
1140 column
= gtk_tree_view_column_new();
1141 //gtk_tree_view_column_set_title(column, _("Status"));
1142 col_status
= column
;
1144 renderer
= gtk_cell_renderer_pixbuf_new ();
1145 //gtk_cell_renderer_set_fixed_size(renderer, GLOBALS->lst_pixbuf_maxwidth, -1);
1146 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1147 gtk_tree_view_column_set_cell_data_func(column
, renderer
, list_txn_status_cell_data_function
, GINT_TO_POINTER(1), NULL
);
1149 renderer
= gtk_cell_renderer_pixbuf_new ();
1150 //gtk_cell_renderer_set_fixed_size(renderer, GLOBALS->lst_pixbuf_maxwidth, -1);
1151 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1152 gtk_tree_view_column_set_cell_data_func(column
, renderer
, list_txn_status_cell_data_function
, GINT_TO_POINTER(2), NULL
);
1154 renderer
= gtk_cell_renderer_pixbuf_new ();
1155 //gtk_cell_renderer_set_fixed_size(renderer, GLOBALS->lst_pixbuf_maxwidth, -1);
1156 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1157 gtk_tree_view_column_set_cell_data_func(column
, renderer
, list_txn_status_cell_data_function
, GINT_TO_POINTER(3), NULL
);
1159 gtk_tree_view_column_set_sort_column_id (column
, LST_DSPOPE_STATUS
);
1160 //gtk_tree_view_column_set_resizable(column, TRUE);
1161 gtk_tree_view_column_set_alignment (column
, 0.5);
1162 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1164 //5.2 we always create the column and set it not visible
1165 column
= list_txn_column_text_create(list_type
, _("Account"), LST_DSPOPE_ACCOUNT
, list_txn_account_cell_data_function
, NULL
);
1166 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1169 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1170 "button-press-event",
1171 G_CALLBACK ( list_txn_column_popup_callback
),
1174 /* column 2: Date */
1175 column
= gtk_tree_view_column_new();
1176 gtk_tree_view_column_set_title(column
, _("Date"));
1177 renderer
= gtk_cell_renderer_text_new ();
1178 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1179 g_object_set(renderer
, "xalign", 1.0, NULL
);
1180 gtk_tree_view_column_set_cell_data_func(column
, renderer
, list_txn_date_cell_data_function
, NULL
, NULL
);
1181 gtk_tree_view_column_set_sort_column_id (column
, LST_DSPOPE_DATE
);
1182 //gtk_tree_view_column_set_resizable(column, TRUE);
1183 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1185 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1186 "button-press-event",
1187 G_CALLBACK ( list_txn_column_popup_callback
),
1191 column
= list_txn_column_info_create(list_type
);
1192 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1194 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1195 "button-press-event",
1196 G_CALLBACK ( list_txn_column_popup_callback
),
1199 column
= list_txn_column_text_create(list_type
, _("Payee"), LST_DSPOPE_PAYEE
, list_txn_payee_cell_data_function
, NULL
);
1200 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1202 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1203 "button-press-event",
1204 G_CALLBACK ( list_txn_column_popup_callback
),
1207 column
= list_txn_column_text_create(list_type
, _("Memo"), LST_DSPOPE_MEMO
, list_txn_memo_cell_data_function
, NULL
);
1208 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1210 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1211 "button-press-event",
1212 G_CALLBACK ( list_txn_column_popup_callback
),
1215 /* column status CLR */
1216 column
= gtk_tree_view_column_new();
1217 gtk_tree_view_column_set_title(column
, _("Status"));
1219 //renderer = gtk_cell_renderer_text_new ();
1220 renderer
= gtk_cell_renderer_pixbuf_new();
1221 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1222 g_object_set(renderer
, "xalign", 1.0, NULL
);
1223 gtk_tree_view_column_set_cell_data_func(column
, renderer
, list_txn_clr_cell_data_function
, NULL
, NULL
);
1224 gtk_tree_view_column_set_reorderable(column
, TRUE
);
1225 gtk_tree_view_column_set_sort_column_id (column
, LST_DSPOPE_CLR
);
1226 //gtk_tree_view_column_set_sort_indicator (column, FALSE);
1227 //gtk_tree_view_column_set_resizable(column, TRUE);
1228 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1230 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1231 "button-press-event",
1232 G_CALLBACK ( list_txn_column_popup_callback
),
1236 column
= list_txn_column_amount_create(list_type
, _("Amount"), LST_DSPOPE_AMOUNT
, list_txn_amount_cell_data_function
);
1237 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1239 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1240 "button-press-event",
1241 G_CALLBACK ( list_txn_column_popup_callback
),
1244 column
= list_txn_column_amount_create(list_type
, _("Expense"), LST_DSPOPE_EXPENSE
, list_txn_amount_cell_data_function
);
1245 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1247 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1248 "button-press-event",
1249 G_CALLBACK ( list_txn_column_popup_callback
),
1252 column
= list_txn_column_amount_create(list_type
, _("Income"), LST_DSPOPE_INCOME
, list_txn_amount_cell_data_function
);
1253 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1255 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1256 "button-press-event",
1257 G_CALLBACK ( list_txn_column_popup_callback
),
1260 column
= list_txn_column_text_create(list_type
, _("Category"), LST_DSPOPE_CATEGORY
, list_txn_category_cell_data_function
, NULL
);
1261 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1263 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1264 "button-press-event",
1265 G_CALLBACK ( list_txn_column_popup_callback
),
1268 column
= list_txn_column_text_create(list_type
, _("Tags"), LST_DSPOPE_TAGS
, list_txn_tags_cell_data_function
, NULL
);
1269 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1271 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1272 "button-press-event",
1273 G_CALLBACK ( list_txn_column_popup_callback
),
1276 if(list_type
== LIST_TXN_TYPE_BOOK
)
1278 column
= list_txn_column_amount_create(list_type
, _("Balance"), LST_DSPOPE_BALANCE
, list_txn_amount_cell_data_function
);
1279 data
->tvc_balance
= column
;
1280 gtk_tree_view_column_set_clickable(column
, FALSE
);
1281 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1283 g_signal_connect ( G_OBJECT (gtk_tree_view_column_get_button (column
)),
1284 "button-press-event",
1285 G_CALLBACK ( list_txn_column_popup_callback
),
1289 /* column 9: empty */
1290 column
= gtk_tree_view_column_new();
1291 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
1294 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_STATUS
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_STATUS
), NULL
);
1295 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_DATE
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_DATE
), NULL
);
1296 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_INFO
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_INFO
), NULL
);
1297 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_PAYEE
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_PAYEE
), NULL
);
1298 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_MEMO
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_MEMO
), NULL
);
1299 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_AMOUNT
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_AMOUNT
), NULL
);
1300 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_EXPENSE
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_EXPENSE
), NULL
);
1301 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_INCOME
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_INCOME
), NULL
);
1302 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_CATEGORY
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_CATEGORY
), NULL
);
1303 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_TAGS
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_TAGS
), NULL
);
1304 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_CLR
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_CLR
), NULL
);
1305 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DSPOPE_ACCOUNT
, list_txn_sort_iter_compare_func
, GINT_TO_POINTER(LST_DSPOPE_ACCOUNT
), NULL
);
1307 /* apply user preference for columns */
1308 list_txn_set_columns(GTK_TREE_VIEW(treeview
), pref_columns
);
1310 /* force account column for detail treeview */
1311 gtk_tree_view_move_column_after(GTK_TREE_VIEW(treeview
), col_acc
, col_status
);
1313 /* by default book don't display acc column, except shoall */
1314 //#1821850 detail account column visible
1315 gboolean visible
= (list_type
== LIST_TXN_TYPE_BOOK
) ? FALSE
: TRUE
;
1316 gtk_tree_view_column_set_visible (col_acc
, visible
);
1318 /* set initial sort order */
1319 DB( g_print("set sort to %d %d\n", PREFS
->lst_ope_sort_id
, PREFS
->lst_ope_sort_order
) );
1320 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store
), PREFS
->lst_ope_sort_id
, PREFS
->lst_ope_sort_order
);
1324 if(list_type
== LIST_TXN_TYPE_BOOK
)
1325 g_signal_connect (GTK_TREE_SORTABLE(store
), "sort-column-changed", G_CALLBACK (list_txn_sort_column_changed
), data
);