GnuCash c935c2f+
Loading...
Searching...
No Matches
dialog-sx-from-trans.cpp
1/********************************************************************
2 * dialog-sx-from-trans.c -- a simple dialog for creating a *
3 * scheduled transaction from a real one *
4 * Copyright (C) 2001 Robert Merkel <rgmerk@mira.net> *
5 * Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
6 * Copyright (c) 2006 David Hampton <hampton@employees.org> *
7 * Copyright (c) 2011 Robert Fewell *
8 * *
9 * This program is free software; you can redistribute it and/or *
10 * modify it under the terms of the GNU General Public License as *
11 * published by the Free Software Foundation; either version 2 of *
12 * the License, or (at your option) any later version. *
13 * *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License*
20 * along with this program; if not, contact: *
21 * *
22 * Free Software Foundation Voice: +1-617-542-5942 *
23 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
24 * Boston, MA 02110-1301, USA gnu@gnu.org *
25 ********************************************************************/
26
27#include <config.h>
28
29#include "dialog-sx-editor.h"
30#include "dialog-sx-from-trans.h"
31#include "dialog-utils.h"
32#include "gnc-component-manager.h"
33#include "gnc-date.h"
34#include "gnc-date-edit.h"
35#include "gnc-dense-cal-store.h"
36#include "gnc-dense-cal.h"
37#include "gnc-engine.h"
38#include "engine-helpers.h"
39#include "gnc-prefs.h"
40#include "gnc-ui-util.h"
41#include "gnc-ui.h"
42#include "qof.h"
43#include "Recurrence.h"
44#include "SchedXaction.h"
45#include "SchedXaction.hpp"
46#include "SX-book.h"
47#include "SX-ttinfo.hpp"
48#include <glib/gi18n.h>
49#include <gtk/gtk.h>
50#include <stdlib.h>
51
52#define SXFTD_ERRNO_UNBALANCED_XACTION 3
53#define SXFTD_ERRNO_OPEN_XACTION -3
54
55#define SXFTD_EXCAL_NUM_MONTHS 4
56#define SXFTD_EXCAL_MONTHS_PER_COL 4
57
58#define SXFTD_RESPONSE_ADVANCED 100 /* 'Advanced' button response code */
59
60#undef G_LOG_DOMAIN
61#define G_LOG_DOMAIN GNC_MOD_GUI_SX
62
63static QofLogModule log_module = GNC_MOD_GUI_SX;
64
65static void sxftd_freq_combo_changed( GtkWidget *w, gpointer user_data );
66static void gnc_sx_trans_window_response_cb(GtkDialog *dialog, gint response, gpointer data);
67
68static void sxftd_destroy( GtkWidget *w, gpointer user_data );
69
70typedef enum { FREQ_DAILY = 0, /* I know the =0 is redundant, but I'm using
71 * the numeric equivalences explicitly here */
72 FREQ_WEEKLY,
73 FREQ_BIWEEKLY,
74 FREQ_MONTHLY,
75 FREQ_QUARTERLY,
76 FREQ_ANNUALLY
77 } SxftiFreqType;
78
79typedef struct
80{
81 GtkBuilder *builder;
82 GtkWidget *dialog;
83 GtkEntry *name;
84 GtkComboBox *freq_combo;
85
86 GtkToggleButton *ne_but;
87 GtkToggleButton *ed_but;
88 GtkToggleButton *oc_but;
89 GtkEntry *n_occurences;
90
91 Transaction *trans;
92 SchedXaction *sx;
93
94 GncDenseCalStore *dense_cal_model;
95 GncDenseCal *example_cal;
96
97 GNCDateEdit *startDateGDE, *endDateGDE;
98
100
101typedef struct
102{
103 gdcs_end_type type;
104 GDate end_date;
105 guint n_occurrences;
107
108static void sxftd_update_example_cal( SXFromTransInfo *sxfti );
109static void sxftd_update_excal_adapt( GObject *o, gpointer ud );
110
112{
113 const gchar *name;
114 const gchar *signal;
115 void (*handlerFn)(GObject*,gpointer);
116};
117
118static void sxftd_ok_clicked(SXFromTransInfo *sxfti);
119static void sxftd_advanced_clicked(SXFromTransInfo *sxfti);
120
121static void
122sxfti_attach_callbacks(SXFromTransInfo *sxfti)
123{
124
125 widgetSignalHandlerTuple callbacks[] =
126 {
127 /* Whenever any of the controls change, we want to update the
128 * calendar. */
129 { "never_end_button", "clicked", sxftd_update_excal_adapt },
130 { "end_on_date_button", "clicked", sxftd_update_excal_adapt },
131 { "n_occurrences_button", "clicked", sxftd_update_excal_adapt },
132 { "n_occurrences_entry", "changed", sxftd_update_excal_adapt },
133 { NULL, NULL, NULL }
134 };
135
136 int i;
137
138 GtkWidget *w;
139 for (i = 0; callbacks[i].name != NULL; i++)
140 {
141 w = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, callbacks[i].name));
142
143 g_signal_connect (G_OBJECT(w), callbacks[i].signal,
144 G_CALLBACK(callbacks[i].handlerFn),
145 sxfti );
146 }
147
148 g_signal_connect (G_OBJECT(sxfti->dialog), "response",
149 G_CALLBACK (gnc_sx_trans_window_response_cb),
150 sxfti);
151}
152
153
154static getEndTuple
155sxftd_get_end_info(SXFromTransInfo *sxfti)
156{
157 getEndTuple retval;
158
159 retval.type = BAD_END;
160 g_date_clear( &(retval.end_date), 1 );
161 retval.n_occurrences = 0;
162
163 if (gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxfti->ne_but)))
164 {
165 retval.type = NEVER_END;
166 return retval;
167 }
168
169 if (gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxfti->ed_but)))
170 {
171 time64 end_tt;
172 retval.type = END_ON_DATE;
173 g_date_clear( &(retval.end_date), 1 );
174 end_tt = gnc_date_edit_get_date(sxfti->endDateGDE);
175 gnc_gdate_set_time64( &(retval.end_date), end_tt);
176 return retval;
177 }
178
179 if (gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxfti->oc_but) ))
180 {
181 guint n_occs;
182
183 const gchar *text = gtk_entry_get_text (GTK_ENTRY(sxfti->n_occurences));
184 if (!text || !text[0])
185 {
186 n_occs = 0;
187 }
188 else
189 {
190 gchar *endptr;
191 n_occs = strtoul(text, &endptr, 10);
192 if ( !endptr )
193 {
194 n_occs = -1;
195 }
196 }
197
198 retval.type = END_AFTER_N_OCCS;
199 retval.n_occurrences = n_occs;
200 return retval;
201 }
202 return retval;
203}
204
205
206static guint
207sxftd_add_template_trans(SXFromTransInfo *sxfti)
208{
209
210 Transaction *tr = sxfti->trans;
211 GList *splits = NULL;
212 TTInfoPtr tti = std::make_shared<TTInfo>();
213 TTSplitInfoPtr ttsi;
214 gnc_numeric runningBalance;
215 gnc_numeric split_value;
216 const char *tmpStr;
217
218 runningBalance = gnc_numeric_zero();
219
220 tti->set_description(xaccTransGetDescription(tr));
221 tti->set_num(gnc_get_num_action(tr, NULL));
222 tti->set_notes (xaccTransGetNotes (tr));
223 tti->set_currency(xaccTransGetCurrency(tr));
224
225 tti->clear_template_splits ();
226
227 for (splits = xaccTransGetSplitList(tr); splits; splits = splits->next)
228 {
229 auto sp = GNC_SPLIT(splits->data);
230 ttsi = std::make_shared<TTSplitInfo>();
231 ttsi->set_action (gnc_get_num_action(NULL, sp));
232 split_value = xaccSplitGetValue(sp);
233 ttsi->set_memo (xaccSplitGetMemo(sp));
234
235 runningBalance = gnc_numeric_add( runningBalance, split_value,
236 100, (GNC_DENOM_AUTO | GNC_HOW_DENOM_LCD) );
237
238 if (gnc_numeric_positive_p(split_value))
239 {
240 tmpStr = xaccPrintAmount( split_value,
241 gnc_default_print_info(FALSE) );
242 ttsi->set_debit_formula (tmpStr);
243 }
244 else
245 {
246 /* Negate the numeric so it prints w/o the sign at the front. */
247 tmpStr = xaccPrintAmount( gnc_numeric_neg( split_value ),
248 gnc_default_print_info(FALSE) );
249 ttsi->set_credit_formula (tmpStr);
250 }
251
252 /* Copy over per-split account info */
253 ttsi->set_account (xaccSplitGetAccount (sp));
254
255 tti->append_template_split (ttsi);
256 }
257
258 if ( ! gnc_numeric_zero_p( runningBalance )
259 && !gnc_verify_dialog (GTK_WINDOW (sxfti->dialog),
260 FALSE, "%s",
261 _("The Scheduled Transaction Editor "
262 "cannot automatically balance "
263 "this transaction. "
264 "Should it still be "
265 "entered?") ) )
266 {
267 return SXFTD_ERRNO_UNBALANCED_XACTION;
268 }
269
270 gnc_suspend_gui_refresh ();
271 xaccSchedXactionSetTemplateTrans (sxfti->sx, { tti }, gnc_get_current_book ());
272 gnc_resume_gui_refresh ();
273
274 return 0;
275}
276
277
278static void
279sxftd_update_schedule( SXFromTransInfo *sxfti, GDate *date, GList **recurrences)
280{
281 gint index;
282
283 /* Note that we make the start date the *NEXT* instance, not the
284 * present one. */
285
286 index = gtk_combo_box_get_active(GTK_COMBO_BOX(sxfti->freq_combo));
287
288 switch (index)
289 {
290 case FREQ_DAILY:
291 {
292 Recurrence *r = g_new0(Recurrence, 1);
293 recurrenceSet(r, 1, PERIOD_DAY, date, WEEKEND_ADJ_NONE);
294 *recurrences = g_list_append(*recurrences, r);
295 }
296 break;
297
298 case FREQ_WEEKLY:
299 case FREQ_BIWEEKLY:
300 {
301 Recurrence *r = g_new0(Recurrence, 1);
302 int mult = (index == FREQ_BIWEEKLY ? 2 : 1);
303 recurrenceSet(r, mult, PERIOD_WEEK, date, WEEKEND_ADJ_NONE);
304 *recurrences = g_list_append(*recurrences, r);
305 }
306 break;
307
308 case FREQ_MONTHLY:
309 case FREQ_QUARTERLY:
310 case FREQ_ANNUALLY:
311 {
312 Recurrence *r = g_new0(Recurrence, 1);
313 int mult = (index == FREQ_MONTHLY
314 ? 1
315 : (index == FREQ_QUARTERLY
316 ? 3
317 : 12));
318 recurrenceSet(r, mult, PERIOD_MONTH, date, recurrenceGetWeekendAdjust(r));
319 *recurrences = g_list_append(*recurrences, r);
320 }
321 break;
322
323 default:
324 g_critical("nonexistent frequency selected");
325 break;
326 }
327}
328
329
330static gint
331sxftd_init( SXFromTransInfo *sxfti )
332{
333 GtkWidget *w;
334 const char *transName;
335 gint pos;
336 GList *schedule = NULL;
337 time64 start_tt;
338 GDate date, nextDate;
339
340 if ( ! sxfti->sx )
341 {
342 return -1;
343 }
344 if ( ! sxfti->trans )
345 {
346 return -2;
347 }
348 if ( xaccTransIsOpen( sxfti->trans ) )
349 {
350 return SXFTD_ERRNO_OPEN_XACTION;
351 }
352
353 /* Setup Widgets */
354 {
355 sxfti->ne_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder, "never_end_button"));
356 sxfti->ed_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder, "end_on_date_button"));
357 sxfti->oc_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder, "n_occurrences_button"));
358 sxfti->n_occurences = GTK_ENTRY(gtk_builder_get_object(sxfti->builder, "n_occurrences_entry"));
359 }
360
361 /* Get the name from the transaction, try that as the initial SX name. */
362 transName = xaccTransGetDescription( sxfti->trans );
363 xaccSchedXactionSetName( sxfti->sx, transName );
364
365 sxfti->name = GTK_ENTRY(gtk_builder_get_object(sxfti->builder, "name_entry" ));
366 pos = 0;
367 gtk_editable_insert_text( GTK_EDITABLE(sxfti->name), transName,
368 (strlen(transName) * sizeof(char)), &pos );
369
370 sxfti_attach_callbacks(sxfti);
371
372 /* Setup the example calendar and related data structures. */
373 {
374 int num_marks = SXFTD_EXCAL_NUM_MONTHS * 31;
375
376 w = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, "ex_cal_frame" ));
377 sxfti->dense_cal_model = gnc_dense_cal_store_new(num_marks);
378 sxfti->example_cal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model (GTK_WINDOW(sxfti->dialog),
379 GNC_DENSE_CAL_MODEL(sxfti->dense_cal_model)));
380 g_object_ref_sink(sxfti->example_cal);
381
382 g_assert(sxfti->example_cal);
383 gnc_dense_cal_set_num_months( sxfti->example_cal, SXFTD_EXCAL_NUM_MONTHS );
384 gnc_dense_cal_set_months_per_col( sxfti->example_cal, SXFTD_EXCAL_MONTHS_PER_COL );
385 gtk_container_add( GTK_CONTAINER(w), GTK_WIDGET(sxfti->example_cal) );
386 }
387
388 /* Setup the start and end dates as GNCDateEdits */
389 {
390 GtkWidget *paramTable = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, "param_table" ));
391 sxfti->startDateGDE = GNC_DATE_EDIT( gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE));
392
393 gtk_grid_attach (GTK_GRID(paramTable), GTK_WIDGET(sxfti->startDateGDE), 1, 2, 1, 1);
394 gtk_widget_set_halign (GTK_WIDGET(sxfti->startDateGDE), GTK_ALIGN_FILL);
395 gtk_widget_set_valign (GTK_WIDGET(sxfti->startDateGDE), GTK_ALIGN_FILL);
396 gtk_widget_set_hexpand (GTK_WIDGET(sxfti->startDateGDE), TRUE);
397 gtk_widget_set_vexpand (GTK_WIDGET(sxfti->startDateGDE), FALSE);
398 g_object_set (GTK_WIDGET(sxfti->startDateGDE), "margin", 0, NULL);
399
400 g_signal_connect( sxfti->startDateGDE, "date-changed",
401 G_CALLBACK( sxftd_update_excal_adapt ),
402 sxfti );
403 }
404 {
405 GtkWidget *endDateBox = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, "end_date_hbox" ));
406 sxfti->endDateGDE =
407 GNC_DATE_EDIT( gnc_date_edit_new (gnc_time (NULL),
408 FALSE, FALSE));
409 gtk_box_pack_start( GTK_BOX( endDateBox ),
410 GTK_WIDGET( sxfti->endDateGDE ),
411 TRUE, TRUE, 0 );
412 g_signal_connect( sxfti->endDateGDE, "date-changed",
413 G_CALLBACK( sxftd_update_excal_adapt ),
414 sxfti );
415 }
416
417 /* Setup the initial start date for user display/confirmation */
418 /* compute good initial date. */
419 start_tt = xaccTransGetDate( sxfti->trans );
420 gnc_gdate_set_time64( &date, start_tt );
421 sxfti->freq_combo = GTK_COMBO_BOX(gtk_builder_get_object(sxfti->builder, "freq_combo_box"));
422 gtk_combo_box_set_active(GTK_COMBO_BOX(sxfti->freq_combo), 0);
423 g_signal_connect( sxfti->freq_combo, "changed",
424 G_CALLBACK(sxftd_freq_combo_changed),
425 sxfti );
426 sxftd_update_schedule( sxfti, &date, &schedule);
427 recurrenceListNextInstance(schedule, &date, &nextDate);
428 recurrenceListFree(&schedule);
429 start_tt = gnc_time64_get_day_start_gdate (&nextDate);
430 gnc_date_edit_set_time( sxfti->startDateGDE, start_tt );
431
432 g_signal_connect( G_OBJECT(sxfti->name), "destroy",
433 G_CALLBACK(sxftd_destroy),
434 sxfti );
435
436 sxftd_update_example_cal( sxfti );
437
438 return 0;
439}
440
441
442static guint
443sxftd_compute_sx(SXFromTransInfo *sxfti)
444{
445 GDate date;
446 GList *schedule = NULL;
447 getEndTuple end_info;
448 guint sxftd_errno = 0; /* 0 == OK, > 0 means dialog needs to be run again */
449
450 SchedXaction *sx = sxfti->sx;
451
452 /* get the name */
453 xaccSchedXactionSetName(sx, gtk_entry_get_text (sxfti->name));
454
455 gnc_gdate_set_time64( &date, gnc_date_edit_get_date( sxfti->startDateGDE ) );
456
457 sxftd_update_schedule(sxfti, &date, &schedule);
458 if (sxftd_errno == 0)
459 {
460 gnc_sx_set_schedule(sx, schedule);
461 xaccSchedXactionSetStartDate( sx, &date );
462 }
463
464 end_info = sxftd_get_end_info(sxfti);
465
466 switch (end_info.type)
467 {
468 case NEVER_END:
469 break;
470
471 case END_ON_DATE:
472 xaccSchedXactionSetEndDate(sx, &(end_info.end_date));
473 break;
474
475 case END_AFTER_N_OCCS:
476 xaccSchedXactionSetNumOccur(sx, end_info.n_occurrences);
477 break;
478
479 default:
480 sxftd_errno = 2;
481 break;
482 }
483
485
486 /* Set the autocreate, days-in-advance and remind-in-advance values from
487 * options. */
488 {
489 gboolean autoCreateState, notifyState;
490 gint daysInAdvance;
491
492 autoCreateState =
493 gnc_prefs_get_bool (GNC_PREFS_GROUP_SXED, GNC_PREF_CREATE_AUTO);
494 notifyState =
495 gnc_prefs_get_bool (GNC_PREFS_GROUP_SXED, GNC_PREF_NOTIFY);
496 xaccSchedXactionSetAutoCreate( sx,
497 autoCreateState,
498 (autoCreateState & notifyState) );
499
500 daysInAdvance =
501 gnc_prefs_get_float (GNC_PREFS_GROUP_SXED, GNC_PREF_CREATE_DAYS);
502 xaccSchedXactionSetAdvanceCreation( sx, daysInAdvance );
503
504 daysInAdvance =
505 gnc_prefs_get_float (GNC_PREFS_GROUP_SXED, GNC_PREF_REMIND_DAYS);
506 xaccSchedXactionSetAdvanceReminder( sx, daysInAdvance );
507 }
508
509 if ( sxftd_add_template_trans( sxfti ) != 0 )
510 {
511 sxftd_errno = SXFTD_ERRNO_UNBALANCED_XACTION;
512 }
513
514 return sxftd_errno;
515}
516
517
518static void
519sxftd_close(SXFromTransInfo *sxfti, gboolean delete_sx)
520{
521 if ( sxfti->sx && delete_sx )
522 {
523 gnc_sx_begin_edit(sxfti->sx);
524 xaccSchedXactionDestroy(sxfti->sx);
525 }
526 sxfti->sx = NULL;
527
528 gtk_widget_destroy (GTK_WIDGET (sxfti->dialog));
529}
530
531
532static void
533sxftd_ok_clicked(SXFromTransInfo *sxfti)
534{
535 QofBook *book;
536 SchedXactions *sxes;
537 guint sx_error = sxftd_compute_sx(sxfti);
538
539 if (sx_error != 0
540 && sx_error != SXFTD_ERRNO_UNBALANCED_XACTION)
541 {
542 g_critical("sxftd_compute_sx after ok_clicked [%d]", sx_error);
543 }
544 else
545 {
546 if ( sx_error == SXFTD_ERRNO_UNBALANCED_XACTION )
547 {
548 gnc_error_dialog (GTK_WINDOW (sxfti->dialog), "%s",
549 _( "The Scheduled Transaction is unbalanced. "
550 "You are strongly encouraged to correct this situation." ) );
551 }
552 book = gnc_get_current_book ();
553 sxes = gnc_book_get_schedxactions(book);
554 gnc_sxes_add_sx(sxes, sxfti->sx);
555 }
556
557 sxftd_close(sxfti, FALSE);
558 return;
559}
560
561
567static void
568sxftd_freq_combo_changed( GtkWidget *w, gpointer user_data )
569{
570 SXFromTransInfo *sxfti = (SXFromTransInfo*)user_data;
571 GDate date, nextDate;
572 time64 tmp_tt;
573 GList *schedule = NULL;
574
575 tmp_tt = xaccTransGetDate( sxfti->trans );
576 gnc_gdate_set_time64 (&date, tmp_tt);
577
578 g_date_clear(&nextDate, 1);
579 sxftd_update_schedule(sxfti, &date, &schedule);
580 recurrenceListNextInstance(schedule, &date, &nextDate);
581 tmp_tt = gnc_time64_get_day_start_gdate (&nextDate);
582 gnc_date_edit_set_time( sxfti->startDateGDE, tmp_tt );
583
584 recurrenceListFree(&schedule);
585 sxftd_update_example_cal( sxfti );
586}
587
588
589static void
590sxftd_advanced_clicked(SXFromTransInfo *sxfti)
591{
592 guint sx_error = sxftd_compute_sx(sxfti);
593 GMainContext *context;
594
595 if ( sx_error != 0 && sx_error != SXFTD_ERRNO_UNBALANCED_XACTION )
596 {
597 // unbalanced-xaction is "okay", since this is also checked for by
598 // the advanced editor.
599 g_warning("something bad happened in sxftd_compute_sx [%d]", sx_error);
600 return;
601 }
602 gtk_widget_hide( sxfti->dialog );
603 /* force a gui update. */
604 context = g_main_context_default();
605 while (g_main_context_iteration(context, FALSE));
606
607 gnc_ui_scheduled_xaction_editor_dialog_create(gnc_ui_get_main_window (sxfti->dialog),
608 sxfti->sx, TRUE /* newSX */);
609 /* close ourself, since advanced editing entails us, and there are sync
610 * issues otherwise. */
611 sxftd_close(sxfti, FALSE);
612}
613
614
615static void
616sxftd_destroy( GtkWidget *w, gpointer user_data )
617{
618 SXFromTransInfo *sxfti = (SXFromTransInfo*)user_data;
619
620 if ( sxfti->sx )
621 {
622 gnc_sx_begin_edit(sxfti->sx);
623 xaccSchedXactionDestroy(sxfti->sx);
624 sxfti->sx = NULL;
625 }
626 if (sxfti->dense_cal_model)
627 g_object_unref(G_OBJECT(sxfti->dense_cal_model));
628 if (sxfti->example_cal)
629 g_object_unref(G_OBJECT(sxfti->example_cal));
630
631 g_free(sxfti);
632}
633
634
635static void
636gnc_sx_trans_window_response_cb (GtkDialog *dialog,
637 gint response,
638 gpointer data)
639{
640 SXFromTransInfo *sxfti = (SXFromTransInfo *)data;
641
642 ENTER(" dialog %p, response %d, sx %p", dialog, response, sxfti);
643 switch (response)
644 {
645 case GTK_RESPONSE_OK:
646 DEBUG(" OK");
647 sxftd_ok_clicked(sxfti);
648 break;
649 case SXFTD_RESPONSE_ADVANCED:
650 DEBUG(" ADVANCED");
651 sxftd_advanced_clicked(sxfti);
652 break;
653 case GTK_RESPONSE_CANCEL:
654 default:
655 DEBUG(" CANCEL");
656 sxftd_close(sxfti, TRUE);
657 break;
658
659 }
660 LEAVE(" ");
661}
662
663
668static void
669sxftd_update_example_cal( SXFromTransInfo *sxfti )
670{
671 time64 tmp_tt;
672 GDate date, startDate, nextDate;
673 GList *schedule = NULL;
674 getEndTuple get;
675
676 get = sxftd_get_end_info( sxfti );
677
678 tmp_tt = gnc_date_edit_get_date( sxfti->startDateGDE );
679 gnc_gdate_set_time64 (&date, tmp_tt);
680
681 sxftd_update_schedule(sxfti, &date, &schedule);
682
683 /* go one day before what's in the box so we can get the correct start
684 * date. */
685 startDate = date;
686 g_date_subtract_days(&date, 1);
687 g_date_clear(&nextDate, 1);
688 recurrenceListNextInstance(schedule, &date, &nextDate);
689
690 gnc_dense_cal_store_update_name (sxfti->dense_cal_model,
691 gtk_entry_get_text (sxfti->name));
692
693 {
694 gchar *schedule_desc;
695 schedule_desc = recurrenceListToCompactString(schedule);
696 gnc_dense_cal_store_update_info(sxfti->dense_cal_model, schedule_desc);
697 g_free(schedule_desc);
698 }
699
700 /* Set End date sensitivity */
701 gtk_widget_set_sensitive( GTK_WIDGET(sxfti->endDateGDE), (get.type == END_ON_DATE) );
702 gtk_widget_set_sensitive( GTK_WIDGET(sxfti->n_occurences), (get.type == END_AFTER_N_OCCS) );
703
704 /* Use the day preceding the start date for the store to find the correct real start date */
705 switch (get.type)
706 {
707 case NEVER_END:
708 gnc_dense_cal_store_update_recurrences_no_end(sxfti->dense_cal_model, &date, schedule);
709 break;
710 case END_ON_DATE:
711 gnc_dense_cal_store_update_recurrences_date_end(sxfti->dense_cal_model, &date, schedule, &get.end_date);
712 break;
713 case END_AFTER_N_OCCS:
714 gnc_dense_cal_store_update_recurrences_count_end(sxfti->dense_cal_model, &date, schedule, get.n_occurrences);
715 break;
716 default:
717 g_warning("unknown get.type [%d]\n", get.type);
718 break;
719 }
720
721 gnc_dense_cal_set_month( sxfti->example_cal, g_date_get_month( &startDate ) );
722 gnc_dense_cal_set_year( sxfti->example_cal, g_date_get_year( &startDate ) );
723
724 recurrenceListFree(&schedule);
725}
726
727
728/***********************************
729 * Callback to update the calendar *
730 **********************************/
731static void
732sxftd_update_excal_adapt( GObject *o, gpointer ud )
733{
734 SXFromTransInfo *sxfti = (SXFromTransInfo*)ud;
735 sxftd_update_example_cal( sxfti );
736}
737
738
739/*********************
740 * Create the dialog *
741 ********************/
742void
743gnc_sx_create_from_trans( GtkWindow *parent, Transaction *trans )
744{
745 int sx_error;
746 SXFromTransInfo *sxfti = g_new0( SXFromTransInfo, 1);
747 GtkBuilder *builder;
748 GtkWidget *dialog;
749
750 builder = gtk_builder_new();
751
752 gnc_builder_add_from_file (builder , "dialog-sx.glade", "freq_liststore");
753
754 gnc_builder_add_from_file (builder , "dialog-sx.glade", "sx_from_real_trans_dialog");
755 dialog = GTK_WIDGET(gtk_builder_get_object (builder, "sx_from_real_trans_dialog"));
756
757 // Set the name of this dialog so it can be easily manipulated with css
758 gtk_widget_set_name (GTK_WIDGET(dialog), "gnc-id-sx-from-trans");
759 gnc_widget_style_context_add_class (GTK_WIDGET(dialog), "gnc-class-sx");
760
761 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
762
763 sxfti->builder = builder;
764 sxfti->dialog = dialog;
765 sxfti->trans = trans;
766
767 sxfti->sx = xaccSchedXactionMalloc(gnc_get_current_book ());
768
769 if ( (sx_error = sxftd_init( sxfti )) < 0 )
770 {
771 if ( sx_error == SXFTD_ERRNO_OPEN_XACTION )
772 {
773 gnc_error_dialog (NULL, "%s",
774 _( "Cannot create a Scheduled Transaction "
775 "from a Transaction currently "
776 "being edited. Please Enter the "
777 "Transaction before Scheduling." ) );
778 sxftd_destroy (NULL, sxfti);
779 return;
780 }
781 else
782 {
783 g_error("sxftd_init: %d", sx_error);
784 }
785 }
786
787 gtk_widget_show_all(GTK_WIDGET(sxfti->dialog));
788
789 gtk_builder_connect_signals(builder, sxfti);
790 g_object_unref(G_OBJECT(builder));
791}
Anchor Scheduled Transaction info in a book.
Scheduled Transactions public handling routines.
Date and Time handling routines.
All type declarations for the whole Gnucash engine.
Generic api to store and retrieve preferences.
utility functions for the GnuCash UI
void gnc_gdate_set_time64(GDate *gd, time64 time)
Set a GDate to a time64.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
time64 gnc_time64_get_day_start_gdate(const GDate *date)
The gnc_time64_get_day_start() routine will take the given time in GLib GDate format and adjust it to...
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing.
const char * xaccTransGetNotes(const Transaction *trans)
Gets the transaction Notes.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
gdouble gnc_prefs_get_float(const gchar *group, const gchar *pref_name)
Get an float value from the preferences backend.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
Creates and initializes a scheduled transaction.
void xaccSchedXactionSetName(SchedXaction *sx, const gchar *newName)
A copy of the name is made.
void xaccSchedXactionSetEndDate(SchedXaction *sx, const GDate *newEnd)
Set to an invalid GDate to turn off 'end-date' definition.
void xaccSchedXactionDestroy(SchedXaction *sx)
Cleans up and frees a SchedXaction and its associated data.
void xaccSchedXactionSetNumOccur(SchedXaction *sx, gint new_num)
Set to '0' to turn off number-of-occurrences definition.
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
Sets the instance count to something other than the default.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
QofBook reference.
Definition qofbook-p.hpp:47