1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2016 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 ofdeftransaction_amountchanged
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 "ui-transaction.h"
24 #include "ui-archive.h"
25 #include "gtk-dateentry.h"
27 #include "ui-category.h"
28 #include "ui-account.h"
34 /****************************************************************************/
36 /****************************************************************************/
45 /* our global datas */
46 extern struct HomeBank
*GLOBALS
;
47 extern struct Preferences
*PREFS
;
50 #define GTK_RESPONSE_SPLIT_SUM 10880
51 #define GTK_RESPONSE_SPLIT_REM 10888
54 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
56 static void ui_split_dialog_filter_text_handler (GtkEntry
*entry
,
62 GtkEditable
*editable
= GTK_EDITABLE(entry
);
64 gchar
*result
= g_new0 (gchar
, length
+1);
66 for (i
=0; i
< length
; i
++)
70 result
[count
++] = text
[i
];
75 g_signal_handlers_block_by_func (G_OBJECT (editable
),
76 G_CALLBACK (ui_split_dialog_filter_text_handler
),
78 gtk_editable_insert_text (editable
, result
, count
, position
);
79 g_signal_handlers_unblock_by_func (G_OBJECT (editable
),
80 G_CALLBACK (ui_split_dialog_filter_text_handler
),
83 g_signal_stop_emission_by_name (G_OBJECT (editable
), "insert-text");
89 void ui_split_dialog_line_sensitive(guint line
, gboolean sensitive
, gpointer user_data
)
91 struct ui_split_dialog_data
*data
= user_data
;
93 if( line
> TXN_MAX_SPLIT
)
96 if( line
== 0 ) // line 0 always active !
100 gtk_widget_set_sensitive(data
->PO_cat
[line
], sensitive
);
101 gtk_widget_set_sensitive(data
->ST_amount
[line
], sensitive
);
102 gtk_widget_set_sensitive(data
->ST_memo
[line
], sensitive
);
103 if(data
->BT_rem
[line
])
104 gtk_widget_set_sensitive(data
->BT_rem
[line
], sensitive
);
105 if(data
->BT_add
[line
])
106 gtk_widget_set_sensitive(data
->BT_add
[line
], sensitive
);
108 if(sensitive
== FALSE
)
110 ui_cat_comboboxentry_set_active(GTK_COMBO_BOX(data
->PO_cat
[line
]), 0);
111 gtk_spin_button_set_value(GTK_SPIN_BUTTON(data
->ST_amount
[line
]), 0.0);
112 gtk_entry_set_text(GTK_ENTRY(data
->ST_memo
[line
]), "");
115 if(sensitive
== TRUE
)
116 data
->activeline
= line
;
121 void ui_split_dialog_compute(GtkWidget
*widget
, gpointer user_data
)
123 struct ui_split_dialog_data
*data
= user_data
;
124 gint i
, count
, nbvalid
;
127 gboolean sensitive
, active
;
128 //guint32 cat[TXN_MAX_SPLIT];
129 gdouble amt
[TXN_MAX_SPLIT
];
130 gboolean valid
[TXN_MAX_SPLIT
];
132 DB( g_print("\n(ui_split_dialog_compute)\n") );
134 data
->sumsplit
= data
->remsplit
= 0.0;
136 for(i
=0;i
<TXN_MAX_SPLIT
;i
++)
138 active
= gtk_widget_get_sensitive(data
->PO_cat
[i
]);
141 //cat[i] = ui_cat_comboboxentry_get_key(GTK_COMBO_BOX(data->PO_cat[i]));
142 amt
[i
] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data
->ST_amount
[i
]));
143 data
->sumsplit
+= amt
[i
];
149 /* disable use same category several time
153 if( (cat[i] == cat[j]) )
159 DB( g_print("- split %d : act.=%d val.=%d : amt=%.2f\n", i
, active
, valid
[i
], amt
[i
]) );
164 DB( g_print("- nbsplit %d\n", data
->nbsplit
) );
166 if(data
->nbsplit
== i
)
168 DB( g_print("- set last split %d\n", i
) );
171 gtk_widget_set_sensitive(data
->BT_add
[i
], valid
[i
]);
174 gtk_widget_set_sensitive(data
->BT_rem
[i
], TRUE
);
178 DB( g_print("- set off to %d\n", i
) );
181 gtk_widget_set_sensitive(data
->BT_add
[i
], FALSE
);
184 gtk_widget_set_sensitive(data
->BT_rem
[i
], FALSE
);
189 DB( g_print("- count=%d, nbvalid=%d\n", count
, nbvalid
) );
192 if(data
->splittype
== TXN_SPLIT_AMOUNT
)
194 data
->remsplit
= data
->amount
- data
->sumsplit
;
198 sensitive
= ((count
== nbvalid
) && (count
> 1)) ? TRUE
: FALSE
;
199 if(data
->splittype
== TXN_SPLIT_NEW
)
200 gtk_dialog_set_response_sensitive(GTK_DIALOG(data
->dialog
), GTK_RESPONSE_SPLIT_SUM
, sensitive
);
202 if(data
->splittype
== TXN_SPLIT_AMOUNT
)
204 sensitive
= hb_amount_round(data
->remsplit
, 2) != 0.0 ? FALSE
: sensitive
;
205 gtk_dialog_set_response_sensitive(GTK_DIALOG(data
->dialog
), GTK_RESPONSE_ACCEPT
, sensitive
);
208 g_sprintf(buf
, "----");
210 g_snprintf(buf
, 48, "%.2f", data
->remsplit
);
212 gtk_label_set_label(GTK_LABEL(data
->LB_remain
), buf
);
214 g_snprintf(buf
, 48, "%.2f", data
->amount
);
215 gtk_label_set_label(GTK_LABEL(data
->LB_txnamount
), buf
);
218 g_snprintf(buf
, 48, "%.2f", data
->sumsplit
);
219 gtk_label_set_text(GTK_LABEL(data
->LB_sumsplit
), buf
);
224 void ui_split_dialog_inactiveline(GtkWidget
*widget
, gpointer user_data
)
226 struct ui_split_dialog_data
*data
;
229 DB( g_print("\n(ui_split_dialog_inactiveline)\n") );
231 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
233 if(data
->nbsplit
<= 0) //1st split always active
236 line
= data
->nbsplit
--;
238 DB( g_print("- nbsplit:%d off:%d\n", data
->nbsplit
, line
) );
240 ui_split_dialog_line_sensitive(line
, FALSE
, data
);
241 ui_split_dialog_compute(widget
, data
);
245 void ui_split_dialog_activeline(GtkWidget
*widget
, gpointer user_data
)
247 struct ui_split_dialog_data
*data
;
250 DB( g_print("\n(ui_split_dialog_activeline)\n") );
252 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
254 line
= data
->nbsplit
;
255 if(line
>= (TXN_MAX_SPLIT
-1)) //bound
258 line
= ++data
->nbsplit
;
260 DB( g_print("- nbsplit:%d off:%d\n", data
->nbsplit
-1, line
) );
263 ui_split_dialog_line_sensitive(line
, TRUE
, data
);
265 if(data
->splittype
== TXN_SPLIT_AMOUNT
)
267 DB( g_print("- line %d :: affect remain\n", line
) );
268 g_signal_handler_block(data
->ST_amount
[line
], data
->handler_id
[line
]);
269 gtk_spin_button_set_value(GTK_SPIN_BUTTON(data
->ST_amount
[line
]), data
->remsplit
);
270 g_signal_handler_unblock(data
->ST_amount
[line
], data
->handler_id
[line
]);
273 ui_split_dialog_compute(widget
, data
);
277 void ui_split_dialog_get(struct ui_split_dialog_data
*data
)
285 DB( g_print("(ui_split_dialog_get)\n") );
287 da_splits_free(data
->splits
);
289 for(i
=0;i
<TXN_MAX_SPLIT
;i
++)
291 kcat
= ui_cat_comboboxentry_get_key_add_new(GTK_COMBO_BOX(data
->PO_cat
[i
]));
292 memo
= (gchar
*)gtk_entry_get_text(GTK_ENTRY(data
->ST_memo
[i
]));
293 amount
= gtk_spin_button_get_value(GTK_SPIN_BUTTON(data
->ST_amount
[i
]));
297 split
= da_split_new(kcat
, amount
, memo
);
299 DB( g_print("- get split %d : %d, %.2f, %s\n", i
, split
->kcat
, split
->amount
, split
->memo
) );
301 da_splits_append (data
->splits
, split
);
307 void ui_split_dialog_set(struct ui_split_dialog_data
*data
)
313 DB( g_print("(ui_split_dialog_set)\n") );
315 for(i
=0;i
<TXN_MAX_SPLIT
;i
++)
317 ui_split_dialog_line_sensitive(i
, FALSE
, data
);
318 ui_cat_comboboxentry_populate(GTK_COMBO_BOX(data
->PO_cat
[i
]), GLOBALS
->h_cat
);
320 //if( data->splittype == TXN_SPLIT_AMOUNT )
322 //if(data->amount > 0.0)
323 // gtk_spin_button_set_range(GTK_SPIN_BUTTON(data->ST_amount[i]), 0.0, G_MAXDOUBLE);
325 // gtk_spin_button_set_range(GTK_SPIN_BUTTON(data->ST_amount[i]), -G_MAXDOUBLE, 0.0);
330 count
= da_splits_count(data
->splits
);
331 data
->nbsplit
= count
> 1 ? count
-1 : 0;
333 DB( g_print("- count = %d\n", count
) );
338 split
= data
->splits
[i
];
340 DB( g_print("- set split %d : %d, %.2f, %s\n", i
, split
->kcat
, split
->amount
, split
->memo
) );
342 ui_cat_comboboxentry_set_active(GTK_COMBO_BOX(data
->PO_cat
[i
]), split
->kcat
);
343 gtk_spin_button_set_value(GTK_SPIN_BUTTON(data
->ST_amount
[i
]), split
->amount
);
344 txt
= (split
->memo
!= NULL
) ? split
->memo
: "";
345 gtk_entry_set_text(GTK_ENTRY(data
->ST_memo
[i
]), txt
);
346 ui_split_dialog_line_sensitive(i
, TRUE
, data
);
354 GtkWidget
*ui_split_dialog (GtkWidget
*parent
, Split
*ope_splits
[], gdouble amount
, void (update_callbackFunction(GtkWidget
*, gdouble
)))
356 struct ui_split_dialog_data data
;
357 GtkWidget
*dialog
, *content
, *mainvbox
, *label
;
358 GtkWidget
*table
, *widget
;
362 dialog
= gtk_dialog_new_with_buttons (_("Transaction splits"),
369 data
.dialog
= dialog
;
370 data
.splits
= ope_splits
;
371 data
.amount
= amount
;
372 data
.splittype
= amount
? TXN_SPLIT_AMOUNT
: TXN_SPLIT_NEW
;
374 gtk_dialog_add_button(GTK_DIALOG(dialog
), _("_Remove"), GTK_RESPONSE_SPLIT_REM
);
376 /* sum button must appear only when new split add */
378 //if(data.splittype == TXN_SPLIT_NEW)
379 gtk_dialog_add_button(GTK_DIALOG(dialog
), _("Sum"), GTK_RESPONSE_SPLIT_SUM
);
382 if(data
.splittype
== TXN_SPLIT_AMOUNT
)
383 gtk_dialog_add_button(GTK_DIALOG(dialog
), _("_OK"), GTK_RESPONSE_ACCEPT
);
385 //store our dialog private data
386 g_object_set_data(G_OBJECT(dialog
), "inst_data", (gpointer
)&data
);
387 DB( g_print("(ui_split_dialog) dialog=%p, inst_data=%p\n", dialog
, &data
) );
389 g_signal_connect (dialog
, "destroy",
390 G_CALLBACK (gtk_widget_destroyed
), &dialog
);
393 content
= gtk_dialog_get_content_area(GTK_DIALOG (dialog
));
394 mainvbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, SPACING_MEDIUM
);
395 gtk_box_pack_start (GTK_BOX (content
), mainvbox
, TRUE
, TRUE
, 0);
396 gtk_container_set_border_width (GTK_CONTAINER(mainvbox
), SPACING_MEDIUM
);
399 table
= gtk_grid_new ();
400 //gtk_container_set_border_width (GTK_CONTAINER (table), SP_BORDER);
401 gtk_grid_set_row_spacing (GTK_GRID (table
), SPACING_SMALL
/2);
402 gtk_grid_set_column_spacing (GTK_GRID (table
), SPACING_MEDIUM
/2);
403 gtk_box_pack_start (GTK_BOX (mainvbox
), table
, TRUE
, TRUE
, 0);
406 label
= gtk_label_new(_("Category"));
407 gimp_label_set_attributes (GTK_LABEL (label
), PANGO_ATTR_SCALE
, PANGO_SCALE_SMALL
, -1);
408 gtk_grid_attach (GTK_GRID (table
), label
, 2, row
, 1, 1);
410 label
= gtk_label_new(_("Memo"));
411 gimp_label_set_attributes (GTK_LABEL (label
), PANGO_ATTR_SCALE
, PANGO_SCALE_SMALL
, -1);
412 gtk_grid_attach (GTK_GRID (table
), label
, 3, row
, 1, 1);
414 label
= gtk_label_new(_("Amount"));
415 gimp_label_set_attributes (GTK_LABEL (label
), PANGO_ATTR_SCALE
, PANGO_SCALE_SMALL
, -1);
416 gtk_grid_attach (GTK_GRID (table
), label
, 4, row
, 1, 1);
418 for(i
=0;i
<TXN_MAX_SPLIT
;i
++)
422 data
.BT_rem
[i
] = NULL
;
423 data
.BT_add
[i
] = NULL
;
427 widget
= gtk_button_new_with_label ("-");
428 data
.BT_rem
[i
] = widget
;
429 gtk_grid_attach (GTK_GRID (table
), widget
, 0, row
, 1, 1);
432 if( (i
< (TXN_MAX_SPLIT
-1)) )
434 widget
= gtk_button_new_with_label ("+");
435 data
.BT_add
[i
] = widget
;
436 gtk_grid_attach (GTK_GRID (table
), widget
, 1, row
, 1, 1);
439 widget
= ui_cat_comboboxentry_new(NULL
);
440 data
.PO_cat
[i
] = widget
;
441 gtk_widget_set_hexpand (widget
, TRUE
);
442 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
444 widget
= make_string(NULL
);
445 gtk_widget_set_hexpand (widget
, TRUE
);
446 data
.ST_memo
[i
] = widget
;
447 gtk_grid_attach (GTK_GRID (table
), widget
, 3, row
, 1, 1);
449 widget
= make_amount(NULL
);
450 data
.ST_amount
[i
] = widget
;
451 gtk_grid_attach (GTK_GRID (table
), widget
, 4, row
, 1, 1);
453 //connect all our signals
454 g_signal_connect (data
.PO_cat
[i
], "changed", G_CALLBACK (ui_split_dialog_compute
), &data
);
455 g_signal_connect (data
.ST_memo
[i
], "insert-text", G_CALLBACK(ui_split_dialog_filter_text_handler
), NULL
);
456 data
.handler_id
[i
] = g_signal_connect (G_OBJECT (data
.ST_amount
[i
]), "value-changed", G_CALLBACK (ui_split_dialog_compute
), &data
);
458 g_signal_connect (data
.BT_rem
[i
], "clicked", G_CALLBACK (ui_split_dialog_inactiveline
), GINT_TO_POINTER(i
));
460 g_signal_connect (data
.BT_add
[i
], "clicked", G_CALLBACK (ui_split_dialog_activeline
), GINT_TO_POINTER(i
));
464 label
= gtk_label_new(_("Sum of splits:"));
465 gtk_widget_set_halign (label
, GTK_ALIGN_END
);
466 gtk_grid_attach (GTK_GRID (table
), label
, 3, row
, 1, 1);
467 widget
= gtk_label_new(NULL
);
468 gtk_widget_set_halign (widget
, GTK_ALIGN_END
);
469 data
.LB_sumsplit
= widget
;
470 gtk_grid_attach (GTK_GRID (table
), widget
, 4, row
, 1, 1);
472 if( data
.splittype
== TXN_SPLIT_AMOUNT
)
475 label
= gtk_label_new(_("Unassigned:"));
476 gtk_widget_set_halign (label
, GTK_ALIGN_END
);
477 gtk_grid_attach (GTK_GRID (table
), label
, 3, row
, 1, 1);
478 widget
= gtk_label_new(NULL
);
479 gtk_widget_set_halign (widget
, GTK_ALIGN_END
);
480 gtk_widget_set_margin_left(widget
, 20);
481 gtk_widget_set_margin_right(widget
, 20);
482 data
.LB_remain
= widget
;
483 gtk_grid_attach (GTK_GRID (table
), widget
, 4, row
, 1, 1);
486 widget
= gtk_separator_new (GTK_ORIENTATION_HORIZONTAL
);
487 gtk_grid_attach (GTK_GRID (table
), widget
, 4, row
, 1, 1);
490 label
= gtk_label_new(_("Transaction amount:"));
491 gtk_widget_set_halign (label
, GTK_ALIGN_END
);
492 gtk_grid_attach (GTK_GRID (table
), label
, 3, row
, 1, 1);
493 widget
= gtk_label_new(NULL
);
494 gtk_widget_set_halign (widget
, GTK_ALIGN_END
);
495 gtk_widget_set_margin_left(widget
, 20);
496 gtk_widget_set_margin_right(widget
, 20);
497 data
.LB_txnamount
= widget
;
498 gtk_grid_attach (GTK_GRID (table
), widget
, 4, row
, 1, 1);
502 //setup, init and show dialog
503 //ui_cur_manage_dialog_setup(&data);
506 ui_split_dialog_set(&data
);
507 ui_split_dialog_compute(NULL
, &data
);
510 //ui_cur_manage_dialog_update(data.LV_cur, NULL);
512 gtk_window_set_default_size(GTK_WINDOW(dialog
), 480, -1);
514 gtk_widget_show_all (dialog
);
517 gint result
= gtk_dialog_run (GTK_DIALOG (dialog
));
521 case GTK_RESPONSE_ACCEPT
:
522 //do_application_specific_something ();
523 ui_split_dialog_get(&data
);
524 update_callbackFunction(parent
,data
.sumsplit
);
526 case GTK_RESPONSE_SPLIT_REM
:
527 da_splits_free(ope_splits
);
528 update_callbackFunction(parent
,data
.sumsplit
);
530 case GTK_RESPONSE_SPLIT_SUM
: // sum split and alter txn amount
531 ui_split_dialog_get(&data
);
532 update_callbackFunction(parent
,data
.sumsplit
);
535 //do_nothing_since_dialog_was_cancelled ();
544 for(i=0;i<TXN_MAX_SPLIT;i++)
546 Split *split = data.ope_splits[i];
547 if(data.ope_splits[i] == NULL)
549 g_print(" split %d : %d, %.2f, %s\n", i, split->kcat, split->amount, split->memo);
554 // cleanup and destroy
555 //GLOBALS->changes_count += data.change;
556 gtk_widget_destroy (dialog
);