GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-period-select.c
Go to the documentation of this file.
1/*
2 * gnc-period-select.c -- Accounting Period selection widget
3 *
4 * Copyright (c) 2005 David Hampton <hampton@employees.org>
5 * All rights reserved.
6 *
7 * Gnucash is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public License
9 * as published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * Gnucash 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 GNU
15 * Library 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, contact:
19 *
20 * Free Software Foundation Voice: +1-617-542-5942
21 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
22 * Boston, MA 02110-1301, USA gnu@gnu.org
23 */
24
32#include <config.h>
33
34#include <gtk/gtk.h>
35#include <glib/gi18n.h>
36
37#include "gnc-date.h"
38#include "gnc-period-select.h"
39#include "gnc-prefs.h"
40#include "dialog-utils.h"
41
42enum
43{
44 PROP_0,
45 PROP_FY_END,
46 PROP_SHOW_DATE,
47 PROP_DATE_BASE,
48 PROP_PS_ACTIVE,
49};
50
51enum
52{
53 CHANGED,
54 LAST_SIGNAL
55};
56
57static guint signals[LAST_SIGNAL] = { 0 };
58
60static void gnc_period_select_finalize (GObject *object);
61
62const gchar *start_strings[GNC_ACCOUNTING_PERIOD_LAST] =
63{
64 /* CY (current year) Strings */
65 N_("Today"),
66 N_("Start of this month"),
67 N_("Start of previous month"),
68 N_("Start of this quarter"),
69 N_("Start of previous quarter"),
70 N_("Start of this year"),
71 N_("Start of previous year"),
72
73 /* FY (fiscal year) Strings */
74 N_("Start of this accounting period"),
75 N_("Start of previous accounting period"),
76};
77
78const gchar *end_strings[GNC_ACCOUNTING_PERIOD_LAST] =
79{
80 /* CY (current year) Strings */
81 N_("Today"),
82 N_("End of this month"),
83 N_("End of previous month"),
84 N_("End of this quarter"),
85 N_("End of previous quarter"),
86 N_("End of this year"),
87 N_("End of previous year"),
88
89 /* FY (fiscal year) Strings */
90 N_("End of this accounting period"),
91 N_("End of previous accounting period"),
92};
93
94
98{
99 GtkBox hbox;
100
101 GtkWidget *selector;
102
103 gboolean start;
104 GDate *fy_end;
105
106 GDate *date_base;
107 GtkWidget *date_label;
108};
109
110G_DEFINE_TYPE(GncPeriodSelect, gnc_period_select, GTK_TYPE_BOX)
111
112
113/************************************************************/
114/* Signal Functions */
115/************************************************************/
116
117/* Tells a GncPeriodSelect object to emit a "changed" signal.
118 */
119static void
120gnc_period_select_changed (GncPeriodSelect *period)
121{
122 g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
123
124 g_signal_emit(G_OBJECT(period), signals[CHANGED], 0);
125}
126
127
133static void
134gnc_period_sample_update_date_label (GncPeriodSelect *period)
135{
136 gchar time_string[MAX_DATE_LENGTH + 1];
137 GDate *date;
139
140 g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
141 if (!period->date_label)
142 return;
143 which = gtk_combo_box_get_active (GTK_COMBO_BOX (period->selector));
144 if (which == -1)
145 date = g_date_new_dmy (31, 7, 2013);
146
147 else if (period->start)
148 date = gnc_accounting_period_start_gdate (which, period->fy_end,
149 period->date_base);
150 else
151 date = gnc_accounting_period_end_gdate (which, period->fy_end,
152 period->date_base);
153 qof_print_gdate (time_string, MAX_DATE_LENGTH, date);
154 gtk_label_set_label (GTK_LABEL(period->date_label), time_string);
155 g_date_free (date);
156}
157
158
168static void
169gnc_period_sample_combobox_changed (GtkComboBox *box, GncPeriodSelect *period)
170{
171 g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
172
173 g_object_set (G_OBJECT (period),
174 "active",
175 gtk_combo_box_get_active (box),
176 NULL);
177}
178
179
192static void
193gnc_period_sample_new_date_format (gpointer prefs, gchar *pref,
194 GncPeriodSelect *period)
195{
196 gnc_period_sample_update_date_label(period);
197}
198
199
200/************************************************************/
201/* Property Functions */
202/************************************************************/
203
204/* Set an item in the GncPeriodSelect to be the active one.
205 * This will first update the internal GtkCombobox (blocking
206 * its "changed" callback to prevent an infinite loop).
207 * Then it will update the sample label and finally it will
208 * emit a "changed" signal of it's own for other objects
209 * listening for this signal.
210 */
211static void
212gnc_period_select_set_active_internal (GncPeriodSelect *period,
214{
215 g_return_if_fail(period != NULL);
216 g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
217 g_return_if_fail(which >= 0);
218 g_return_if_fail(which < GNC_ACCOUNTING_PERIOD_LAST);
219
220 g_signal_handlers_block_by_func(G_OBJECT(period),
221 G_CALLBACK(gnc_period_sample_combobox_changed), period);
222 gtk_combo_box_set_active(GTK_COMBO_BOX(period->selector), which);
223 g_signal_handlers_unblock_by_func(G_OBJECT(period),
224 G_CALLBACK(gnc_period_sample_combobox_changed), period);
225
226 /* Update this widget */
227 gnc_period_sample_update_date_label(period);
228
229 /* Pass it on... */
230 gnc_period_select_changed(period);
231}
232
233
237/* Get the current value of the fiscal year end setting from a
238 * GncPeriodSelect widget. If the result is NULL then fiscal years
239 * are not currently supported.
240 */
241GDate *
242gnc_period_select_get_fy_end (GncPeriodSelect *period)
243{
244 g_return_val_if_fail(period != NULL, NULL);
245 g_return_val_if_fail(GNC_IS_PERIOD_SELECT(period), NULL);
246
247 if (!period->fy_end)
248 return NULL;
249 return g_date_new_dmy(g_date_get_day(period->fy_end),
250 g_date_get_month(period->fy_end),
251 G_DATE_BAD_YEAR);
252}
253
254
255/* Set the fiscal year end on a GncPeriodSelect widget. If set to a
256 * value other than NULL then widget will include fiscal accounting
257 * period like "this fiscal year".
258 */
259void
260gnc_period_select_set_fy_end (GncPeriodSelect *period, const GDate *fy_end)
261{
262 const gchar *label;
263 gint i;
264
265 g_return_if_fail(period != NULL);
266 g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
267
268 if (period->fy_end)
269 g_date_free(period->fy_end);
270
271 if (fy_end)
272 {
273 period->fy_end = g_date_copy (fy_end);
274 }
275 else
276 {
277 period->fy_end = NULL;
278 }
279
280 if (fy_end)
281 {
282 for (i = GNC_ACCOUNTING_PERIOD_CYEAR_LAST; i < GNC_ACCOUNTING_PERIOD_FYEAR_LAST; i++)
283 {
284 label = period->start ? _(start_strings[i]) : _(end_strings[i]);
285 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(period->selector), label);
286 }
287 }
288 else
289 {
290 for (i = GNC_ACCOUNTING_PERIOD_FYEAR_LAST - 1; i >= GNC_ACCOUNTING_PERIOD_FYEAR_LAST; i--)
291 {
292 gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(period->selector), i);
293 }
294 }
295}
296
297
298static void
299gnc_period_select_set_date_common (GncPeriodSelect *period, const GDate *date)
300{
301 if (date)
302 {
303 if (period->date_base)
304 g_date_free(period->date_base);
305 period->date_base = g_date_new_dmy(g_date_get_day(date),
306 g_date_get_month(date),
307 g_date_get_year(date));
308 if (period->date_label == NULL)
309 {
310 period->date_label = gtk_label_new("");
311 gtk_widget_set_margin_start (GTK_WIDGET(period->date_label), 6);
312 gtk_box_pack_start(GTK_BOX(period), period->date_label, TRUE, TRUE, 0);
313 gtk_widget_show_all(period->date_label);
314 }
315 gnc_period_sample_update_date_label(period);
316 return;
317 }
318
319 if (period->date_base)
320 {
321 g_date_free(period->date_base);
322 period->date_base = NULL;
323 gtk_widget_destroy(period->date_label);
324 period->date_label = NULL;
325 }
326}
327
328
329/* Get the current value of the "show date" setting from a
330 * GncPeriodSelect widget.
331 */
332gboolean
333gnc_period_select_get_show_date (GncPeriodSelect *period)
334{
335 g_return_val_if_fail(period != NULL, FALSE);
336 g_return_val_if_fail(GNC_IS_PERIOD_SELECT(period), FALSE);
337
338 return (period->date_base != NULL);
339}
340
341/* Set the "show date" setting on a GncPeriodSelect widget. If set
342 * to TRUE then a GtkLabel will be used to show the date
343 * corresponding to the selected time period.
344 */
345void
346gnc_period_select_set_show_date (GncPeriodSelect *period, const gboolean show_date)
347{
348 GDate date;
349
350 g_return_if_fail(period != NULL);
351 g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
352
353 if (show_date)
354 {
355 g_date_clear(&date, 1);
356 gnc_gdate_set_time64(&date, gnc_time (NULL));
357 gnc_period_select_set_date_common(period, &date);
358 }
359 else
360 {
361 gnc_period_select_set_date_common(period, NULL);
362 }
363}
364
365
366GDate *
367gnc_period_select_get_date_base (GncPeriodSelect *period)
368{
369 g_return_val_if_fail(period != NULL, NULL);
370 g_return_val_if_fail(GNC_IS_PERIOD_SELECT(period), NULL);
371
372 if (!period->date_base)
373 return NULL;
374 return g_date_new_dmy(g_date_get_day(period->date_base),
375 g_date_get_month(period->date_base),
376 g_date_get_year(period->date_base));
377}
378
379
380/* Set the base date used by a GncPeriodSelect widget. All example
381 * dates presented by the widget will be computed from this date.
382 */
383void
384gnc_period_select_set_date_base (GncPeriodSelect *period, const GDate *date_base)
385{
386 g_return_if_fail(period != NULL);
387 g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
388
389 gnc_period_select_set_date_common(period, date_base);
390}
391
392
400static void
401gnc_period_select_get_property (GObject *object,
402 guint prop_id,
403 GValue *value,
404 GParamSpec *pspec)
405{
406 GncPeriodSelect *period = GNC_PERIOD_SELECT(object);
407
408 switch (prop_id)
409 {
410 case PROP_FY_END:
411 g_value_set_pointer(value, gnc_period_select_get_fy_end(period));
412 break;
413 case PROP_SHOW_DATE:
414 g_value_set_boolean(value, gnc_period_select_get_show_date(period));
415 break;
416 case PROP_DATE_BASE:
417 g_value_set_pointer(value, gnc_period_select_get_date_base(period));
418 break;
419 case PROP_PS_ACTIVE:
420 g_value_set_int(value, gnc_period_select_get_active(period));
421 break;
422 default:
423 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
424 break;
425 }
426}
427
428
437static void
438gnc_period_select_set_property (GObject *object,
439 guint prop_id,
440 const GValue *value,
441 GParamSpec *pspec)
442{
443 GncPeriodSelect *period = GNC_PERIOD_SELECT(object);
444
445 switch (prop_id)
446 {
447 case PROP_FY_END:
448 gnc_period_select_set_fy_end(period, g_value_get_pointer(value));
449 break;
450 case PROP_SHOW_DATE:
451 gnc_period_select_set_show_date(period, g_value_get_boolean(value));
452 break;
453 case PROP_DATE_BASE:
454 gnc_period_select_set_date_base(period, g_value_get_pointer(value));
455 break;
456 case PROP_PS_ACTIVE:
457 gnc_period_select_set_active_internal(period, g_value_get_int(value));
458 break;
459 default:
460 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
461 break;
462 }
463}
464
467/************************************************************/
468/* Core Implementation */
469/************************************************************/
470
483static void
484gnc_period_select_class_init (GncPeriodSelectClass *klass)
485{
486 GObjectClass *gobject_class;
487
488 gobject_class = G_OBJECT_CLASS(klass);
489 gobject_class->set_property = gnc_period_select_set_property;
490 gobject_class->get_property = gnc_period_select_get_property;
491 gobject_class->finalize = gnc_period_select_finalize;
492
493
494 signals[CHANGED] = g_signal_new("changed",
495 G_OBJECT_CLASS_TYPE (klass),
496 G_SIGNAL_RUN_FIRST,
497 0,
498 NULL, NULL,
499 g_cclosure_marshal_VOID__VOID,
500 G_TYPE_NONE,
501 0);
502
503
504 g_object_class_install_property(gobject_class,
505 PROP_FY_END,
506 g_param_spec_pointer("fy-end",
507 "Fiscal Year End",
508 "The fiscal year to use for this widget",
509 G_PARAM_READWRITE));
510 g_object_class_install_property(gobject_class,
511 PROP_SHOW_DATE,
512 g_param_spec_boolean("show-date",
513 "Show Date",
514 "Show the start/end date of the accounting period in this widget",
515 FALSE,
516 G_PARAM_READWRITE));
517 g_object_class_install_property(gobject_class,
518 PROP_DATE_BASE,
519 g_param_spec_pointer("date-base",
520 "Date Base",
521 "The starting date to use for display calculations",
522 G_PARAM_READWRITE));
523 g_object_class_install_property(gobject_class,
524 PROP_PS_ACTIVE,
525 g_param_spec_int("active",
526 "Active period",
527 "The currently selected period in the list of periods",
528 -1,
529 G_MAXINT,
530 0,
531 G_PARAM_READWRITE));
532}
533
542static void
543gnc_period_select_init (GncPeriodSelect *period)
544{
545 gtk_orientable_set_orientation (GTK_ORIENTABLE(period), GTK_ORIENTATION_HORIZONTAL);
546
547 // Set the name for this widget so it can be easily manipulated with css
548 gtk_widget_set_name (GTK_WIDGET(period), "gnc-id-period-select");
549
550 period->start = TRUE;
551}
552
553
564static void
565gnc_period_select_finalize (GObject *object)
566{
567 GncPeriodSelect *period;
568
569 g_return_if_fail (object != NULL);
570 g_return_if_fail (GNC_IS_PERIOD_SELECT (object));
571
572 period = GNC_PERIOD_SELECT(object);
573
574 /* Stop tracking changes to date formatting */
575 gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL, GNC_PREF_DATE_FORMAT,
576 gnc_period_sample_new_date_format, period);
577
578 /* The selector and date_label were added to the hbox. They will be
579 * freed automatically. */
580 if (period->fy_end)
581 g_date_free(period->fy_end);
582 if (period->date_base)
583 g_date_free(period->date_base);
584
585 /* Do not free the private data structure. It is part of a larger
586 * memory block allocated by the type system. */
587
588 G_OBJECT_CLASS(gnc_period_select_parent_class)->finalize (object);
589}
590
591
592/* Create a new GncPeriodSelect widget which is used to select a
593 * accounting period like "previous month" or "this year".
594 *
595 * @param starting_labels If set to TRUE then all the labels will
596 * refer to the "Start of…". If FALSE, labels will refer to "End
597 * of...".
598 *
599 * @return A GncPeriodSelect widget.
600 */
601GtkWidget *
602gnc_period_select_new (gboolean starting_labels)
603{
604 GncPeriodSelect *period;
605 const gchar *label;
606 gint i;
607
608 period = g_object_new(GNC_TYPE_PERIOD_SELECT, NULL);
609
610 /* Set up private data structures */
611 period->selector = gtk_combo_box_text_new();
612 period->start = starting_labels;
613
614 /* Add the internal widgets to the hbox */
615 gtk_box_pack_start(GTK_BOX(period), period->selector, TRUE, TRUE, 0);
616 gtk_widget_show(period->selector);
617
618 /* Find out when the combo box changes */
619 g_signal_connect(G_OBJECT(period->selector), "changed",
620 G_CALLBACK(gnc_period_sample_combobox_changed), period);
621
622 /* Build all the labels except the fiscal year labels */
623 for (i = 0; i < GNC_ACCOUNTING_PERIOD_CYEAR_LAST; i++)
624 {
625 label = starting_labels ? _(start_strings[i]) : _(end_strings[i]);
626 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(period->selector), label);
627 }
628
629 /* Track changes to date formatting */
630 gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL, GNC_PREF_DATE_FORMAT,
631 gnc_period_sample_new_date_format, period);
632
633 return GTK_WIDGET (period);
634}
635
636
637/* Create a new GncPeriodSelect widget from a glade file. The int1
638 * argument passed from glade is used to determine whether the widget
639 * uses labels for start times or end times. A non-zero int2
640 * argument indicates that an example date should be shown.
641 */
642GtkWidget *
643gnc_period_select_new_glade (gchar *widget_name,
644 gchar *string1, gchar *string2,
645 gint int1, gint int2)
646{
647 GtkWidget *widget;
648 widget = gnc_period_select_new(int1 != 0);
649 if (int2)
650 gnc_period_select_set_show_date(GNC_PERIOD_SELECT(widget), TRUE);
651 gtk_widget_show(widget);
652 return widget;
653}
654
657/************************************************************/
658/* Auxiliary Functions */
659/************************************************************/
660
661
662/* Set which item in the GncPeriodSelect is initially selected. This
663 * is used to set the initial selection before the widget is shown to
664 * the user.
665 */
666void
667gnc_period_select_set_active (GncPeriodSelect *period,
669{
670 g_return_if_fail(period != NULL);
671 g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
672 g_return_if_fail(which >= 0);
673 g_return_if_fail(which < GNC_ACCOUNTING_PERIOD_LAST);
674
675 g_object_set (G_OBJECT (period), "active", which, NULL);
676}
677
678
679/* Get the currently selected accounting period from a
680 * GncPeriodSelect widget. This is used to retrieve the user's
681 * selection in the form of an enum.
682 */
684gnc_period_select_get_active (GncPeriodSelect *period)
685{
686 g_return_val_if_fail(period != NULL, -1);
687 g_return_val_if_fail(GNC_IS_PERIOD_SELECT(period), -1);
688
689 return gtk_combo_box_get_active(GTK_COMBO_BOX(period->selector));
690}
691
692
693/* Get the currently selected accounting period choice from a
694 * GncPeriodSelect widget. This is used to retrieve the user's
695 * selection in the form of a GDate.
696 */
697GDate *
698gnc_period_select_get_date (GncPeriodSelect *period)
699{
701
702 g_return_val_if_fail(period != NULL, 0);
703 g_return_val_if_fail(GNC_IS_PERIOD_SELECT(period), 0);
704
705 which = gtk_combo_box_get_active(GTK_COMBO_BOX(period->selector));
706 if (which == -1)
707 return NULL;
708
709 if (period->start)
710 return gnc_accounting_period_start_gdate(which, period->fy_end,
711 period->date_base);
712 return gnc_accounting_period_end_gdate(which, period->fy_end,
713 period->date_base);
714}
715
Date and Time handling routines.
A custom widget for selecting accounting periods.
Generic api to store and retrieve preferences.
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
Definition gnc-date.h:108
void gnc_gdate_set_time64(GDate *gd, time64 time)
Set a GDate to a time64.
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
size_t qof_print_gdate(char *buf, size_t len, const GDate *gd)
Convenience; calls through to qof_print_date_dmy_buff().
Definition gnc-date.cpp:598
GDate * gnc_period_select_get_date(GncPeriodSelect *period)
Get the currently selected accounting period choice from a GncPeriodSelect widget.
GtkWidget * gnc_period_select_new_glade(gchar *widget_name, gchar *string1, gchar *string2, gint int1, gint int2)
Create a new GncPeriodSelect widget from a glade file.
GncAccountingPeriod
This specifies a time interval.
void gnc_period_select_set_show_date(GncPeriodSelect *period, const gboolean show_date)
Set the "show sample" setting on a GncPeriodSelect widget.
gboolean gnc_period_select_get_show_date(GncPeriodSelect *period)
Get the current value of the "show sample" setting from a GncPeriodSelect widget.
GDate * gnc_period_select_get_fy_end(GncPeriodSelect *period)
Get the current value of the fiscal year end setting from a GncPeriodSelect widget.
GDate * gnc_accounting_period_end_gdate(GncAccountingPeriod which, const GDate *fy_end, const GDate *contains)
This function returns the ending date for an accounting period.
void gnc_period_select_set_fy_end(GncPeriodSelect *period, const GDate *fy_end)
Set the fiscal year end on a GncPeriodSelect widget.
GDate * gnc_accounting_period_start_gdate(GncAccountingPeriod which, const GDate *fy_end, const GDate *contains)
This function returns the starting date for an accounting period.
GncAccountingPeriod gnc_period_select_get_active(GncPeriodSelect *period)
Get the currently selected accounting period from a GncPeriodSelect widget.
GtkWidget * gnc_period_select_new(gboolean starting_labels)
Create a new GncPeriodSelect widget which is used to select a accounting period like "previous month"...
void gnc_period_select_set_active(GncPeriodSelect *period, GncAccountingPeriod which)
Set which item in the GncPeriodSelect is initially selected.
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Register a callback that gets triggered when the given preference changes.
Private Data Structure.