GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dialog-sx-from-trans.c
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 <[email protected]> *
5  * Copyright (C) 2001 Joshua Sled <[email protected]> *
6  * Copyright (c) 2006 David Hampton <[email protected]> *
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 [email protected] *
25  ********************************************************************/
26 
27 #include "config.h"
28 
29 #include <gnc-gdate-utils.h>
30 #include "dialog-sx-editor.h"
31 #include "dialog-sx-from-trans.h"
32 #include "dialog-utils.h"
33 #include "gnc-component-manager.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 "SX-book.h"
46 #include "SX-ttinfo.h"
47 #include <glib/gi18n.h>
48 #include <gtk/gtk.h>
49 #include <stdlib.h>
50 
51 #define SXFTD_ERRNO_UNBALANCED_XACTION 3
52 #define SXFTD_ERRNO_OPEN_XACTION -3
53 
54 #define SXFTD_EXCAL_NUM_MONTHS 4
55 #define SXFTD_EXCAL_MONTHS_PER_COL 4
56 
57 #define SXFTD_RESPONSE_ADVANCED 100 /* 'Advanced' button response code */
58 
59 #undef G_LOG_DOMAIN
60 #define G_LOG_DOMAIN GNC_MOD_GUI_SX
61 
62 static QofLogModule log_module = GNC_MOD_GUI_SX;
63 
64 static void sxftd_freq_combo_changed( GtkWidget *w, gpointer user_data );
65 static void gnc_sx_trans_window_response_cb(GtkDialog *dialog, gint response, gpointer data);
66 
67 static void sxftd_destroy( GtkWidget *w, gpointer user_data );
68 
69 typedef enum { FREQ_DAILY = 0, /* I know the =0 is redundant, but I'm using
70  * the numeric equivalences explicitly here */
71  FREQ_WEEKLY,
72  FREQ_BIWEEKLY,
73  FREQ_MONTHLY,
74  FREQ_QUARTERLY,
75  FREQ_ANNUALLY
76  } SxftiFreqType;
77 
78 typedef struct
79 {
80  GtkBuilder *builder;
81  GtkWidget *dialog;
82  GtkEntry *name;
83  GtkComboBox *freq_combo;
84 
85  GtkToggleButton *ne_but;
86  GtkToggleButton *ed_but;
87  GtkToggleButton *oc_but;
88  GtkEntry *n_occurences;
89 
90  Transaction *trans;
91  SchedXaction *sx;
92 
93  GncDenseCalStore *dense_cal_model;
94  GncDenseCal *example_cal;
95 
96  GNCDateEdit *startDateGDE, *endDateGDE;
97 
99 
100 typedef struct
101 {
102  gdcs_end_type type;
103  GDate end_date;
104  guint n_occurrences;
105 } getEndTuple;
106 
107 static void sxftd_update_example_cal( SXFromTransInfo *sxfti );
108 static void sxftd_update_excal_adapt( GObject *o, gpointer ud );
109 
110 typedef struct
111 {
112  gchar *name;
113  gchar *signal;
114  void (*handlerFn)();
116 
117 static void sxftd_ok_clicked(SXFromTransInfo *sxfti);
118 static void sxftd_advanced_clicked(SXFromTransInfo *sxfti);
119 
120 static void
121 sxfti_attach_callbacks(SXFromTransInfo *sxfti)
122 {
123 
124  widgetSignalHandlerTuple callbacks[] =
125  {
126  /* Whenever any of the controls change, we want to update the
127  * calendar. */
128  { "never_end_button", "clicked", sxftd_update_excal_adapt },
129  { "end_on_date_button", "clicked", sxftd_update_excal_adapt },
130  { "n_occurrences_button", "clicked", sxftd_update_excal_adapt },
131  { "n_occurrences_entry", "changed", sxftd_update_excal_adapt },
132  { NULL, NULL, NULL }
133  };
134 
135  int i;
136 
137  GtkWidget *w;
138  for (i = 0; callbacks[i].name != NULL; i++)
139  {
140  w = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, callbacks[i].name));
141 
142  g_signal_connect (GTK_OBJECT(w), callbacks[i].signal,
143  G_CALLBACK(callbacks[i].handlerFn),
144  sxfti );
145  }
146 
147  g_signal_connect (G_OBJECT(sxfti->dialog), "response",
148  G_CALLBACK (gnc_sx_trans_window_response_cb),
149  sxfti);
150 }
151 
152 
153 static getEndTuple
154 sxftd_get_end_info(SXFromTransInfo *sxfti)
155 {
156  getEndTuple retval;
157 
158  retval.type = BAD_END;
159  g_date_clear( &(retval.end_date), 1 );
160  retval.n_occurrences = 0;
161 
162  if (gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxfti->ne_but)))
163  {
164  retval.type = NEVER_END;
165  return retval;
166  }
167 
168  if (gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxfti->ed_but)))
169  {
170  time64 end_tt;
171  retval.type = END_ON_DATE;
172  g_date_clear( &(retval.end_date), 1 );
173  end_tt = gnc_date_edit_get_date(sxfti->endDateGDE);
174  gnc_gdate_set_time64( &(retval.end_date), end_tt);
175  return retval;
176  }
177 
178  if (gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxfti->oc_but) ))
179  {
180  gchar *text, *endptr;
181  guint n_occs;
182 
183  text = gtk_editable_get_chars(GTK_EDITABLE(sxfti->n_occurences), 0, -1);
184  if (text == NULL || strlen(text) == 0)
185  {
186  n_occs = 0;
187  }
188  else
189  {
190  n_occs = strtoul(text, &endptr, 10);
191  if ( !endptr )
192  {
193  n_occs = -1;
194  }
195  }
196  g_free(text);
197 
198  retval.type = END_AFTER_N_OCCS;
199  retval.n_occurrences = n_occs;
200  return retval;
201  }
202  return retval;
203 }
204 
205 
206 static guint
207 sxftd_add_template_trans(SXFromTransInfo *sxfti)
208 {
209 
210  Transaction *tr = sxfti->trans;
211  GList *tt_list = NULL;
212  GList *splits, *template_splits = NULL;
213  TTInfo *tti = gnc_ttinfo_malloc();
214  TTSplitInfo *ttsi;
215  Split *sp;
216  gnc_numeric runningBalance;
217  gnc_numeric split_value;
218  const char *tmpStr;
219 
220  runningBalance = gnc_numeric_zero();
221 
222  gnc_ttinfo_set_description(tti, xaccTransGetDescription(tr));
223  gnc_ttinfo_set_num(tti, gnc_get_num_action(tr, NULL));
224  gnc_ttinfo_set_currency(tti, xaccTransGetCurrency(tr));
225 
226  for (splits = xaccTransGetSplitList(tr); splits; splits = splits->next)
227  {
228  sp = splits->data;
229  ttsi = gnc_ttsplitinfo_malloc();
230  gnc_ttsplitinfo_set_action(ttsi, gnc_get_num_action(NULL, sp));
231  split_value = xaccSplitGetValue(sp);
232  gnc_ttsplitinfo_set_memo(ttsi, xaccSplitGetMemo(sp));
233 
234  runningBalance = gnc_numeric_add( runningBalance, split_value,
236 
237  if (gnc_numeric_positive_p(split_value))
238  {
239  tmpStr = xaccPrintAmount( split_value,
240  gnc_default_print_info(FALSE) );
241  gnc_ttsplitinfo_set_debit_formula( ttsi, tmpStr );
242  }
243  else
244  {
245  /* Negate the numeric so it prints w/o the sign at the front. */
246  tmpStr = xaccPrintAmount( gnc_numeric_neg( split_value ),
247  gnc_default_print_info(FALSE) );
248  gnc_ttsplitinfo_set_credit_formula( ttsi, tmpStr );
249  }
250 
251  /* Copy over per-split account info */
252  gnc_ttsplitinfo_set_account( ttsi, xaccSplitGetAccount( sp ) );
253 
254  template_splits = g_list_append(template_splits, ttsi);
255  }
256 
257  if ( ! gnc_numeric_zero_p( runningBalance )
258  && !gnc_verify_dialog( (GtkWidget *)sxfti->dialog,
259  FALSE, "%s",
260  _("The Scheduled Transaction Editor "
261  "cannot automatically balance "
262  "this transaction. "
263  "Should it still be "
264  "entered?") ) )
265  {
266  return SXFTD_ERRNO_UNBALANCED_XACTION;
267  }
268 
269  gnc_ttinfo_set_template_splits(tti, template_splits);
270 
271  tt_list = g_list_append(tt_list, tti);
272 
273  gnc_suspend_gui_refresh ();
274  xaccSchedXactionSetTemplateTrans(sxfti->sx, tt_list,
275  gnc_get_current_book ());
276  gnc_resume_gui_refresh ();
277 
278  return 0;
279 }
280 
281 
282 static void
283 sxftd_update_schedule( SXFromTransInfo *sxfti, GDate *date, GList **recurrences)
284 {
285  gint index;
286 
287  /* Note that we make the start date the *NEXT* instance, not the
288  * present one. */
289 
290  index = gtk_combo_box_get_active(GTK_COMBO_BOX(sxfti->freq_combo));
291 
292  switch (index)
293  {
294  case FREQ_DAILY:
295  {
296  Recurrence *r = g_new0(Recurrence, 1);
297  recurrenceSet(r, 1, PERIOD_DAY, date, WEEKEND_ADJ_NONE);
298  *recurrences = g_list_append(*recurrences, r);
299  }
300  break;
301 
302  case FREQ_WEEKLY:
303  case FREQ_BIWEEKLY:
304  {
305  Recurrence *r = g_new0(Recurrence, 1);
306  int mult = (index == FREQ_BIWEEKLY ? 2 : 1);
307  recurrenceSet(r, mult, PERIOD_WEEK, date, WEEKEND_ADJ_NONE);
308  *recurrences = g_list_append(*recurrences, r);
309  }
310  break;
311 
312  case FREQ_MONTHLY:
313  case FREQ_QUARTERLY:
314  case FREQ_ANNUALLY:
315  {
316  Recurrence *r = g_new0(Recurrence, 1);
317  int mult = (index == FREQ_MONTHLY
318  ? 1
319  : (index == FREQ_QUARTERLY
320  ? 3
321  : 12));
322  recurrenceSet(r, mult, PERIOD_MONTH, date, recurrenceGetWeekendAdjust(r));
323  *recurrences = g_list_append(*recurrences, r);
324  }
325  break;
326 
327  default:
328  g_critical("nonexistent frequency selected");
329  break;
330  }
331 }
332 
333 
334 static gint
335 sxftd_init( SXFromTransInfo *sxfti )
336 {
337  GtkWidget *w;
338  const char *transName;
339  gint pos;
340  GList *schedule = NULL;
341  time64 start_tt;
342  struct tm *tmpTm;
343  GDate date, nextDate;
344 
345  if ( ! sxfti->sx )
346  {
347  return -1;
348  }
349  if ( ! sxfti->trans )
350  {
351  return -2;
352  }
353  if ( xaccTransIsOpen( sxfti->trans ) )
354  {
355  return SXFTD_ERRNO_OPEN_XACTION;
356  }
357 
358  /* Setup Widgets */
359  {
360  sxfti->ne_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder, "never_end_button"));
361  sxfti->ed_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder, "end_on_date_button"));
362  sxfti->oc_but = GTK_TOGGLE_BUTTON(gtk_builder_get_object(sxfti->builder, "n_occurrences_button"));
363  sxfti->n_occurences = GTK_ENTRY(gtk_builder_get_object(sxfti->builder, "n_occurrences_entry"));
364  }
365 
366  /* Get the name from the transaction, try that as the initial SX name. */
367  transName = xaccTransGetDescription( sxfti->trans );
368  xaccSchedXactionSetName( sxfti->sx, transName );
369 
370  sxfti->name = GTK_ENTRY(gtk_builder_get_object(sxfti->builder, "name_entry" ));
371  pos = 0;
372  gtk_editable_insert_text( GTK_EDITABLE(sxfti->name), transName,
373  (strlen(transName) * sizeof(char)), &pos );
374 
375  sxfti_attach_callbacks(sxfti);
376 
377  /* Setup the example calendar and related data structures. */
378  {
379  int num_marks = SXFTD_EXCAL_NUM_MONTHS * 31;
380 
381  w = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, "ex_cal_frame" ));
382  sxfti->dense_cal_model = gnc_dense_cal_store_new(num_marks);
383  sxfti->example_cal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model(GNC_DENSE_CAL_MODEL(sxfti->dense_cal_model)));
384  g_object_ref_sink(sxfti->example_cal);
385 
386  g_assert(sxfti->example_cal);
387  gnc_dense_cal_set_num_months( sxfti->example_cal, SXFTD_EXCAL_NUM_MONTHS );
388  gnc_dense_cal_set_months_per_col( sxfti->example_cal, SXFTD_EXCAL_MONTHS_PER_COL );
389  gtk_container_add( GTK_CONTAINER(w), GTK_WIDGET(sxfti->example_cal) );
390  }
391 
392  /* Setup the start and end dates as GNCDateEdits */
393  {
394  GtkWidget *paramTable = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, "param_table" ));
395  sxfti->startDateGDE =
396  GNC_DATE_EDIT( gnc_date_edit_new (gnc_time (NULL),
397  FALSE, FALSE));
398  gtk_table_attach( GTK_TABLE(paramTable),
399  GTK_WIDGET( sxfti->startDateGDE ),
400  1, 2, 2, 3,
401  (GTK_EXPAND | GTK_FILL),
402  GTK_FILL,
403  0, 0 );
404  g_signal_connect( sxfti->startDateGDE, "date-changed",
405  G_CALLBACK( sxftd_update_excal_adapt ),
406  sxfti );
407  }
408  {
409  GtkWidget *endDateBox = GTK_WIDGET(gtk_builder_get_object(sxfti->builder, "end_date_hbox" ));
410  sxfti->endDateGDE =
411  GNC_DATE_EDIT( gnc_date_edit_new (gnc_time (NULL),
412  FALSE, FALSE));
413  gtk_box_pack_start( GTK_BOX( endDateBox ),
414  GTK_WIDGET( sxfti->endDateGDE ),
415  TRUE, TRUE, 0 );
416  g_signal_connect( sxfti->endDateGDE, "date-changed",
417  G_CALLBACK( sxftd_update_excal_adapt ),
418  sxfti );
419  }
420 
421  /* Setup the initial start date for user display/confirmation */
422  /* compute good initial date. */
423  start_tt = xaccTransGetDate( sxfti->trans );
424  gnc_gdate_set_time64( &date, start_tt );
425  sxfti->freq_combo = GTK_COMBO_BOX(gtk_builder_get_object(sxfti->builder, "freq_combo_box"));
426  gtk_combo_box_set_active(GTK_COMBO_BOX(sxfti->freq_combo), 0);
427  g_signal_connect( sxfti->freq_combo, "changed",
428  G_CALLBACK(sxftd_freq_combo_changed),
429  sxfti );
430  sxftd_update_schedule( sxfti, &date, &schedule);
431  recurrenceListNextInstance(schedule, &date, &nextDate);
432  recurrenceListFree(&schedule);
433  start_tt = gnc_time64_get_day_start_gdate (&nextDate);
434  gnc_date_edit_set_time( sxfti->startDateGDE, start_tt );
435 
436  g_signal_connect( GTK_OBJECT(sxfti->name), "destroy",
437  G_CALLBACK(sxftd_destroy),
438  sxfti );
439 
440  sxftd_update_example_cal( sxfti );
441 
442  return 0;
443 }
444 
445 
446 static guint
447 sxftd_compute_sx(SXFromTransInfo *sxfti)
448 {
449  gchar *name;
450  GDate date;
451  GList *schedule = NULL;
452  getEndTuple end_info;
453  guint sxftd_errno = 0; /* 0 == OK, > 0 means dialog needs to be run again */
454 
455  SchedXaction *sx = sxfti->sx;
456 
457  /* get the name */
458  name = gtk_editable_get_chars(GTK_EDITABLE(sxfti->name), 0, -1);
459 
460  xaccSchedXactionSetName(sx, name);
461  g_free(name);
462 
463  gnc_gdate_set_time64( &date, gnc_date_edit_get_date( sxfti->startDateGDE ) );
464 
465  sxftd_update_schedule(sxfti, &date, &schedule);
466  if (sxftd_errno == 0)
467  {
468  gnc_sx_set_schedule(sx, schedule);
469  xaccSchedXactionSetStartDate( sx, &date );
470  }
471 
472  end_info = sxftd_get_end_info(sxfti);
473 
474  switch (end_info.type)
475  {
476  case NEVER_END:
477  break;
478 
479  case END_ON_DATE:
480  xaccSchedXactionSetEndDate(sx, &(end_info.end_date));
481  break;
482 
483  case END_AFTER_N_OCCS:
484  xaccSchedXactionSetNumOccur(sx, end_info.n_occurrences);
485  break;
486 
487  default:
488  sxftd_errno = 2;
489  break;
490  }
491 
492  gnc_sx_set_instance_count( sx, 1 );
493 
494  /* Set the autocreate, days-in-advance and remind-in-advance values from
495  * options. */
496  {
497  gboolean autoCreateState, notifyState;
498  gint daysInAdvance;
499 
500  autoCreateState =
501  gnc_prefs_get_bool (GNC_PREFS_GROUP_SXED, GNC_PREF_CREATE_AUTO);
502  notifyState =
503  gnc_prefs_get_bool (GNC_PREFS_GROUP_SXED, GNC_PREF_NOTIFY);
504  xaccSchedXactionSetAutoCreate( sx,
505  autoCreateState,
506  (autoCreateState & notifyState) );
507 
508  daysInAdvance =
509  gnc_prefs_get_float (GNC_PREFS_GROUP_SXED, GNC_PREF_CREATE_DAYS);
510  xaccSchedXactionSetAdvanceCreation( sx, daysInAdvance );
511 
512  daysInAdvance =
513  gnc_prefs_get_float (GNC_PREFS_GROUP_SXED, GNC_PREF_REMIND_DAYS);
514  xaccSchedXactionSetAdvanceReminder( sx, daysInAdvance );
515  }
516 
517  if ( sxftd_add_template_trans( sxfti ) != 0 )
518  {
519  sxftd_errno = SXFTD_ERRNO_UNBALANCED_XACTION;
520  }
521 
522  return sxftd_errno;
523 }
524 
525 
526 static void
527 sxftd_close(SXFromTransInfo *sxfti, gboolean delete_sx)
528 {
529  if ( sxfti->sx && delete_sx )
530  {
531  gnc_sx_begin_edit(sxfti->sx);
532  xaccSchedXactionDestroy(sxfti->sx);
533  }
534  sxfti->sx = NULL;
535 
536  gtk_widget_destroy (GTK_WIDGET (sxfti->dialog));
537 }
538 
539 
540 static void
541 sxftd_ok_clicked(SXFromTransInfo *sxfti)
542 {
543  QofBook *book;
544  SchedXactions *sxes;
545  guint sx_error = sxftd_compute_sx(sxfti);
546 
547  if (sx_error != 0
548  && sx_error != SXFTD_ERRNO_UNBALANCED_XACTION)
549  {
550  g_critical("sxftd_compute_sx after ok_clicked [%d]", sx_error);
551  }
552  else
553  {
554  if ( sx_error == SXFTD_ERRNO_UNBALANCED_XACTION )
555  {
556  gnc_error_dialog( gnc_ui_get_toplevel(), "%s",
557  _( "The Scheduled Transaction is unbalanced. "
558  "You are strongly encouraged to correct this situation." ) );
559  }
560  book = gnc_get_current_book ();
561  sxes = gnc_book_get_schedxactions(book);
562  gnc_sxes_add_sx(sxes, sxfti->sx);
563  }
564 
565  sxftd_close(sxfti, FALSE);
566  return;
567 }
568 
569 
575 static void
576 sxftd_freq_combo_changed( GtkWidget *w, gpointer user_data )
577 {
578  SXFromTransInfo *sxfti = (SXFromTransInfo*)user_data;
579  GDate date, nextDate;
580  time64 tmp_tt;
581  struct tm *tmpTm;
582  GList *schedule = NULL;
583 
584  tmp_tt = xaccTransGetDate( sxfti->trans );
585  gnc_gdate_set_time64 (&date, tmp_tt);
586 
587  g_date_clear(&nextDate, 1);
588  sxftd_update_schedule(sxfti, &date, &schedule);
589  recurrenceListNextInstance(schedule, &date, &nextDate);
590  tmp_tt = gnc_time64_get_day_start_gdate (&nextDate);
591  gnc_date_edit_set_time( sxfti->startDateGDE, tmp_tt );
592 
593  recurrenceListFree(&schedule);
594  sxftd_update_example_cal( sxfti );
595 }
596 
597 
598 static void
599 sxftd_advanced_clicked(SXFromTransInfo *sxfti)
600 {
601  guint sx_error = sxftd_compute_sx(sxfti);
602  GMainContext *context;
603 
604  if ( sx_error != 0 && sx_error != SXFTD_ERRNO_UNBALANCED_XACTION )
605  {
606  // unbalanced-xaction is "okay", since this is also checked for by
607  // the advanced editor.
608  g_warning("something bad happened in sxftd_compute_sx [%d]", sx_error);
609  return;
610  }
611  gtk_widget_hide( sxfti->dialog );
612  /* force a gui update. */
613  context = g_main_context_default();
614  while (g_main_context_iteration(context, FALSE));
615 
616  gnc_ui_scheduled_xaction_editor_dialog_create(sxfti->sx, TRUE /* newSX */);
617  /* close ourself, since advanced editing entails us, and there are sync
618  * issues otherwise. */
619  sxftd_close(sxfti, FALSE);
620 }
621 
622 
623 static void
624 sxftd_destroy( GtkWidget *w, gpointer user_data )
625 {
626  SXFromTransInfo *sxfti = (SXFromTransInfo*)user_data;
627 
628  if ( sxfti->sx )
629  {
630  gnc_sx_begin_edit(sxfti->sx);
631  xaccSchedXactionDestroy(sxfti->sx);
632  sxfti->sx = NULL;
633  }
634 
635  g_object_unref(G_OBJECT(sxfti->dense_cal_model));
636  g_object_unref(G_OBJECT(sxfti->example_cal));
637 
638  g_free(sxfti);
639 }
640 
641 
642 static void
643 gnc_sx_trans_window_response_cb (GtkDialog *dialog,
644  gint response,
645  gpointer data)
646 {
647  SXFromTransInfo *sxfti = (SXFromTransInfo *)data;
648 
649  ENTER(" dialog %p, response %d, sx %p", dialog, response, sxfti);
650  switch (response)
651  {
652  case GTK_RESPONSE_OK:
653  g_debug(" OK");
654  sxftd_ok_clicked(sxfti);
655  break;
656  case SXFTD_RESPONSE_ADVANCED:
657  g_debug(" ADVANCED");
658  sxftd_advanced_clicked(sxfti);
659  break;
660  case GTK_RESPONSE_CANCEL:
661  default:
662  g_debug(" CANCEL");
663  sxftd_close(sxfti, TRUE);
664  break;
665 
666  }
667  LEAVE(" ");
668 }
669 
670 
675 static void
676 sxftd_update_example_cal( SXFromTransInfo *sxfti )
677 {
678  struct tm *tmpTm;
679  time64 tmp_tt;
680  GDate date, startDate, nextDate;
681  GList *schedule = NULL;
682  getEndTuple get;
683 
684  get = sxftd_get_end_info( sxfti );
685 
686  tmp_tt = gnc_date_edit_get_date( sxfti->startDateGDE );
687  gnc_gdate_set_time64 (&date, tmp_tt);
688 
689  sxftd_update_schedule(sxfti, &date, &schedule);
690 
691  /* go one day before what's in the box so we can get the correct start
692  * date. */
693  startDate = date;
694  g_date_subtract_days(&date, 1);
695  g_date_clear(&nextDate, 1);
696  recurrenceListNextInstance(schedule, &date, &nextDate);
697 
698  {
699  gchar *name;
700  /* get the name */
701  name = NULL;
702  name = gtk_editable_get_chars(GTK_EDITABLE(sxfti->name), 0, -1);
703  gnc_dense_cal_store_update_name(sxfti->dense_cal_model, name);
704  g_free(name);
705  }
706 
707  {
708  gchar *schedule_desc;
709  schedule_desc = recurrenceListToCompactString(schedule);
710  gnc_dense_cal_store_update_info(sxfti->dense_cal_model, schedule_desc);
711  g_free(schedule_desc);
712  }
713 
714  /* Set End date sensitivity */
715  gtk_widget_set_sensitive( GTK_WIDGET(sxfti->endDateGDE), (get.type == END_ON_DATE) );
716  gtk_widget_set_sensitive( GTK_WIDGET(sxfti->n_occurences), (get.type == END_AFTER_N_OCCS) );
717 
718  switch (get.type)
719  {
720  case NEVER_END:
721  gnc_dense_cal_store_update_recurrences_no_end(sxfti->dense_cal_model, &startDate, schedule);
722  break;
723  case END_ON_DATE:
724  gnc_dense_cal_store_update_recurrences_date_end(sxfti->dense_cal_model, &startDate, schedule, &get.end_date);
725  break;
726  case END_AFTER_N_OCCS:
727  gnc_dense_cal_store_update_recurrences_count_end(sxfti->dense_cal_model, &startDate, schedule, get.n_occurrences);
728  break;
729  default:
730  g_warning("unknown get.type [%d]\n", get.type);
731  break;
732  }
733 
734  gnc_dense_cal_set_month( sxfti->example_cal, g_date_get_month( &startDate ) );
735  gnc_dense_cal_set_year( sxfti->example_cal, g_date_get_year( &startDate ) );
736 
737  recurrenceListFree(&schedule);
738 }
739 
740 
741 /***********************************
742  * Callback to update the calendar *
743  **********************************/
744 static void
745 sxftd_update_excal_adapt( GObject *o, gpointer ud )
746 {
747  SXFromTransInfo *sxfti = (SXFromTransInfo*)ud;
748  sxftd_update_example_cal( sxfti );
749 }
750 
751 
752 /*********************
753  * Create the dialog *
754  ********************/
755 void
756 gnc_sx_create_from_trans( Transaction *trans )
757 {
758  int errno;
759  SXFromTransInfo *sxfti = g_new0( SXFromTransInfo, 1);
760  GtkBuilder *builder;
761  GtkWidget *dialog;
762 
763  builder = gtk_builder_new();
764 
765  gnc_builder_add_from_file (builder , "dialog-sx.glade", "freq_liststore");
766 
767  gnc_builder_add_from_file (builder , "dialog-sx.glade", "sx_from_real_trans");
768  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "sx_from_real_trans"));
769 
770  sxfti->builder = builder;
771  sxfti->dialog = dialog;
772  sxfti->trans = trans;
773 
774  sxfti->sx = xaccSchedXactionMalloc(gnc_get_current_book ());
775 
776  if ( (errno = sxftd_init( sxfti )) < 0 )
777  {
778  if ( errno == SXFTD_ERRNO_OPEN_XACTION )
779  {
780  gnc_error_dialog( gnc_ui_get_toplevel(), "%s",
781  _( "Cannot create a Scheduled Transaction "
782  "from a Transaction currently "
783  "being edited. Please Enter the "
784  "Transaction before Scheduling." ) );
785  sxftd_close( sxfti, TRUE );
786  return;
787  }
788  else
789  {
790  g_error("sxftd_init: %d", errno);
791  }
792  }
793 
794  gtk_widget_show_all(GTK_WIDGET(sxfti->dialog));
795 
796  gtk_builder_connect_signals(builder, sxfti);
797  g_object_unref(G_OBJECT(builder));
798 }
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
Definition: SchedXaction.c:565
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
time64 xaccTransGetDate(const Transaction *trans)
Definition: Transaction.c:2215
gboolean xaccTransIsOpen(const Transaction *trans)
Definition: Transaction.c:1819
utility functions for the GnuCash UI
void xaccSchedXactionSetNumOccur(SchedXaction *sx, gint new_num)
Definition: SchedXaction.c:690
gnc_numeric gnc_numeric_neg(gnc_numeric a)
time64 gnc_time64_get_day_start_gdate(const GDate *date)
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gboolean gnc_numeric_zero_p(gnc_numeric a)
#define ENTER(format, args...)
Definition: qoflog.h:261
Anchor Scheduled Transaction info in a book. See src/doc/books.txt for design overview.
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2184
void xaccSchedXactionSetTemplateTrans(SchedXaction *sx, GList *t_t_list, QofBook *book)
Set the schedxaction's template transaction.
All type declarations for the whole Gnucash engine.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Generic api to store and retrieve preferences.
void xaccSchedXactionSetName(SchedXaction *sx, const gchar *newName)
Definition: SchedXaction.c:581
GDate helper routines.
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1348
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
#define LEAVE(format, args...)
Definition: qoflog.h:271
time64 gnc_time(time64 *tbuf)
get the current local time
GtkWidget * gnc_ui_get_toplevel(void)
const char * xaccSplitGetMemo(const Split *split)
Definition: Split.c:1968
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
Definition: SchedXaction.c:404
gint64 time64
Definition: gnc-date.h:83
Scheduled Transactions public handling routines.
void xaccSchedXactionSetEndDate(SchedXaction *sx, const GDate *newEnd)
Definition: SchedXaction.c:635
#define GNC_DENOM_AUTO
Definition: gnc-numeric.h:246
void xaccSchedXactionDestroy(SchedXaction *sx)
Definition: SchedXaction.c:473
SplitList * xaccTransGetSplitList(const Transaction *trans)
Definition: Transaction.c:2164
const gchar * QofLogModule
Definition: qofid.h:89
void gnc_gdate_set_time64(GDate *gd, time64 time)
gdouble gnc_prefs_get_float(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:227