1 /* ************************************************************************** */
2 /* */
3 /* */
4 /* Copyright (C) 2000-2008 Cédric Auger (cedric@grisbi.org) */
5 /* https://www.grisbi.org/ */
6 /* */
7 /* This program is free software; you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation; either version 2 of the License, or */
10 /* (at your option) any later version. */
11 /* */
12 /* This program is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
15 /* GNU General Public License for more details. */
16 /* */
17 /* You should have received a copy of the GNU General Public License */
18 /* along with this program; if not, write to the Free Software */
19 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
20 /* */
21 /* ************************************************************************** */
22
23 /**
24 * \file gsb_data_fyear_data.c
25 * work with the fyear structure, no GUI here
26 */
27
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "include.h"
34 #include <glib/gi18n.h>
35
36 /*START_INCLUDE*/
37 #include "gsb_data_fyear.h"
38 #include "dialog.h"
39 #include "gsb_fyear.h"
40 #include "structures.h"
41 #include "utils_dates.h"
42 #include "utils_str.h"
43 /*END_INCLUDE*/
44
45
46 /**
47 * describe the invalid numbers
48 * */
49 enum fyear_invalid {
50 FYEAR_INVALID_DATE_ORDER = 1,
51 FYEAR_INVALID_CROSS,
52 FYEAR_INVALID_DATE
53 };
54
55 /*START_STATIC*/
56 static void _gsb_data_fyear_free ( FyearStruct *fyear );
57 static gpointer gsb_data_fyear_get_structure ( gint fyear_number );
58 static gint gsb_data_fyear_max_number ( void );
59 /*END_STATIC*/
60
61 /*START_EXTERN*/
62 /*END_EXTERN*/
63
64 /** contains the g_slist of FyearStruct */
65 static GSList *fyear_list = NULL;
66
67 /** a pointer to the last fyear used (to increase the speed) */
68 static FyearStruct *fyear_buffer;
69
70
71 /**
72 * set the fyears global variables to NULL,
73 * usually when we init all the global variables
74 *
75 * \param
76 *
77 * \return FALSE
78 * */
gsb_data_fyear_init_variables(void)79 gboolean gsb_data_fyear_init_variables ( void )
80 {
81 if ( fyear_list )
82 {
83 GSList* tmp_list = fyear_list;
84 while ( tmp_list )
85 {
86 FyearStruct *fyear;
87 fyear = tmp_list -> data;
88 tmp_list = tmp_list -> next;
89 _gsb_data_fyear_free ( fyear );
90 }
91 g_slist_free ( fyear_list );
92 }
93 fyear_list = NULL;
94 fyear_buffer = NULL;
95 return FALSE;
96 }
97
98
99 /**
100 * find and return the structure of the fyear asked
101 *
102 * \param fyear_number number of fyear
103 *
104 * \return the adr of the struct of the fyear (NULL if doesn't exit)
105 * */
gsb_data_fyear_get_structure(gint fyear_number)106 gpointer gsb_data_fyear_get_structure ( gint fyear_number )
107 {
108 GSList *tmp;
109
110 if (!fyear_number)
111 return NULL;
112
113 /* before checking all the fyears, we check the buffer */
114
115 if ( fyear_buffer
116 &&
117 fyear_buffer -> fyear_number == fyear_number )
118 return fyear_buffer;
119
120 tmp = fyear_list;
121
122 while ( tmp )
123 {
124 FyearStruct *fyear;
125
126 fyear = tmp -> data;
127
128 if ( fyear -> fyear_number == fyear_number )
129 {
130 fyear_buffer = fyear;
131 return fyear;
132 }
133
134 tmp = tmp -> next;
135 }
136 return NULL;
137 }
138
139
140 /**
141 * give the g_slist of fyears structure
142 * usefull when want to check all fyears
143 *
144 * \param none
145 *
146 * \return the g_slist of fyears structure
147 * */
gsb_data_fyear_get_fyears_list(void)148 GSList *gsb_data_fyear_get_fyears_list ( void )
149 {
150 return fyear_list;
151 }
152
153 /**
154 * return the number of the fyears given in param
155 *
156 * \param fyear_ptr a pointer to the struct of the fyear
157 *
158 * \return the number of the fyear, 0 if problem
159 * */
gsb_data_fyear_get_no_fyear(gpointer fyear_ptr)160 gint gsb_data_fyear_get_no_fyear ( gpointer fyear_ptr )
161 {
162 FyearStruct *fyear;
163
164 if ( !fyear_ptr )
165 return 0;
166
167 fyear = fyear_ptr;
168 fyear_buffer = fyear;
169 return fyear -> fyear_number;
170 }
171
172
173 /**
174 * find and return the last number of fyear
175 *
176 * \param none
177 *
178 * \return last number of fyear
179 * */
gsb_data_fyear_max_number(void)180 gint gsb_data_fyear_max_number ( void )
181 {
182 GSList *tmp;
183 gint number_tmp = 0;
184
185 tmp = fyear_list;
186
187 while ( tmp )
188 {
189 FyearStruct *fyear;
190
191 fyear = tmp -> data;
192
193 if ( fyear -> fyear_number > number_tmp )
194 number_tmp = fyear -> fyear_number;
195
196 tmp = tmp -> next;
197 }
198 return number_tmp;
199 }
200
201
202 /**
203 * create a new fyear, give him a number, append it to the list
204 * and return the number
205 *
206 * \param name the name of the fyear (can be freed after, it's a copy) or NULL
207 *
208 * \return the number of the new fyear
209 * */
gsb_data_fyear_new(const gchar * name)210 gint gsb_data_fyear_new ( const gchar *name )
211 {
212 FyearStruct *fyear;
213
214 fyear = g_malloc0 ( sizeof ( FyearStruct ));
215 fyear -> fyear_number = gsb_data_fyear_max_number () + 1;
216
217 if (name)
218 fyear -> fyear_name = my_strdup (name);
219 else
220 fyear -> fyear_name = NULL;
221
222 fyear_list = g_slist_append ( fyear_list, fyear );
223 fyear_buffer = fyear;
224
225 return fyear -> fyear_number;
226 }
227
228
229 /**
230 * This internal function is called to free the memory used by a FyearStruct structure
231 */
_gsb_data_fyear_free(FyearStruct * fyear)232 static void _gsb_data_fyear_free ( FyearStruct *fyear )
233 {
234 if ( ! fyear )
235 return;
236 if ( fyear -> fyear_name )
237 g_free ( fyear -> fyear_name );
238 if ( fyear -> beginning_date )
239 g_date_free ( fyear -> beginning_date );
240 if ( fyear -> end_date )
241 g_date_free ( fyear -> end_date );
242 g_free ( fyear );
243 if ( fyear_buffer == fyear )
244 fyear_buffer = NULL;
245 }
246
247 /**
248 * remove a fyear
249 * set all the fyears of transaction which are this one to 0
250 *
251 * \param fyear_number the fyear we want to remove
252 *
253 * \return TRUE ok
254 * */
gsb_data_fyear_remove(gint fyear_number)255 gboolean gsb_data_fyear_remove ( gint fyear_number )
256 {
257 FyearStruct *fyear;
258
259 fyear = gsb_data_fyear_get_structure ( fyear_number );
260
261 if (!fyear)
262 return FALSE;
263
264 fyear_list = g_slist_remove ( fyear_list,
265 fyear );
266
267 _gsb_data_fyear_free ( fyear );
268
269 return TRUE;
270 }
271
272
273 /**
274 * set a new number for the fyear
275 * normally used only while loading the file because
276 * the number are given automaticly
277 *
278 * \param fyear_number the number of the fyear
279 * \param new_no_fyear the new number of the fyear
280 *
281 * \return the new number or 0 if the fyear doen't exist
282 * */
gsb_data_fyear_set_new_number(gint fyear_number,gint new_no_fyear)283 gint gsb_data_fyear_set_new_number ( gint fyear_number,
284 gint new_no_fyear )
285 {
286 FyearStruct *fyear;
287
288 fyear = gsb_data_fyear_get_structure ( fyear_number );
289
290 if (!fyear)
291 return 0;
292
293 fyear -> fyear_number = new_no_fyear;
294 return new_no_fyear;
295 }
296
297
298 /**
299 * return the name of the fyear
300 *
301 * \param fyear_number the number of the fyear
302 *
303 * \return the name of the fyear or NULL if fail
304 * */
gsb_data_fyear_get_name(gint fyear_number)305 const gchar *gsb_data_fyear_get_name ( gint fyear_number )
306 {
307 FyearStruct *fyear;
308
309 fyear = gsb_data_fyear_get_structure ( fyear_number );
310
311 if (!fyear)
312 return NULL;
313
314 return fyear -> fyear_name;
315 }
316
317
318 /**
319 * set the name of the fyear
320 * the value is dupplicate in memory
321 *
322 * \param fyear_number the number of the fyear
323 * \param name the name of the fyear
324 *
325 * \return TRUE if ok or FALSE if problem
326 * */
gsb_data_fyear_set_name(gint fyear_number,const gchar * name)327 gboolean gsb_data_fyear_set_name ( gint fyear_number,
328 const gchar *name )
329 {
330 FyearStruct *fyear;
331
332 fyear = gsb_data_fyear_get_structure ( fyear_number );
333
334 if (!fyear)
335 return FALSE;
336
337 /* we free the last name */
338 if ( fyear -> fyear_name )
339 g_free (fyear -> fyear_name);
340
341 /* and copy the new one */
342 fyear -> fyear_name = my_strdup (name);
343
344 /* update list fyear in form */
345 if (fyear -> showed_in_form)
346 gsb_fyear_update_fyear_list ();
347
348 return TRUE;
349 }
350
351
352
353 /**
354 * return the beginning date of the fyear
355 *
356 * \param fyear_number the number of the fyear
357 *
358 * \return the beginning date of the fyear or NULL if fail
359 * */
gsb_data_fyear_get_beginning_date(gint fyear_number)360 GDate *gsb_data_fyear_get_beginning_date ( gint fyear_number )
361 {
362 FyearStruct *fyear;
363
364 fyear = gsb_data_fyear_get_structure ( fyear_number );
365
366 if (!fyear)
367 return NULL;
368
369 return fyear -> beginning_date;
370 }
371
372
373 /**
374 * set the beginning date of the fyear
375 * the value is dupplicate in memory
376 *
377 * \param fyear_number the number of the fyear
378 * \param date the beginning date of the fyear
379 *
380 * \return TRUE if ok or FALSE if problem
381 * */
gsb_data_fyear_set_beginning_date(gint fyear_number,GDate * date)382 gboolean gsb_data_fyear_set_beginning_date ( gint fyear_number,
383 GDate *date )
384 {
385 FyearStruct *fyear;
386
387 fyear = gsb_data_fyear_get_structure ( fyear_number );
388
389 if (!fyear)
390 return FALSE;
391
392 /* we free the last date */
393 if ( fyear -> beginning_date )
394 g_date_free (fyear -> beginning_date);
395
396 /* and copy the new one */
397 fyear -> beginning_date = gsb_date_copy (date);
398
399 return TRUE;
400 }
401
402
403 /**
404 * return the end date of the fyear
405 *
406 * \param fyear_number the number of the fyear
407 *
408 * \return the end date of the fyear or NULL if fail
409 * */
gsb_data_fyear_get_end_date(gint fyear_number)410 GDate *gsb_data_fyear_get_end_date ( gint fyear_number )
411 {
412 FyearStruct *fyear;
413
414 fyear = gsb_data_fyear_get_structure ( fyear_number );
415
416 if (!fyear)
417 return NULL;
418
419 return fyear -> end_date;
420 }
421
422
423 /**
424 * set the end date of the fyear
425 * the value is dupplicate in memory
426 *
427 * \param fyear_number the number of the fyear
428 * \param date the end date of the fyear
429 *
430 * \return TRUE if ok or FALSE if problem
431 * */
gsb_data_fyear_set_end_date(gint fyear_number,GDate * date)432 gboolean gsb_data_fyear_set_end_date ( gint fyear_number,
433 GDate *date )
434 {
435 FyearStruct *fyear;
436
437 fyear = gsb_data_fyear_get_structure ( fyear_number );
438
439 if (!fyear)
440 return FALSE;
441
442 /* we free the last date */
443 if ( fyear -> end_date )
444 g_date_free (fyear -> end_date);
445
446 /* and copy the new one */
447 fyear -> end_date = gsb_date_copy (date);
448
449 return TRUE;
450 }
451
452
453
454 /**
455 * return the showed_in_form of the fyear
456 *
457 * \param fyear_number the number of the fyear
458 *
459 * \return the showed_in_form of the fyear or NULL if fail
460 * */
gsb_data_fyear_get_form_show(gint fyear_number)461 gboolean gsb_data_fyear_get_form_show ( gint fyear_number )
462 {
463 FyearStruct *fyear;
464
465 fyear = gsb_data_fyear_get_structure ( fyear_number );
466
467 if (!fyear)
468 return FALSE;
469
470 return fyear -> showed_in_form;
471 }
472
473
474 /**
475 * set the showed_in_form of the fyear
476 *
477 * \param fyear_number the number of the fyear
478 * \param showed_in_form the showed_in_form of the fyear
479 *
480 * \return TRUE if ok or FALSE if problem
481 * */
gsb_data_fyear_set_form_show(gint fyear_number,gboolean showed_in_form)482 gboolean gsb_data_fyear_set_form_show ( gint fyear_number,
483 gboolean showed_in_form )
484 {
485 FyearStruct *fyear;
486
487 fyear = gsb_data_fyear_get_structure ( fyear_number );
488
489 if (!fyear)
490 return FALSE;
491
492 /* and copy the new one */
493 fyear -> showed_in_form = showed_in_form;
494
495 /* update list fyear in form */
496 gsb_fyear_update_fyear_list ();
497
498 return TRUE;
499 }
500
501
502 /**
503 * return the invalid_fyear of the fyear
504 * the flag invalid is set automatickly by gsb_data_fyear_check_for_invalid
505 *
506 * \param fyear_number the number of the fyear
507 *
508 * \return TRUE if the fyear is invalid
509 * */
gsb_data_fyear_get_invalid(gint fyear_number)510 gint gsb_data_fyear_get_invalid ( gint fyear_number )
511 {
512 FyearStruct *fyear;
513
514 fyear = gsb_data_fyear_get_structure ( fyear_number );
515
516 if (!fyear)
517 return FALSE;
518
519 return fyear -> invalid_fyear;
520 }
521
522 /**
523 * return the message error because of the invalid fyear
524 *
525 * \param fyear_number the number of the fyear
526 *
527 * \return a const gchar formatted with markup : error the message or NULL if not exist
528 * */
gsb_data_fyear_get_invalid_message(gint fyear_number)529 const gchar *gsb_data_fyear_get_invalid_message ( gint fyear_number )
530 {
531 FyearStruct *fyear;
532 gchar *string = NULL;
533
534 fyear = gsb_data_fyear_get_structure ( fyear_number );
535
536 if ( !fyear || !fyear -> invalid_fyear )
537 return NULL;
538
539 switch ( fyear -> invalid_fyear )
540 {
541 case FYEAR_INVALID_DATE_ORDER:
542 string = dialogue_make_red ( _("Warning : the dates are not in good order.") );
543 break;
544 case FYEAR_INVALID_CROSS:
545 string = dialogue_make_red ( _("Warning : that financial year cross with another one.") );
546 break;
547 case FYEAR_INVALID_DATE:
548 string = dialogue_make_red ( _("Warning : Invalid date.") );
549 break;
550 }
551
552 return string;
553 }
554
555 /**
556 * check all the fyear if the are invalid and set their flag
557 * normaly called to each change of a fyear
558 * an invalid fyear will not be used by grisbi and showed as invalid in the configuration
559 *
560 * \param fyear_number the number of the fyear to check
561 *
562 * \return TRUE if invalid, FALSE if not
563 * */
gsb_data_fyear_check_all_for_invalid(void)564 void gsb_data_fyear_check_all_for_invalid ( void )
565 {
566 GSList *tmp_list;
567
568 tmp_list = fyear_list;
569
570 while (tmp_list)
571 {
572 fyear_buffer = tmp_list -> data;
573 gsb_data_fyear_check_for_invalid ( fyear_buffer -> fyear_number);
574
575 tmp_list = tmp_list -> next;
576 }
577 }
578
579
580 /**
581 * check if the fyear is invalid and set the flag
582 * a fyear is invalid
583 * an invalid fyear will not be used by grisbi and showed as invalid in the configuration
584 *
585 * \param fyear_number the number of the fyear to check
586 *
587 * \return TRUE if invalid, FALSE if not
588 * */
gsb_data_fyear_check_for_invalid(gint fyear_number)589 gboolean gsb_data_fyear_check_for_invalid ( gint fyear_number )
590 {
591 FyearStruct *fyear;
592
593 fyear = gsb_data_fyear_get_structure ( fyear_number );
594
595 if (!fyear)
596 return FALSE;
597
598 /* check if there is some good date */
599 if (!fyear -> beginning_date
600 ||
601 !fyear -> end_date)
602 {
603 fyear -> invalid_fyear = FYEAR_INVALID_DATE;
604 return TRUE;
605 }
606
607 /* first : we check that the first date is above the second */
608 if ( g_date_compare (fyear -> beginning_date,
609 fyear -> end_date) > 0)
610 {
611 fyear -> invalid_fyear = FYEAR_INVALID_DATE_ORDER;
612 return TRUE;
613 }
614
615 /* second : we check if there is not a cross with another fyear */
616 if ( (gsb_data_fyear_get_from_date (fyear -> beginning_date) != fyear_number)
617 ||
618 (gsb_data_fyear_get_from_date (fyear -> end_date) != fyear_number))
619 {
620 fyear -> invalid_fyear = FYEAR_INVALID_CROSS;
621 return TRUE;
622 }
623
624 /* it's ok, the fyear is valid */
625 fyear -> invalid_fyear = FALSE;
626
627 return FALSE;
628 }
629
630
631
632 /**
633 * get the financial year corresponding to the given date
634 * if there is more than 1 financial year corresponding to that date, return -1
635 *
636 * \param date
637 *
638 * \return the number of financial year, 0 if none on that date, -1 if more than 1 on that date
639 * */
gsb_data_fyear_get_from_date(const GDate * date)640 gint gsb_data_fyear_get_from_date ( const GDate *date )
641 {
642 GSList *tmp_list;
643 gint return_value = 0;
644
645 if (!date)
646 return 0;
647
648 tmp_list = fyear_list;
649 while (tmp_list)
650 {
651 FyearStruct *fyear;
652
653 fyear = tmp_list -> data;
654
655 /* check the fyear only if the dates are valid */
656 if (fyear -> beginning_date && fyear -> end_date)
657 {
658 if ( g_date_compare ( date, fyear -> beginning_date) >= 0
659 &&
660 g_date_compare ( date, fyear -> end_date) <= 0 )
661 {
662 if (return_value)
663 return_value = -1;
664 else
665 return_value = fyear -> fyear_number;
666 }
667 }
668 tmp_list = tmp_list -> next;
669 }
670 return return_value;
671 }
672
673
674 /**
675 * compare 2 financial years
676 *
677 * \param fyear_number_1
678 * \param fyear_number_2
679 *
680 * \return -1 if fyear 1 is before 2 ; +1 if fyear 1 is after 2 ; 0 if problem
681 * */
gsb_data_fyear_compare(gint fyear_number_1,gint fyear_number_2)682 gint gsb_data_fyear_compare ( gint fyear_number_1, gint fyear_number_2 )
683 {
684 FyearStruct *fyear_1;
685 FyearStruct *fyear_2;
686
687 fyear_1 = gsb_data_fyear_get_structure (fyear_number_1);
688 fyear_2 = gsb_data_fyear_get_structure (fyear_number_2);
689
690 return gsb_data_fyear_compare_from_struct ( fyear_1, fyear_2, 0);
691
692 }
693
694
695 /**
696 * compare 2 financial years bye FyearStruct *fyear
697 *
698 * \param FyearStruct *fyear_1
699 * \param FyearStruct *fyear_2
700 *
701 * \return -1 if fyear 2 is before 1 ; +1 if fyear 2 is after 1 ; 0 if problem
702 * */
gsb_data_fyear_compare_from_struct(FyearStruct * fyear_1,FyearStruct * fyear_2,gpointer sort_order)703 gint gsb_data_fyear_compare_from_struct (FyearStruct *fyear_1,
704 FyearStruct *fyear_2,
705 gpointer sort_order)
706 {
707 gint fyear_combobox_sort_order;
708
709 fyear_combobox_sort_order = GPOINTER_TO_INT (sort_order);
710
711 if ( !fyear_1 || !fyear_2 )
712 {
713 return 0;
714 }
715
716 if (fyear_combobox_sort_order)
717 {
718 if ( !fyear_1 -> beginning_date )
719 return 1;
720 if ( !fyear_2 -> beginning_date )
721 return 1;
722
723 if ( g_date_compare ( fyear_1 -> end_date, fyear_2 -> beginning_date ) < 0 )
724 return 1;
725 if ( g_date_compare ( fyear_1 -> beginning_date, fyear_2 -> end_date ) > 0 )
726 return -1;
727 return 0;
728 }
729 else
730 {
731 if ( !fyear_1 -> beginning_date )
732 return -1;
733 if ( !fyear_2 -> beginning_date )
734 return -1;
735
736 if ( g_date_compare ( fyear_1 -> end_date, fyear_2 -> beginning_date ) < 0 )
737 return -1;
738 if ( g_date_compare ( fyear_1 -> beginning_date, fyear_2 -> end_date ) > 0 )
739 return 1;
740 return 0;
741 }
742 }
743
744
745 /**
746 * retourne l'exercice précédent l'exercice passé en paramètre
747 *
748 * \param fyear_number
749 *
750 * \return previous_fyear_number ou 0 si pas d'exercice precedent
751 * */
gsb_data_fyear_get_previous_financial_year(const gint fyear_number)752 gint gsb_data_fyear_get_previous_financial_year ( const gint fyear_number )
753 {
754 gint previous_fyear_number = 0;
755 GSList *tmp_list;
756
757 tmp_list = fyear_list;
758
759 while ( tmp_list )
760 {
761 gint tmp_fyear_number;
762
763 tmp_fyear_number = gsb_data_fyear_get_no_fyear ( tmp_list -> data );
764
765 if ( gsb_data_fyear_compare ( fyear_number, tmp_fyear_number ) == 1)
766 {
767 if ( previous_fyear_number )
768 {
769 if ( gsb_data_fyear_compare ( previous_fyear_number, tmp_fyear_number ) == -1)
770 previous_fyear_number = tmp_fyear_number;
771 }
772 else
773 {
774 previous_fyear_number = tmp_fyear_number;
775 }
776 }
777 tmp_list = tmp_list -> next;
778 }
779
780 return previous_fyear_number;
781 }
782
783
784 /**
785 *
786 *
787 * \param
788 *
789 * \return
790 * */
791 /* Local Variables: */
792 /* c-basic-offset: 4 */
793 /* End: */
794