GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-plugin-page-register-filter.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * gnc-plugin-page-register-filter.cpp -- register page filter *
3 * *
4 * Copyright (C) 2026, Robert Fewell *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22 **********************************************************************/
23
33#include <config.h>
34
35#include <gtk/gtk.h>
36#include <glib/gi18n.h>
37#include "dialog-utils.h"
38#include "gnc-date.h"
39#include "gnc-date-edit.h"
40#include "gnc-glib-utils.h"
41#include "gnc-ui.h"
42#include "gnc-state.h"
43#include "gnc-period-select.h"
44#include "gnc-prefs.h"
45#include "gnc-ui-util.h"
46#include "gnc-window.h"
47#include "gnc-main-window.h"
48#include "engine-helpers.h"
49#include "qofbookslots.h"
50#include "qof.h"
51#include "Query.h"
52
53#include <algorithm>
54#include <array>
55#include <cstdio>
56#include <iostream>
57#include <sstream>
58#include <string>
59#include <vector>
60
63
64static std::string DEFAULT_FILTER_NUM_DAYS_GL = "30";
65static std::string DEFAULT_FILTER = "0x001f";
66
67/* This static indicates the debugging module that this .o belongs to. */
68static QofLogModule log_module = GNC_MOD_GUI;
69
71{
72 GncPluginPage* plugin_page;
73 GtkWidget* dialog;
74 GtkWidget* table;
75 GtkWidget* start_earliest; //label
76 GtkWidget* start_relative_check; //checkbutton
77 GtkWidget* start_relative; //account period
78 GtkWidget* start_date_check; //checkbutton
79 GtkWidget* start_date; //date
80 GtkWidget* start_days_check; //checkbutton
81 GtkWidget* start_days; //spin
82
83 GtkWidget* end_latest;
84 GtkWidget* end_relative_check;
85 GtkWidget* end_relative;
86 GtkWidget* end_date_check;
87 GtkWidget* end_date;
88 GtkWidget* end_days_check;
89 GtkWidget* end_days;
90
91 GtkWidget* num_days;
92
93 cleared_match_t original_cleared_match;
94 GncAccountingPeriod original_start_ap;
95 time64 original_start_time;
96 int original_start_days;
97 GncAccountingPeriod original_end_ap;
98 time64 original_end_time;
99 int original_end_days;
100 int original_days;
101 bool original_save_filter;
102
103 bool show_save_button;
104};
105
106extern "C"
107{
108// These functions are the dialog callbacks. They're connected to their
109// signals in gnc-plugin-page-register.glade so they mustn't be name-mangled.
110void
111gnc_ppr_filter_select_range_cb (GtkRadioButton* button,
113void
114gnc_ppr_filter_start_cb (GtkWidget* radio,
116void
117gnc_ppr_filter_end_cb (GtkWidget* radio,
119void
120gnc_ppr_filter_response_cb (GtkDialog* dialog,
121 gint response,
123void
124gnc_ppr_filter_status_select_all_cb (GtkButton* button,
126void
127gnc_ppr_filter_status_clear_all_cb (GtkButton* button,
129void
130gnc_ppr_filter_status_one_cb (GtkToggleButton* button,
132void
133gnc_ppr_filter_save_cb (GtkToggleButton* button,
135void
136gnc_ppr_filter_days_changed_cb (GtkSpinButton* button,
138void
139gnc_ppr_filter_start_toggle_cb (GtkToggleButton* button,
141void
142gnc_ppr_filter_end_toggle_cb (GtkToggleButton* button,
144void
145gnc_ppr_filter_start_end_days_changed_cb (GtkSpinButton* button,
147}
148
150{
151 std::string action_name;
152 int value;
153 GtkWidget* widget;
154};
155
156static std::array<status_action, 5> status_actions {{
157 { "filter_status_reconciled", CLEARED_RECONCILED, nullptr },
158 { "filter_status_cleared", CLEARED_CLEARED, nullptr },
159 { "filter_status_voided", CLEARED_VOIDED, nullptr },
160 { "filter_status_frozen", CLEARED_FROZEN, nullptr },
161 { "filter_status_unreconciled", CLEARED_NO, nullptr }
162}};
163
164#ifdef skip
165static inline bool
166gboolean_to_bool (gboolean value)
167{
168 return value ? true : false;
169}
170#endif
171static inline gboolean
172bool_to_gboolean (bool value)
173{
174 return value ? TRUE : FALSE;
175}
176
177static std::string
178get_filter_default_num_of_days (GNCLedgerDisplayType ledger_type)
179{
180 if (ledger_type == LD_GL)
181 return DEFAULT_FILTER_NUM_DAYS_GL;
182 else
183 return "0";
184}
185
186/* This function converts a time64 value date to a string */
187static std::string
188ppr_filter_time2dmy (time64 raw_time)
189{
190 struct tm* timeinfo;
191 char date_string[11];
192
193 timeinfo = gnc_localtime (&raw_time);
194 strftime (date_string, 11, "%d-%m-%Y", timeinfo);
195 PINFO("Date to string is %s", date_string);
196 gnc_tm_free (timeinfo);
197
198 return (date_string);
199}
200
201/* This function converts a string date to a time64 value */
202static time64
203ppr_filter_dmy2time (std::string date_string)
204{
205 struct tm when;
206
207 PINFO("Date from string is %s", date_string.c_str());
208 memset (&when, 0, sizeof (when));
209
210 std::sscanf (date_string.c_str(), "%d-%d-%d", &when.tm_mday,
211 &when.tm_mon, &when.tm_year);
212
213 when.tm_mon -= 1;
214 when.tm_year -= 1900;
215
216 return gnc_mktime (&when);
217}
218
219/* This function subtracts a number of days from now to a time64 value */
220static time64
221get_time_for_days_ago (int days, bool use_day_start)
222{
223 time64 time_val = 0;
224
225 if (days > 0)
226 {
227 struct tm tm;
228 if (use_day_start)
230 else
232 tm.tm_mday = tm.tm_mday - days;
233 time_val = gnc_mktime (&tm);
234 }
235 return time_val;
236}
237
238static std::vector<std::string>
239split_filter_by_delimiter (std::string str, char delimiter)
240{
241 std::istringstream ss;
242 std::vector<std::string> res;
243 std::string token;
244 ss.str (str);
245 while (std::getline (ss, token, delimiter))
246 {
247 res.push_back (token);
248 }
249 return res;
250}
251
252static void
253ppr_check_for_empty_group (GKeyFile *state_file,
254 const gchar *state_section)
255{
256 gsize num_keys;
257 gchar **keys = g_key_file_get_keys (state_file, state_section, &num_keys, nullptr);
258
259 if (num_keys == 0)
260 gnc_state_drop_sections_for (state_section);
261
262 g_strfreev (keys);
263}
264
265static std::string
266ppr_filter_load_filter (GNCSplitReg *gsr, GNCLedgerDisplayType ledger_type)
267{
268 // get the filter from the .gcm file
269 GKeyFile* state_file = gnc_state_get_current();
270 auto state_section = gsr_get_register_state_section (gsr);
271 GError* error = nullptr;
272
273 auto filter = g_key_file_get_string (state_file, state_section,
274 KEY_PAGE_FILTER, &error);
275 std::string filter_str;
276
277 if (error)
278 g_clear_error (&error);
279 else
280 filter_str = std::string (filter);
281
282 g_free (filter);
283 g_free (state_section);
284
285 if (!filter_str.empty())
286 return filter_str;
287
288 return DEFAULT_FILTER + ";0;0;" + get_filter_default_num_of_days (ledger_type);
289}
290
291static void
292set_filterdata_to_defaults (FilterData *fd, bool date_parts_only)
293{
294 if (!date_parts_only)
295 {
296 fd->cleared_match = (cleared_match_t)std::stol (DEFAULT_FILTER, nullptr, 16);
297 fd->save_filter = false;
298 }
299 fd->start_ap = GNC_ACCOUNTING_PERIOD_INVALID;
300 fd->start_time = 0;
301 fd->start_days = 0;
302 fd->end_ap = GNC_ACCOUNTING_PERIOD_INVALID;
303 fd->end_time = 0;
304 fd->end_days = 0;
305 fd->days = 0;
306}
307
308static int
309get_trailing_int (const std::string split_filter, const std::string find_text)
310{
311 int ret_int = -1;
312 std::size_t found = split_filter.find (find_text);
313
314 if (found != std::string::npos)
315 {
316 std::string found_str = split_filter.substr (found + find_text.length(), std::string::npos);
317 ret_int = std::stol (found_str, nullptr, 10);
318 }
319 return ret_int;
320}
321
322static void
323update_fd_with_date_filter_parts (FilterData *fd, const std::string filter_part,
324 bool start_filter, int ap_trailing_int, int days_trailing_int)
325{
326 if (ap_trailing_int != -1)
327 {
328 GDate *tmp_date = nullptr;
329
330 if (start_filter)
331 {
332 fd->start_ap = (GncAccountingPeriod)ap_trailing_int;
333 tmp_date = gnc_accounting_period_start_gdate (fd->start_ap, nullptr, nullptr);
334 }
335 else
336 {
337 fd->end_ap = (GncAccountingPeriod)ap_trailing_int;
338 tmp_date = gnc_accounting_period_end_gdate (fd->end_ap, nullptr, nullptr);
339 }
340
341 if (tmp_date)
342 {
343 if (start_filter)
344 fd->start_time = gnc_time64_get_day_start_gdate (tmp_date);
345 else
346 fd->end_time = gnc_time64_get_day_end_gdate (tmp_date);
347
348 g_date_free (tmp_date);
349 }
350 }
351 else
352 {
353 if (days_trailing_int != -1)
354 {
355 if (start_filter)
356 {
357 fd->start_days = days_trailing_int;
358 fd->start_time = get_time_for_days_ago (fd->start_days, true);
359 }
360 else
361 {
362 fd->end_days = days_trailing_int;
363 fd->end_time = get_time_for_days_ago (fd->end_days, false);
364 }
365 }
366 else
367 {
368 time64 tmp_time = ppr_filter_dmy2time (filter_part);
369 if (start_filter)
370 fd->start_time = gnc_time64_get_day_start (tmp_time);
371 else
372 fd->end_time = gnc_time64_get_day_end (tmp_time);
373 }
374 }
375 fd->save_filter = true;
376}
377
378static void
379ppr_filter_load_filter_parts (GNCSplitReg *gsr, GNCLedgerDisplayType ledger_type, FilterData *fd)
380{
381 set_filterdata_to_defaults (fd, false);
382 fd->dialog = nullptr;
383
384 if (!gsr)
385 return;
386
387 std::string filter_str = ppr_filter_load_filter (gsr, ledger_type);
388
389 PINFO("Loaded Filter String is %s", filter_str.c_str());
390
391 std::vector<std::string> split_filter = split_filter_by_delimiter (filter_str, ';');
392 int split_filter_size = split_filter.size();
393
394 if (split_filter_size > 0 && (split_filter[0].compare (DEFAULT_FILTER)) != 0)
395 {
396 PINFO("Loaded Filter Status is %s", split_filter[0].c_str());
397
398 fd->cleared_match = (cleared_match_t)std::stol (split_filter[0], nullptr, 16);
399 fd->save_filter = true;
400 }
401
402 if (split_filter_size > 1 && (split_filter[1].compare (std::string ("0"))) != 0)
403 {
404 PINFO("Loaded Filter Start Date is %s", split_filter[1].c_str());
405
406 int ap_trailing_int = get_trailing_int (split_filter[1], "SAP");
407 int days_trailing_int = get_trailing_int (split_filter[1], "SDAY");
408
409 update_fd_with_date_filter_parts (fd, split_filter[1], true, ap_trailing_int, days_trailing_int);
410 }
411
412 if (split_filter_size > 2 && (split_filter[2].compare (std::string ("0"))) != 0)
413 {
414 PINFO("Loaded Filter End Date is %s", split_filter[2].c_str());
415
416 int ap_trailing_int = get_trailing_int (split_filter[2], "EAP");
417 int days_trailing_int = get_trailing_int (split_filter[2], "EDAY");
418
419 update_fd_with_date_filter_parts (fd, split_filter[2], false, ap_trailing_int, days_trailing_int);
420 }
421
422 // set the default for the number of days
423 fd->days = (int)std::stol (get_filter_default_num_of_days (ledger_type), nullptr, 10);
424
425 if (split_filter_size > 3 &&
426 (split_filter[3].compare (get_filter_default_num_of_days (ledger_type)) != 0))
427 {
428 PINFO("Loaded Filter Days is %s", split_filter[3].c_str());
429
430 fd->days = (int)std::stol (split_filter[3], nullptr, 10);
431 fd->save_filter = true;
432 }
433}
434
435static void
436ppr_filter_save_filter (GNCSplitReg *gsr, std::string filter)
437
438{
439 GNCLedgerDisplayType ledger_type = gnc_ledger_display_type (gsr->ledger);
440
441 std::string default_filter_str = DEFAULT_FILTER + ";0;0;" +
442 get_filter_default_num_of_days (ledger_type);
443
444 // save the filter to the .gcm file also
445 GKeyFile* state_file = gnc_state_get_current();
446 auto state_section = gsr_get_register_state_section (gsr);
447
448 if (filter.empty() || (filter.compare (default_filter_str) == 0))
449 {
450 if (g_key_file_has_key (state_file, state_section, KEY_PAGE_FILTER, nullptr))
451 g_key_file_remove_key (state_file, state_section, KEY_PAGE_FILTER, nullptr);
452
453 ppr_check_for_empty_group (state_file, state_section);
454 }
455 else
456 {
457 PINFO("The filter to save is %s", filter.c_str());
458 g_key_file_set_string (state_file, state_section, KEY_PAGE_FILTER,
459 filter.c_str());
460 }
461 g_free (state_section);
462}
463
464static void
465ppr_filter_save_filter_parts (GNCSplitReg *gsr, FilterData *fd)
466{
467 if (!gsr)
468 return;
469
470 std::string save_filter_str;
471
472 if (fd->save_filter)
473 {
474 static const size_t buffer_size = 10;
475 char buffer [buffer_size];
476
477 // cleared match
478 std::snprintf (buffer, buffer_size, "0x%04x", fd->cleared_match);
479 save_filter_str.append (buffer);
480
481 // start time
482 if (fd->start_ap != GNC_ACCOUNTING_PERIOD_INVALID)
483 save_filter_str.append (";SAP" + std::to_string (fd->start_ap));
484 else if (fd->start_days > 0)
485 save_filter_str.append (";SDAY" + std::to_string (fd->start_days));
486 else if (fd->start_time != 0)
487 save_filter_str.append (";" + ppr_filter_time2dmy (fd->start_time));
488 else
489 save_filter_str.append (";0");
490
491 // end time
492 if (fd->end_ap != GNC_ACCOUNTING_PERIOD_INVALID)
493 save_filter_str.append (";EAP" + std::to_string (fd->end_ap));
494 else if (fd->end_days > 0)
495 save_filter_str.append (";EDAY" + std::to_string (fd->end_days));
496 else if (fd->end_time != 0)
497 save_filter_str.append (";" + ppr_filter_time2dmy (fd->end_time));
498 else
499 save_filter_str.append (";0");
500
501 // number of days
502 if (fd->days > 0)
503 {
504 save_filter_str.append (";" + std::to_string (fd->days));
505 }
506 else
507 save_filter_str.append (";0");
508 }
509 ppr_filter_save_filter (gsr, save_filter_str);
510}
511
512static void
513update_match_filter_text (cleared_match_t match, const guint mask,
514 const gchar* filter_name, GList **show, GList **hide)
515{
516 if ((match & mask) == mask)
517 *show = g_list_prepend (*show, g_strdup (filter_name));
518 else
519 *hide = g_list_prepend (*hide, g_strdup (filter_name));
520}
521
530void
532{
533 GList *t_list = nullptr;
534
535 ENTER(" ");
536
537 auto gsr = gnc_plugin_page_register_get_gsr (plugin_page);
538
539 // filtered start time
540 if (fd->start_time != 0)
541 {
542 auto sdate = qof_print_date (fd->start_time);
543 t_list = g_list_prepend
544 (t_list, g_strdup_printf ("%s %s", _("Start Date:"), sdate));
545 g_free (sdate);
546 }
547
548 // filtered number of days
549 if (fd->days > 0)
550 {
551 t_list = g_list_prepend
552 (t_list, g_strdup_printf ("%s %d", _("Show previous number of days:"),
553 fd->days));
554 }
555 // filtered end time
556 if (fd->end_time != 0)
557 {
558 auto edate = qof_print_date (fd->end_time);
559 t_list = g_list_prepend
560 (t_list, g_strdup_printf ("%s %s", _("End Date:"), edate));
561 g_free (edate);
562 }
563
564 // filtered match items
565 if (fd->cleared_match != CLEARED_ALL)
566 {
567 GList *show = nullptr;
568 GList *hide = nullptr;
569
570 update_match_filter_text (fd->cleared_match, 0x01, _("Unreconciled"),
571 &show, &hide);
572 update_match_filter_text (fd->cleared_match, 0x02, _("Cleared"),
573 &show, &hide);
574 update_match_filter_text (fd->cleared_match, 0x04, _("Reconciled"),
575 &show, &hide);
576 update_match_filter_text (fd->cleared_match, 0x08, _("Frozen"),
577 &show, &hide);
578 update_match_filter_text (fd->cleared_match, 0x10, _("Voided"),
579 &show, &hide);
580
581 show = g_list_reverse (show);
582 hide = g_list_reverse (hide);
583
584 if (show)
585 {
586 auto str = gnc_list_formatter (show);
587 t_list = g_list_prepend
588 (t_list, g_strdup_printf ("%s %s", _("Show:"), str));
589 g_free (str);
590 }
591
592 if (hide)
593 {
594 auto str = gnc_list_formatter (hide);
595 t_list = g_list_prepend
596 (t_list, g_strdup_printf ("%s %s", _("Hide:"), str));
597 g_free (str);
598 }
599
600 g_list_free_full (show, g_free);
601 g_list_free_full (hide, g_free);
602 }
603
604 t_list = g_list_reverse (t_list);
605
606 if (t_list)
607 t_list = g_list_prepend (t_list, g_strdup (_("Filter By:")));
608
609 // free the existing text if present
610 if (gsr->filter_text)
611 g_free (gsr->filter_text);
612
613 // set the tooltip text variable in the gsr
614 gsr->filter_text = gnc_g_list_stringjoin (t_list, "\n");
615
616 g_list_free_full (t_list, g_free);
617
618 LEAVE(" ");
619}
620
621static void
622ppr_filter_update_status_query (GncPluginPage* plugin_page)
623{
624 ENTER(" ");
625
626 auto gsr = gnc_plugin_page_register_get_gsr (plugin_page);
627 if (!gsr->ledger)
628 {
629 LEAVE("no ledger");
630 return;
631 }
632
633 // check if this a search register and save query
634 gnc_plugin_page_register_update_for_search_query (GNC_PLUGIN_PAGE_REGISTER(plugin_page));
635
636 auto query = gnc_plugin_page_register_get_query (plugin_page);
637 if (!query)
638 {
639 LEAVE("no query found");
640 return;
641 }
642
643 auto fd = gnc_plugin_page_register_get_filter_data (plugin_page);
644 auto reg = gnc_ledger_display_get_split_register (gsr->ledger);
645
646 /* Remove the old status match */
647 if (reg->type != SEARCH_LEDGER)
648 {
649 GSList *param_list = qof_query_build_param_list (SPLIT_RECONCILE, nullptr);
650 qof_query_purge_terms (query, param_list);
651 g_slist_free (param_list);
652 }
653
654 /* Install the new status match */
655 if (fd->cleared_match != CLEARED_ALL)
656 xaccQueryAddClearedMatch (query, fd->cleared_match, QOF_QUERY_AND);
657
658 // Set filter tooltip for summary bar
659 gnc_ppr_filter_set_tooltip (plugin_page, fd);
660
661 gnc_plugin_page_register_query_update (GNC_PLUGIN_PAGE_REGISTER(plugin_page), query);
662 LEAVE (" ");
663}
664
665static void
666ppr_filter_update_date_query (GncPluginPage* plugin_page)
667{
668 ENTER(" ");
669
670 auto gsr = gnc_plugin_page_register_get_gsr (plugin_page);
671 if (!gsr->ledger)
672 {
673 LEAVE("no ledger");
674 return;
675 }
676
677 // check if this a search register and save query
678 gnc_plugin_page_register_update_for_search_query (GNC_PLUGIN_PAGE_REGISTER(plugin_page));
679
680 auto query = gnc_plugin_page_register_get_query (plugin_page);
681 if (!query)
682 {
683 LEAVE("no query found");
684 return;
685 }
686
687 auto fd = gnc_plugin_page_register_get_filter_data (plugin_page);
688 auto reg = gnc_ledger_display_get_split_register (gsr->ledger);
689
690 /* Delete any existing old date spec. */
691 if (reg->type != SEARCH_LEDGER)
692 {
693 GSList *param_list = qof_query_build_param_list (SPLIT_TRANS,
694 TRANS_DATE_POSTED, nullptr);
695 qof_query_purge_terms (query, param_list);
696 g_slist_free (param_list);
697 }
698
699 if (fd->start_time || fd->end_time)
700 {
701 /* Build a new spec */
702 xaccQueryAddDateMatchTT (query,
703 fd->start_time != 0, fd->start_time,
704 fd->end_time != 0, fd->end_time,
705 QOF_QUERY_AND);
706 }
707
708 if (fd->days > 0)
709 {
710 time64 start = get_time_for_days_ago (fd->days, true);
711 xaccQueryAddDateMatchTT (query, TRUE, start, FALSE, 0, QOF_QUERY_AND);
712 }
713
714 // Set filter tooltip for summary bar
715 gnc_ppr_filter_set_tooltip (plugin_page, fd);
716
717 gnc_plugin_page_register_query_update (GNC_PLUGIN_PAGE_REGISTER(plugin_page), query);
718 LEAVE(" ");
719}
720
727void
729{
730 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page));
731
732 auto fd = gnc_plugin_page_register_get_filter_data (plugin_page);
733
734 set_filterdata_to_defaults (fd, false);
735
736 ppr_filter_update_date_query (plugin_page);
737}
738
744void
746{
747 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page));
748
749 auto gsr = gnc_plugin_page_register_get_gsr (plugin_page);
750
751 if (!gsr)
752 return;
753
754 auto fd = gnc_plugin_page_register_get_filter_data (plugin_page);
755 GNCLedgerDisplayType ledger_type = gnc_ledger_display_type (gsr->ledger);
756
757 /* Set the filter for the split register and status of save filter button */
758 fd->save_filter = false;
759
760 ppr_filter_load_filter_parts (gsr, ledger_type, fd);
761
762 if (ledger_type == LD_GL)
763 {
764 SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger);
765
766 if (reg->type != GENERAL_JOURNAL) // search ledger and the like
767 set_filterdata_to_defaults (fd, false);
768 }
769 /* Update Query with Filter Status and Dates */
770 ppr_filter_update_status_query (plugin_page);
771 ppr_filter_update_date_query (plugin_page);
772}
773
783void
784gnc_ppr_filter_status_one_cb (GtkToggleButton* button,
786{
787 g_return_if_fail (GTK_IS_CHECK_BUTTON(button));
788 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
789
790 auto name = gtk_buildable_get_name (GTK_BUILDABLE(button));
791
792 ENTER("toggle button %s (%p), plugin_page %p", name, button, rfd->plugin_page);
793
794 auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page);
795
796 /* Determine what status bit to change */
797 int value = CLEARED_NONE;
798 for (const auto& action : status_actions)
799 {
800 if (action.action_name.compare (name) == 0)
801 {
802 value = action.value;
803 break;
804 }
805 }
806
807 /* Compute the new match status */
808 if (gtk_toggle_button_get_active (button))
809 fd->cleared_match = (cleared_match_t)(fd->cleared_match | value);
810 else
811 fd->cleared_match = (cleared_match_t)(fd->cleared_match & ~value);
812
813 ppr_filter_update_status_query (rfd->plugin_page);
814
815 LEAVE(" ");
816}
817
818static void
819set_sensitive_start_widget (RegisterFilterDialog *rfd, GtkWidget *enable_widget, gboolean active)
820{
821 gtk_widget_set_sensitive (GTK_WIDGET(rfd->start_earliest), !active);
822 gtk_widget_set_sensitive (GTK_WIDGET(rfd->start_relative), FALSE);
823 gtk_widget_set_sensitive (GTK_WIDGET(rfd->start_date), FALSE);
824 gtk_widget_set_sensitive (GTK_WIDGET(rfd->start_days), FALSE);
825 gtk_widget_set_sensitive (GTK_WIDGET(enable_widget), active);
826}
827
828static void
829set_sensitive_end_widget (RegisterFilterDialog *rfd, GtkWidget *enable_widget, gboolean active)
830{
831 gtk_widget_set_sensitive (GTK_WIDGET(rfd->end_latest), !active);
832 gtk_widget_set_sensitive (GTK_WIDGET(rfd->end_relative), FALSE);
833 gtk_widget_set_sensitive (GTK_WIDGET(rfd->end_date), FALSE);
834 gtk_widget_set_sensitive (GTK_WIDGET(rfd->end_days), FALSE);
835 gtk_widget_set_sensitive (GTK_WIDGET(enable_widget), active);
836}
837
838static void
839set_checkbutton_with_blocking (GtkWidget *widget1, GtkWidget *widget2,
840 GFunc function,
842 gboolean active)
843{
844 PINFO("Block GtkToggleButton %p for setting active %s",
845 widget1, active ? "TRUE" : "FALSE");
846 g_signal_handlers_block_by_func (widget1,
847 (gpointer)function, rfd);
848 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget1), active);
849 g_signal_handlers_unblock_by_func (widget1,
850 (gpointer)function, rfd);
851
852 if (widget2)
853 {
854 PINFO("Block GtkToggleButton %p for setting active %s",
855 widget2, active ? "TRUE" : "FALSE");
856 g_signal_handlers_block_by_func (widget2,
857 (gpointer)function, rfd);
858 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget2), active);
859 g_signal_handlers_unblock_by_func (widget2,
860 (gpointer)function, rfd);
861 }
862}
863
872void
875{
876 g_return_if_fail (GTK_IS_BUTTON(button));
877 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
878
879 ENTER("(button %p, page %p)", button, rfd->plugin_page);
880
881 auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page);
882
883 /* Turn on all the check menu items */
884 for (const auto& action : status_actions)
885 {
886 set_checkbutton_with_blocking (action.widget, nullptr,
888 rfd, TRUE);
889 }
890
891 /* Set the requested status */
892 fd->cleared_match = CLEARED_ALL;
893 ppr_filter_update_status_query (rfd->plugin_page);
894 LEAVE(" ");
895}
896
905void
908{
909 g_return_if_fail (GTK_IS_BUTTON(button));
910 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
911
912 ENTER("(button %p, page %p)", button, rfd->plugin_page);
913
914 auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page);
915
916 /* Turn off all the check menu items */
917 for (const auto& action : status_actions)
918 {
919 set_checkbutton_with_blocking (action.widget, nullptr,
921 rfd, FALSE);
922 }
923
924 /* Set the requested status */
925 fd->cleared_match = CLEARED_NONE;
926 ppr_filter_update_status_query (rfd->plugin_page);
927 LEAVE(" ");
928}
929
930static void
931print_info_time64_date (const gchar *text, time64 date)
932{
933 gchar *date_txt = qof_print_date (date);
934 PINFO("%s, %s", text, date_txt);
935 g_free (date_txt);
936}
937
938static void
939get_filter_times (RegisterFilterDialog* rfd)
940{
941 time64 time_val;
942
943 auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page);
944
945 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->start_date_check)))
946 {
947 time_val = gnc_date_edit_get_date (GNC_DATE_EDIT(rfd->start_date));
948 time_val = gnc_time64_get_day_start (time_val);
949 fd->start_time = time_val;
950 fd->start_ap = GNC_ACCOUNTING_PERIOD_INVALID;
951 print_info_time64_date ("Start date is", fd->start_time);
952 }
953 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->start_relative_check)))
954 {
955 auto *sdate = gnc_period_select_get_date (GNC_PERIOD_SELECT(rfd->start_relative));
956 fd->start_time = gnc_time64_get_day_start_gdate (sdate);
957 fd->start_ap = gnc_period_select_get_active (GNC_PERIOD_SELECT(rfd->start_relative));
958 print_info_time64_date ("Start date relative is", fd->start_time);
959 g_date_free (sdate);
960 }
961 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->start_days_check)))
962 {
963 fd->start_days = gtk_spin_button_get_value (GTK_SPIN_BUTTON(rfd->start_days));
964 fd->start_time = get_time_for_days_ago (fd->start_days, true);
965 fd->start_ap = GNC_ACCOUNTING_PERIOD_INVALID;
966 print_info_time64_date ("Start date using days is", fd->start_time);
967 }
968 else
969 fd->start_time = 0;
970
971 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->end_date_check)))
972 {
973 time_val = gnc_date_edit_get_date (GNC_DATE_EDIT(rfd->end_date));
974 time_val = gnc_time64_get_day_end (time_val);
975 fd->end_time = time_val;
976 fd->end_ap = GNC_ACCOUNTING_PERIOD_INVALID;
977 print_info_time64_date ("End date is", fd->end_time);
978 }
979 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->end_relative_check)))
980 {
981 auto *edate = gnc_period_select_get_date (GNC_PERIOD_SELECT(rfd->end_relative));
982 fd->end_time = gnc_time64_get_day_end_gdate (edate);
983 fd->end_ap = gnc_period_select_get_active (GNC_PERIOD_SELECT(rfd->end_relative));
984 print_info_time64_date ("End date relative is", fd->end_time);
985 g_date_free (edate);
986 }
987 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->end_days_check)))
988 {
989 fd->end_days = gtk_spin_button_get_value (GTK_SPIN_BUTTON(rfd->end_days));
990 fd->end_time = get_time_for_days_ago (fd->end_days, false);
991 fd->end_ap = GNC_ACCOUNTING_PERIOD_INVALID;
992 print_info_time64_date ("End date using days is", fd->end_time);
993 }
994 else
995 fd->end_time = 0;
996}
997
1008void
1009gnc_ppr_filter_select_range_cb (GtkRadioButton* button,
1011{
1012 g_return_if_fail (GTK_IS_RADIO_BUTTON(button));
1013 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
1014
1015 ENTER("(button %p, page %p)", button, rfd->plugin_page);
1016
1017 auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page);
1018
1019 auto name = gtk_buildable_get_name (GTK_BUILDABLE(button));
1020 gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(button));
1021
1022 if (active && g_strcmp0 (name, "filter_show_range") == 0)
1023 {
1024 gtk_widget_set_sensitive (rfd->table, active);
1025 gtk_widget_set_sensitive (rfd->num_days, !active);
1026 get_filter_times (rfd);
1027 }
1028 else if (active && g_strcmp0 (name, "filter_show_days") == 0)
1029 {
1030 gtk_widget_set_sensitive (rfd->table, !active);
1031 gtk_widget_set_sensitive (rfd->num_days, active);
1032 fd->days = gtk_spin_button_get_value (GTK_SPIN_BUTTON(rfd->num_days));
1033 }
1034 else
1035 {
1036 gtk_widget_set_sensitive (rfd->table, FALSE);
1037 gtk_widget_set_sensitive (rfd->num_days, FALSE);
1038 set_filterdata_to_defaults (fd, true);
1039 }
1040 ppr_filter_update_date_query (rfd->plugin_page);
1041 LEAVE(" ");
1042}
1043
1053void
1054gnc_ppr_filter_days_changed_cb (GtkSpinButton* button,
1056{
1057 g_return_if_fail (GTK_IS_SPIN_BUTTON(button));
1058 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
1059
1060 ENTER("(button %p, page %p)", button, rfd->plugin_page);
1061
1062 auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page);
1063
1064 fd->days = gtk_spin_button_get_value (GTK_SPIN_BUTTON(button));
1065 ppr_filter_update_date_query (rfd->plugin_page);
1066
1067 LEAVE(" ");
1068}
1069
1070static void
1071ppr_filter_gde_changed_cb (GtkWidget* unused,
1073{
1074 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
1075
1076 ENTER("(widget %s(%p), page %p)",
1077 gtk_buildable_get_name (GTK_BUILDABLE(unused)), unused, rfd->plugin_page);
1078
1079 get_filter_times (rfd);
1080 ppr_filter_update_date_query (rfd->plugin_page);
1081
1082 LEAVE(" ");
1083}
1084
1103void
1104gnc_ppr_filter_start_cb (GtkWidget* radio,
1106{
1107 g_return_if_fail (GTK_IS_RADIO_BUTTON(radio));
1108 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
1109
1110 ENTER("(radio %s(%p), page %p)",
1111 gtk_buildable_get_name (GTK_BUILDABLE(radio)), radio, rfd->plugin_page);
1112
1113 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(radio)))
1114 {
1115 LEAVE("1st callback of pair. Defer to 2nd callback.");
1116 return;
1117 }
1118
1119 auto name = gtk_buildable_get_name (GTK_BUILDABLE(radio));
1120 gboolean active = !g_strcmp0 (name, "start_date_choose");
1121 gtk_widget_set_sensitive (rfd->start_date, active);
1122 get_filter_times (rfd);
1123 ppr_filter_update_date_query (rfd->plugin_page);
1124
1125 LEAVE(" ");
1126}
1127
1146void
1147gnc_ppr_filter_end_cb (GtkWidget* radio,
1149{
1150 g_return_if_fail (GTK_IS_RADIO_BUTTON(radio));
1151 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
1152
1153 ENTER("(radio %s(%p), page %p)",
1154 gtk_buildable_get_name (GTK_BUILDABLE(radio)), radio, rfd->plugin_page);
1155
1156 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(radio)))
1157 {
1158 LEAVE("1st callback of pair. Defer to 2nd callback.");
1159 return;
1160 }
1161
1162 auto name = gtk_buildable_get_name (GTK_BUILDABLE(radio));
1163 gboolean active = !g_strcmp0 (name, "end_date_choose");
1164 gtk_widget_set_sensitive (rfd->end_date, active);
1165 get_filter_times (rfd);
1166 ppr_filter_update_date_query (rfd->plugin_page);
1167
1168 LEAVE(" ");
1169}
1170
1171static void
1172ppr_filter_relative_changed_cb (GtkWidget *widget,
1174{
1175 g_return_if_fail (GNC_IS_PERIOD_SELECT(widget));
1176 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
1177
1178 ENTER("Period Select (%p), active_id %d, plugin_page %p",
1179 widget, gnc_period_select_get_active (GNC_PERIOD_SELECT(widget)),
1180 rfd->plugin_page);
1181
1182 get_filter_times (rfd);
1183 ppr_filter_update_date_query (rfd->plugin_page);
1184
1185 LEAVE(" ");
1186}
1187
1197void
1200{
1201 g_return_if_fail (GTK_IS_SPIN_BUTTON(button));
1202 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
1203
1204 ENTER("(button %p, page %p)", button, rfd->plugin_page);
1205
1206 auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page);
1207
1208 auto name = gtk_buildable_get_name (GTK_BUILDABLE(button));
1209
1210 if (g_strcmp0 (name, "start_days_spin") == 0)
1211 fd->start_days = gtk_spin_button_get_value (GTK_SPIN_BUTTON(button));
1212
1213 if (g_strcmp0 (name, "end_days_spin") == 0)
1214 fd->end_days = gtk_spin_button_get_value (GTK_SPIN_BUTTON(button));
1215
1216 get_filter_times (rfd);
1217 ppr_filter_update_date_query (rfd->plugin_page);
1218
1219 LEAVE(" ");
1220}
1221
1230void
1231gnc_ppr_filter_start_toggle_cb (GtkToggleButton* button,
1233{
1234 g_return_if_fail (GTK_IS_CHECK_BUTTON(button));
1235 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
1236
1237 ENTER("Start toggle button (%p), plugin_page %p", button, rfd->plugin_page);
1238
1239 auto name = gtk_buildable_get_name (GTK_BUILDABLE(button));
1240
1241 gboolean active = gtk_toggle_button_get_active (button);
1242
1243 gtk_widget_set_sensitive (rfd->start_earliest, !active);
1244
1245 if (g_strcmp0 (name, "start_date_check") == 0)
1246 {
1247 set_sensitive_start_widget (rfd, rfd->start_date, active);
1248
1249 set_checkbutton_with_blocking (rfd->start_relative_check,
1250 rfd->start_days_check,
1252 rfd, FALSE);
1253 }
1254 if (g_strcmp0 (name, "start_relative_check") == 0)
1255 {
1256 set_sensitive_start_widget (rfd, rfd->start_relative, active);
1257
1258 set_checkbutton_with_blocking (rfd->start_date_check,
1259 rfd->start_days_check,
1261 rfd, FALSE);
1262 }
1263 if (g_strcmp0 (name, "start_days_check") == 0)
1264 {
1265 set_sensitive_start_widget (rfd, rfd->start_days, active);
1266
1267 set_checkbutton_with_blocking (rfd->start_date_check,
1268 rfd->start_relative_check,
1270 rfd, FALSE);
1271 }
1272 get_filter_times (rfd);
1273 ppr_filter_update_date_query (rfd->plugin_page);
1274
1275 LEAVE(" ");
1276}
1277
1286void
1287gnc_ppr_filter_end_toggle_cb (GtkToggleButton* button,
1289{
1290 g_return_if_fail (GTK_IS_CHECK_BUTTON(button));
1291 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
1292
1293 ENTER("End toggle button (%p), plugin_page %p", button, rfd->plugin_page);
1294
1295 auto name = gtk_buildable_get_name (GTK_BUILDABLE(button));
1296
1297 gboolean active = gtk_toggle_button_get_active (button);
1298
1299 gtk_widget_set_sensitive (rfd->end_latest, !active);
1300
1301 if (g_strcmp0 (name, "end_date_check") == 0)
1302 {
1303 set_sensitive_end_widget (rfd, rfd->end_date, active);
1304
1305 set_checkbutton_with_blocking (rfd->end_relative_check,
1306 rfd->end_days_check,
1308 rfd, FALSE);
1309 }
1310 if (g_strcmp0 (name, "end_relative_check") == 0)
1311 {
1312 set_sensitive_end_widget (rfd, rfd->end_relative, active);
1313
1314 set_checkbutton_with_blocking (rfd->end_date_check,
1315 rfd->end_days_check,
1317 rfd, FALSE);
1318 }
1319 if (g_strcmp0 (name, "end_days_check") == 0)
1320 {
1321 set_sensitive_end_widget (rfd, rfd->end_days, active);
1322
1323 set_checkbutton_with_blocking (rfd->end_date_check,
1324 rfd->end_relative_check,
1326 rfd, FALSE);
1327 }
1328 get_filter_times (rfd);
1329 ppr_filter_update_date_query (rfd->plugin_page);
1330
1331 LEAVE(" ");
1332}
1333
1341void
1342gnc_ppr_filter_save_cb (GtkToggleButton* button,
1344{
1345 g_return_if_fail (GTK_IS_CHECK_BUTTON(button));
1346 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
1347
1348 ENTER("Save toggle button (%p), plugin_page %p", button, rfd->plugin_page);
1349
1350 auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page);
1351
1352 /* Compute the new save filter status */
1353 if (gtk_toggle_button_get_active (button))
1354 fd->save_filter = true;
1355 else
1356 fd->save_filter = false;
1357
1358 LEAVE(" ");
1359}
1360
1371void
1373 gint response,
1375{
1376 g_return_if_fail (GTK_IS_DIALOG(dialog));
1377 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page));
1378
1379 ENTER(" ");
1380
1381 auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page);
1382 auto gsr = gnc_plugin_page_register_get_gsr (rfd->plugin_page);
1383
1384 if ((fd->start_time > 0 && fd->end_time > 0) && (fd->start_time > fd->end_time))
1385 {
1386 auto response = gnc_ok_cancel_dialog (GTK_WINDOW(rfd->dialog),
1387 GTK_RESPONSE_CANCEL,
1388 _("The Start date is after the End date.\n"
1389 "Select Cancel to change dates.\n"));
1390 if (response == GTK_RESPONSE_CANCEL)
1391 return;
1392 }
1393
1394 if (response != GTK_RESPONSE_OK)
1395 {
1396 /* Remove the old status match */
1397 fd->cleared_match = rfd->original_cleared_match;
1398 gnc_plugin_register_set_enable_refresh (GNC_PLUGIN_PAGE_REGISTER(rfd->plugin_page), FALSE);
1399 ppr_filter_update_status_query (rfd->plugin_page);
1400 gnc_plugin_register_set_enable_refresh (GNC_PLUGIN_PAGE_REGISTER(rfd->plugin_page), TRUE);
1401
1402 fd->start_ap = rfd->original_start_ap;
1403 fd->start_time = rfd->original_start_time;
1404 fd->start_days = rfd->original_start_days;
1405 fd->end_ap = rfd->original_end_ap;
1406 fd->end_time = rfd->original_end_time;
1407 fd->end_days = rfd->original_end_days;
1408
1409 fd->days = rfd->original_days;
1410 fd->save_filter = rfd->original_save_filter;
1411 ppr_filter_update_date_query (rfd->plugin_page);
1412 }
1413 else
1414 {
1415 // clear the filter when unticking the save option
1416 if (!fd->save_filter && rfd->original_save_filter)
1417 ppr_filter_save_filter (gsr, "");
1418
1419 rfd->original_save_filter = fd->save_filter;
1420
1421 if (fd->save_filter)
1422 ppr_filter_save_filter_parts (gsr, fd);
1423 }
1424 rfd->dialog = nullptr;
1425 fd->dialog = nullptr;
1426 g_free (rfd);
1427 gtk_widget_destroy (GTK_WIDGET(dialog));
1428 LEAVE(" ");
1429}
1430
1431static GtkWidget *
1432setup_period_select (GtkBuilder *builder, gboolean start_type, const gchar *hbox_txt)
1433{
1434 GtkWidget *period_select = GTK_WIDGET(gnc_period_select_new (start_type));
1435
1436 auto hbox = GTK_WIDGET(gtk_builder_get_object (builder, hbox_txt));
1437 gtk_box_pack_start (GTK_BOX(hbox), period_select, TRUE, TRUE, 0);
1438 gtk_widget_show (period_select);
1439 gnc_period_select_set_active (GNC_PERIOD_SELECT(period_select), GNC_ACCOUNTING_PERIOD_TODAY);
1440 gtk_widget_set_sensitive (GTK_WIDGET(period_select), FALSE);
1441 return period_select;
1442}
1443
1444static GtkWidget *
1445setup_date_edit (GtkBuilder *builder, const gchar *hbox_txt)
1446{
1447 GtkWidget *date_widget = gnc_date_edit_new (gnc_time (nullptr), FALSE, FALSE);
1448 auto hbox = GTK_WIDGET(gtk_builder_get_object (builder, hbox_txt));
1449 gtk_box_pack_start (GTK_BOX(hbox), date_widget, TRUE, TRUE, 0);
1450 gtk_widget_show (date_widget);
1451 gtk_widget_set_sensitive (GTK_WIDGET(date_widget), FALSE);
1452 return date_widget;
1453}
1454
1455static void
1456ppr_filter_dialog_create (RegisterFilterDialog* rfd, FilterData *fd, Query *query)
1457{
1458 time64 start_time, end_time, time_val;
1459
1460 /* Create the dialog */
1461 auto builder = gtk_builder_new();
1462 gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", "days_adjustment");
1463 gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", "start_days_adjustment");
1464 gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", "end_days_adjustment");
1465 gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", "filter_by_dialog");
1466 auto dialog = GTK_WIDGET(gtk_builder_get_object (builder, "filter_by_dialog"));
1467 rfd->dialog = dialog;
1468 fd->dialog = rfd->dialog;
1469
1470 gtk_window_set_transient_for (GTK_WINDOW(dialog),
1471 gnc_window_get_gtk_window (GNC_WINDOW(
1472 GNC_PLUGIN_PAGE(rfd->plugin_page)->window)));
1473
1474 /* Translators: The %s is the name of the plugin page */
1475 auto title = g_strdup_printf (_ ("Filter %s by…"),
1476 gnc_plugin_page_get_page_name (rfd->plugin_page));
1477 gtk_window_set_title (GTK_WINDOW(dialog), title);
1478 g_free (title);
1479
1480 /* Set the check buttons for the current status */
1481 for (auto& action : status_actions)
1482 {
1483 auto toggle = GTK_WIDGET(gtk_builder_get_object (builder,
1484 action.action_name.c_str()));
1485 bool value = fd->cleared_match & action.value;
1486 action.widget = toggle;
1487 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(toggle), bool_to_gboolean (value));
1488 }
1489 rfd->original_cleared_match = fd->cleared_match;
1490
1491 auto button = GTK_WIDGET(gtk_builder_get_object (builder, "filter_save"));
1492 if (fd->save_filter)
1493 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), TRUE);
1494
1495 rfd->original_save_filter = fd->save_filter;
1496
1497 // hide the save button if appropriate
1498 gtk_widget_set_visible (GTK_WIDGET(button), bool_to_gboolean (rfd->show_save_button));
1499
1500 /* Set up number of days */
1501 rfd->num_days = GTK_WIDGET(gtk_builder_get_object (builder, "filter_show_num_days"));
1502 button = GTK_WIDGET(gtk_builder_get_object (builder, "filter_show_days"));
1503
1504 if (fd->days > 0) // using number of days
1505 {
1506 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), TRUE);
1507 gtk_widget_set_sensitive (GTK_WIDGET(rfd->num_days), TRUE);
1508 gtk_spin_button_set_value (GTK_SPIN_BUTTON(rfd->num_days), fd->days);
1509 rfd->original_days = fd->days;
1510
1511 /* Set the start_time and end_time to 0 */
1512 start_time = 0;
1513 end_time = 0;
1514 }
1515 else
1516 {
1517 gtk_widget_set_sensitive (GTK_WIDGET(rfd->num_days), FALSE);
1518 rfd->original_days = 0;
1519 fd->days = 0;
1520
1521 /* Get the start and end times */
1522 xaccQueryGetDateMatchTT (query, &start_time, &end_time);
1523 }
1524
1525 /* Set the date info */
1526 rfd->original_start_time = start_time;
1527 fd->start_time = start_time;
1528 rfd->original_end_time = end_time;
1529 fd->end_time = end_time;
1530
1531 button = GTK_WIDGET(gtk_builder_get_object (builder, "filter_show_range"));
1532 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), start_time || end_time);
1533 auto table = GTK_WIDGET(gtk_builder_get_object (builder, "select_range_table"));
1534 rfd->table = table;
1535 gtk_widget_set_sensitive (GTK_WIDGET(table), start_time || end_time);
1536
1537 rfd->start_earliest = GTK_WIDGET(gtk_builder_get_object (builder, "earliest_label"));
1538 rfd->start_date_check = GTK_WIDGET(gtk_builder_get_object (builder, "start_date_check"));
1539 rfd->start_relative_check = GTK_WIDGET(gtk_builder_get_object (builder, "start_relative_check"));
1540 rfd->start_days_check = GTK_WIDGET(gtk_builder_get_object (builder, "start_days_check"));
1541
1542 {
1543 rfd->start_relative = setup_period_select (builder, TRUE, "start_relative_hbox");
1544 rfd->start_date = setup_date_edit (builder, "start_date_hbox");
1545 rfd->start_days = GTK_WIDGET(gtk_builder_get_object (builder, "start_days_spin"));
1546
1547 /* Start date info */
1548 if (start_time == 0)
1549 {
1550 set_sensitive_start_widget (rfd, rfd->start_earliest, TRUE);
1551 time_val = xaccQueryGetEarliestDateFound (query);
1552 }
1553 else
1554 {
1555 rfd->original_start_ap = fd->start_ap;
1556 if (fd->start_ap != GNC_ACCOUNTING_PERIOD_INVALID)
1557 {
1558 set_sensitive_start_widget (rfd, rfd->start_relative, TRUE);
1559 gnc_period_select_set_active (GNC_PERIOD_SELECT(rfd->start_relative), fd->start_ap);
1560 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->start_relative_check), TRUE);
1561 }
1562 else if (fd->start_days != 0)
1563 {
1564 set_sensitive_start_widget (rfd, rfd->start_days, TRUE);
1565 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->start_days_check), TRUE);
1566 gtk_spin_button_set_value (GTK_SPIN_BUTTON(rfd->start_days), fd->start_days);
1567 rfd->original_start_days = fd->start_days;
1568
1569 }
1570 else
1571 {
1572 set_sensitive_start_widget (rfd, rfd->start_date, TRUE);
1573 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->start_date_check), TRUE);
1574 }
1575 time_val = start_time;
1576 }
1577 g_signal_connect (G_OBJECT(rfd->start_relative), "changed",
1578 G_CALLBACK(ppr_filter_relative_changed_cb), rfd);
1579
1580 if (time_val == 0)
1581 time_val = gnc_time64_get_today_start();
1582 gnc_date_edit_set_time (GNC_DATE_EDIT(rfd->start_date), time_val);
1583 g_signal_connect (G_OBJECT(rfd->start_date), "date-changed",
1584 G_CALLBACK(ppr_filter_gde_changed_cb), rfd);
1585 }
1586
1587 rfd->end_latest = GTK_WIDGET(gtk_builder_get_object (builder, "latest_label"));
1588 rfd->end_date_check = GTK_WIDGET(gtk_builder_get_object (builder, "end_date_check"));
1589 rfd->end_relative_check = GTK_WIDGET(gtk_builder_get_object (builder, "end_relative_check"));
1590 rfd->end_days_check = GTK_WIDGET(gtk_builder_get_object (builder, "end_days_check"));
1591
1592 {
1593 rfd->end_relative = setup_period_select (builder, FALSE, "end_relative_hbox");
1594 rfd->end_date = setup_date_edit (builder, "end_date_hbox");
1595 rfd->end_days = GTK_WIDGET(gtk_builder_get_object (builder, "end_days_spin"));
1596
1597 /* End date info */
1598 if (end_time == 0)
1599 {
1600 set_sensitive_end_widget (rfd, rfd->end_latest, TRUE);
1601 time_val = xaccQueryGetLatestDateFound (query);
1602 }
1603 else
1604 {
1605 rfd->original_end_ap = fd->end_ap;
1606 if (fd->end_ap != GNC_ACCOUNTING_PERIOD_INVALID)
1607 {
1608 set_sensitive_end_widget (rfd, rfd->end_relative, TRUE);
1609 gnc_period_select_set_active (GNC_PERIOD_SELECT(rfd->end_relative), fd->end_ap);
1610 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->end_relative_check), TRUE);
1611 }
1612 else if (fd->end_days != 0)
1613 {
1614 set_sensitive_end_widget (rfd, rfd->end_days, TRUE);
1615 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->end_days_check), TRUE);
1616 gtk_spin_button_set_value (GTK_SPIN_BUTTON(rfd->end_days), fd->end_days);
1617 rfd->original_end_days = fd->end_days;
1618 }
1619 else
1620 {
1621 set_sensitive_end_widget (rfd, rfd->end_date, TRUE);
1622 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->end_date_check), TRUE);
1623 }
1624 time_val = end_time;
1625 }
1626 g_signal_connect (G_OBJECT(rfd->end_relative), "changed",
1627 G_CALLBACK(ppr_filter_relative_changed_cb), rfd);
1628
1629 if (time_val == 0)
1630 time_val = gnc_time64_get_today_end();
1631 gnc_date_edit_set_time (GNC_DATE_EDIT(rfd->end_date), time_val);
1632 g_signal_connect (G_OBJECT(rfd->end_date), "date-changed",
1633 G_CALLBACK(ppr_filter_gde_changed_cb), rfd);
1634 }
1635
1636 /* Wire it up */
1637 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, rfd);
1638
1639 /* Show it */
1640 gtk_widget_show (dialog);
1641 g_object_unref (G_OBJECT(builder));
1642 LEAVE (" ");
1643}
1644
1656void
1658 FilterData *fd, bool show_save_button)
1659{
1661
1662 ENTER(" ");
1663
1664 rfd = g_new0 (RegisterFilterDialog, 1);
1665
1666 rfd->plugin_page = plugin_page;
1667 rfd->show_save_button = show_save_button;
1668
1669 ppr_filter_dialog_create (rfd, fd, query);
1670
1671 LEAVE(" ");
1672}
Date and Time handling routines.
GLib helper routines.
Functions for adding content to a window.
A custom widget for selecting accounting periods.
Functions providing a register page filter for the GnuCash UI.
Functions providing a register page for the GnuCash UI.
Generic api to store and retrieve preferences.
Functions to load, save and get gui state.
utility functions for the GnuCash UI
Functions that are supported by all types of windows.
const gchar * gnc_plugin_page_get_page_name(GncPluginPage *page)
Retrieve the name of this page.
time64 gnc_mktime(struct tm *time)
calculate seconds from the epoch given a time struct
Definition gnc-date.cpp:219
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
char * qof_print_date(time64 t)
Convenience; calls through to qof_print_date_dmy_buff().
Definition gnc-date.cpp:610
time64 gnc_time64_get_day_start(time64 time_val)
The gnc_time64_get_day_start() routine will take the given time in seconds and adjust it to the first...
time64 gnc_time64_get_today_start(void)
The gnc_time64_get_today_start() routine returns a time64 value corresponding to the first second of ...
time64 gnc_time64_get_day_end(time64 time_val)
The gnc_time64_get_day_end() routine will take the given time in seconds and adjust it to the last se...
void gnc_tm_get_today_end(struct tm *tm)
The gnc_tm_get_today_end() routine takes a pointer to a struct tm and fills it in with the last secon...
void gnc_tm_free(struct tm *time)
free a struct tm* created with gnc_localtime() or gnc_gmtime()
Definition gnc-date.cpp:97
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
struct tm * gnc_localtime(const time64 *secs)
fill out a time struct from a 64-bit time value.
Definition gnc-date.cpp:103
time64 gnc_time64_get_day_end_gdate(const GDate *date)
The gnc_time64_get_day_end() routine will take the given time in GLib GDate format and adjust it to t...
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...
void gnc_tm_get_today_start(struct tm *tm)
The gnc_tm_get_today_start() routine takes a pointer to a struct tm and fills it in with the first se...
time64 gnc_time64_get_today_end(void)
The gnc_time64_get_today_end() routine returns a time64 value corresponding to the last second of tod...
GDate * gnc_period_select_get_date(GncPeriodSelect *period)
Get the currently selected accounting period choice from a GncPeriodSelect widget.
GncAccountingPeriod
This specifies a time interval.
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.
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.
gint gnc_state_drop_sections_for(const gchar *partial_name)
Drop all sections from the state file whose name contains partial_name.
Definition gnc-state.c:260
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition gnc-state.c:248
SplitRegister * gnc_ledger_display_get_split_register(GNCLedgerDisplay *ld)
return the split register associated with a ledger display
gchar * gnc_list_formatter(GList *strings)
This function takes a GList of char*, and uses locale-sensitive list formatter.
gchar * gnc_g_list_stringjoin(GList *list_of_strings, const gchar *sep)
Return a string joining a GList whose elements are gchar* strings.
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#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
void qof_query_purge_terms(QofQuery *q, QofQueryParamList *param_list)
Remove query terms of a particular type from q.
Definition qofquery.cpp:705
void gnc_ppr_filter_start_toggle_cb(GtkToggleButton *button, RegisterFilterDialog *rfd)
This function is called when one of the check buttons for start relative or start date is changed.
void gnc_ppr_filter_days_changed_cb(GtkSpinButton *button, RegisterFilterDialog *rfd)
This function is called when the "number of days" spin button is changed which is then saved and upda...
void gnc_ppr_filter_status_clear_all_cb(GtkButton *button, RegisterFilterDialog *rfd)
This function is called whenever the "clear all" status button is clicked.
void gnc_ppr_filter_select_range_cb(GtkRadioButton *button, RegisterFilterDialog *rfd)
This function is called when the radio buttons changes state.
void gnc_plugin_page_register_update_for_search_query(GncPluginPageRegister *page)
This checks if the register is a search register and if so saves the query.
void gnc_ppr_filter_clear_current_filter(GncPluginPage *plugin_page)
This function is used to clear the current filter so that a specific split can be shown in the regist...
void gnc_ppr_filter_response_cb(GtkDialog *dialog, gint response, RegisterFilterDialog *rfd)
This function is called when the "Filter By…" dialog is closed.
FilterData * gnc_plugin_page_register_get_filter_data(GncPluginPage *plugin_page)
Get the FilterData data structure associated with this register page.
void gnc_ppr_filter_set_tooltip(GncPluginPage *plugin_page, FilterData *fd)
This function is used to update the tooltip shown in the register which shows a summary of the curren...
Query * gnc_plugin_page_register_get_query(GncPluginPage *plugin_page)
This function is called to get the query associated with this plugin page.
void gnc_ppr_filter_by(GncPluginPage *plugin_page, Query *query, FilterData *fd, bool show_save_button)
This function is called for the filter dialog.
void gnc_ppr_filter_end_toggle_cb(GtkToggleButton *button, RegisterFilterDialog *rfd)
This function is called when one of the check buttons for end relative or end date is changed.
void gnc_ppr_filter_start_end_days_changed_cb(GtkSpinButton *button, RegisterFilterDialog *rfd)
This function is called when the "days ago" spin button is changed which is then saved and updates th...
void gnc_ppr_filter_update_register(GncPluginPage *plugin_page)
This function is called to update the register.
void gnc_plugin_page_register_query_update(GncPluginPageRegister *page, Query *query)
This updates the query after the filters have been applied.
void gnc_ppr_filter_status_one_cb(GtkToggleButton *button, RegisterFilterDialog *rfd)
This function is called whenever one of the status entries is checked or unchecked.
void gnc_ppr_filter_save_cb(GtkToggleButton *button, RegisterFilterDialog *rfd)
This function is called whenever the save status is checked or unchecked.
void gnc_ppr_filter_end_cb(GtkWidget *radio, RegisterFilterDialog *rfd)
This function is called when one of the end date radio buttons is selected.
GNCSplitReg * gnc_plugin_page_register_get_gsr(GncPluginPage *plugin_page)
Get the GNCSplitReg data structure associated with this register page.
void gnc_ppr_filter_start_cb(GtkWidget *radio, RegisterFilterDialog *rfd)
This function is called when one of the start date radio buttons is selected.
void gnc_plugin_register_set_enable_refresh(GncPluginPageRegister *page, gboolean enable_refresh)
This allows controlling when refreshes happen, used to reduce refreshes when different aspects of the...
void gnc_ppr_filter_status_select_all_cb(GtkButton *button, RegisterFilterDialog *rfd)
This function is called whenever the "select all" status button is clicked.
The instance data structure for a content plugin.
A Query.
Definition qofquery.cpp:75