From 35822232ca40fc5680ea95dbbca7c1fb5092e6b8 Mon Sep 17 00:00:00 2001 From: Robert Fewell <14uBobIT@gmail.com> Date: Sun, 7 Jun 2026 10:22:31 +0100 Subject: [PATCH] Bug 421610 - Include logical dates in View->Filter Change the register filter option 'Today' radio button to be a period select widget. This will give some predefined relative options that are the same as in the Preference dialog. --- .../gnome/gnc-plugin-page-register-filter.cpp | 604 +++++++++++++++--- .../gnome/gnc-plugin-page-register-filter.hpp | 18 +- .../gtkbuilder/gnc-plugin-page-register.glade | 213 +++--- 3 files changed, 652 insertions(+), 183 deletions(-) diff --git a/gnucash/gnome/gnc-plugin-page-register-filter.cpp b/gnucash/gnome/gnc-plugin-page-register-filter.cpp index 2e84c12b8c..5ca2bd5672 100644 --- a/gnucash/gnome/gnc-plugin-page-register-filter.cpp +++ b/gnucash/gnome/gnc-plugin-page-register-filter.cpp @@ -38,7 +38,9 @@ #include "gnc-date.h" #include "gnc-date-edit.h" #include "gnc-glib-utils.h" +#include "gnc-ui.h" #include "gnc-state.h" +#include "gnc-period-select.h" #include "gnc-prefs.h" #include "gnc-ui-util.h" #include "gnc-window.h" @@ -70,21 +72,35 @@ struct RegisterFilterDialog GncPluginPage* plugin_page; GtkWidget* dialog; GtkWidget* table; - GtkWidget* start_date_choose; - GtkWidget* start_date_today; - GtkWidget* start_date; - GtkWidget* end_date_choose; - GtkWidget* end_date_today; + GtkWidget* start_earliest; //label + GtkWidget* start_relative_check; //checkbutton + GtkWidget* start_relative; //account period + GtkWidget* start_date_check; //checkbutton + GtkWidget* start_date; //date + GtkWidget* start_days_check; //checkbutton + GtkWidget* start_days; //spin + + GtkWidget* end_latest; + GtkWidget* end_relative_check; + GtkWidget* end_relative; + GtkWidget* end_date_check; GtkWidget* end_date; - GtkWidget* num_days; + GtkWidget* end_days_check; + GtkWidget* end_days; - cleared_match_t original_cleared_match; - time64 original_start_time; - time64 original_end_time; - int original_days; - bool original_save_filter; + GtkWidget* num_days; - bool show_save_button; + cleared_match_t original_cleared_match; + GncAccountingPeriod original_start_ap; + time64 original_start_time; + int original_start_days; + GncAccountingPeriod original_end_ap; + time64 original_end_time; + int original_end_days; + int original_days; + bool original_save_filter; + + bool show_save_button; }; extern "C" @@ -119,6 +135,15 @@ gnc_ppr_filter_save_cb (GtkToggleButton* button, void gnc_ppr_filter_days_changed_cb (GtkSpinButton* button, RegisterFilterDialog* rfd); +void +gnc_ppr_filter_start_toggle_cb (GtkToggleButton* button, + RegisterFilterDialog* rfd); +void +gnc_ppr_filter_end_toggle_cb (GtkToggleButton* button, + RegisterFilterDialog* rfd); +void +gnc_ppr_filter_start_end_days_changed_cb (GtkSpinButton* button, + RegisterFilterDialog* rfd); } struct status_action @@ -191,6 +216,25 @@ ppr_filter_dmy2time (std::string date_string) return gnc_mktime (&when); } +/* This function subtracts a number of days from now to a time64 value */ +static time64 +get_time_for_days_ago (int days, bool use_day_start) +{ + time64 time_val = 0; + + if (days > 0) + { + struct tm tm; + if (use_day_start) + gnc_tm_get_today_start (&tm); + else + gnc_tm_get_today_end (&tm); + tm.tm_mday = tm.tm_mday - days; + time_val = gnc_mktime (&tm); + } + return time_val; +} + static std::vector split_filter_by_delimiter (std::string str, char delimiter) { @@ -245,19 +289,96 @@ ppr_filter_load_filter (GNCSplitReg *gsr, GNCLedgerDisplayType ledger_type) } static void -set_filterdata_to_defaults (FilterData *fd) +set_filterdata_to_defaults (FilterData *fd, bool date_parts_only) { - fd->cleared_match = (cleared_match_t)std::stol (DEFAULT_FILTER, nullptr, 16); + if (!date_parts_only) + { + fd->cleared_match = (cleared_match_t)std::stol (DEFAULT_FILTER, nullptr, 16); + fd->save_filter = false; + } + fd->start_ap = GNC_ACCOUNTING_PERIOD_INVALID; fd->start_time = 0; + fd->start_days = 0; + fd->end_ap = GNC_ACCOUNTING_PERIOD_INVALID; fd->end_time = 0; + fd->end_days = 0; fd->days = 0; - fd->save_filter = false; +} + +static int +get_trailing_int (const std::string split_filter, const std::string find_text) +{ + int ret_int = -1; + std::size_t found = split_filter.find (find_text); + + if (found != std::string::npos) + { + std::string found_str = split_filter.substr (found + find_text.length(), std::string::npos); + ret_int = std::stol (found_str, nullptr, 10); + } + return ret_int; +} + +static void +update_fd_with_date_filter_parts (FilterData *fd, const std::string filter_part, + bool start_filter, int ap_trailing_int, int days_trailing_int) +{ + if (ap_trailing_int != -1) + { + GDate *tmp_date = nullptr; + + if (start_filter) + { + fd->start_ap = (GncAccountingPeriod)ap_trailing_int; + tmp_date = gnc_accounting_period_start_gdate (fd->start_ap, nullptr, nullptr); + } + else + { + fd->end_ap = (GncAccountingPeriod)ap_trailing_int; + tmp_date = gnc_accounting_period_end_gdate (fd->end_ap, nullptr, nullptr); + } + + if (tmp_date) + { + if (start_filter) + fd->start_time = gnc_time64_get_day_start_gdate (tmp_date); + else + fd->end_time = gnc_time64_get_day_end_gdate (tmp_date); + + g_date_free (tmp_date); + } + } + else + { + if (days_trailing_int != -1) + { + if (start_filter) + { + fd->start_days = days_trailing_int; + fd->start_time = get_time_for_days_ago (fd->start_days, true); + } + else + { + fd->end_days = days_trailing_int; + fd->end_time = get_time_for_days_ago (fd->end_days, false); + } + } + else + { + time64 tmp_time = ppr_filter_dmy2time (filter_part); + if (start_filter) + fd->start_time = gnc_time64_get_day_start (tmp_time); + else + fd->end_time = gnc_time64_get_day_end (tmp_time); + } + } + fd->save_filter = true; } static void ppr_filter_load_filter_parts (GNCSplitReg *gsr, GNCLedgerDisplayType ledger_type, FilterData *fd) { - set_filterdata_to_defaults (fd); + set_filterdata_to_defaults (fd, false); fd->dialog = nullptr; if (!gsr) @@ -282,18 +403,20 @@ ppr_filter_load_filter_parts (GNCSplitReg *gsr, GNCLedgerDisplayType ledger_type { PINFO("Loaded Filter Start Date is %s", split_filter[1].c_str()); - fd->start_time = ppr_filter_dmy2time (split_filter[1]); - fd->start_time = gnc_time64_get_day_start (fd->start_time); - fd->save_filter = true; + int ap_trailing_int = get_trailing_int (split_filter[1], "SAP"); + int days_trailing_int = get_trailing_int (split_filter[1], "SDAY"); + + update_fd_with_date_filter_parts (fd, split_filter[1], true, ap_trailing_int, days_trailing_int); } if (split_filter_size > 2 && (split_filter[2].compare (std::string ("0"))) != 0) { PINFO("Loaded Filter End Date is %s", split_filter[2].c_str()); - fd->end_time = ppr_filter_dmy2time (split_filter[2]); - fd->end_time = gnc_time64_get_day_end (fd->end_time); - fd->save_filter = true; + int ap_trailing_int = get_trailing_int (split_filter[2], "EAP"); + int days_trailing_int = get_trailing_int (split_filter[1], "EDAY"); + + update_fd_with_date_filter_parts (fd, split_filter[2], false, ap_trailing_int, days_trailing_int); } // set the default for the number of days @@ -356,18 +479,22 @@ ppr_filter_save_filter_parts (GNCSplitReg *gsr, FilterData *fd) save_filter_str.append (buffer); // start time - if (fd->start_time != 0) - { + if (fd->start_ap != GNC_ACCOUNTING_PERIOD_INVALID) + save_filter_str.append (";SAP" + std::to_string (fd->start_ap)); + else if (fd->start_days > 0) + save_filter_str.append (";SDAY" + std::to_string (fd->start_days)); + else if (fd->start_time != 0) save_filter_str.append (";" + ppr_filter_time2dmy (fd->start_time)); - } else save_filter_str.append (";0"); // end time - if (fd->end_time != 0) - { + if (fd->end_ap != GNC_ACCOUNTING_PERIOD_INVALID) + save_filter_str.append (";EAP" + std::to_string (fd->end_ap)); + else if (fd->end_days > 0) + save_filter_str.append (";EDAY" + std::to_string (fd->end_days)); + else if (fd->end_time != 0) save_filter_str.append (";" + ppr_filter_time2dmy (fd->end_time)); - } else save_filter_str.append (";0"); @@ -580,13 +707,7 @@ ppr_filter_update_date_query (GncPluginPage* plugin_page) if (fd->days > 0) { - time64 start; - struct tm tm; - - gnc_tm_get_today_start (&tm); - - tm.tm_mday = tm.tm_mday - fd->days; - start = gnc_mktime (&tm); + time64 start = get_time_for_days_ago (fd->days, true); xaccQueryAddDateMatchTT (query, TRUE, start, FALSE, 0, QOF_QUERY_AND); } @@ -610,7 +731,7 @@ gnc_ppr_filter_clear_current_filter (GncPluginPage* plugin_page) auto fd = gnc_plugin_page_register_get_filter_data (plugin_page); - set_filterdata_to_defaults (fd); + set_filterdata_to_defaults (fd, false); ppr_filter_update_date_query (plugin_page); } @@ -643,7 +764,7 @@ gnc_ppr_filter_update_register (GncPluginPage* plugin_page) SplitRegister *reg = gnc_ledger_display_get_split_register (gsr->ledger); if (reg->type != GENERAL_JOURNAL) // search ledger and the like - set_filterdata_to_defaults (fd); + set_filterdata_to_defaults (fd, false); } /* Update Query with Filter Status and Dates */ ppr_filter_update_status_query (plugin_page); @@ -695,18 +816,49 @@ gnc_ppr_filter_status_one_cb (GtkToggleButton* button, } static void -set_checkbutton_with_blocking (GtkWidget *widget, +set_sensitive_start_widget (RegisterFilterDialog *rfd, GtkWidget *enable_widget, gboolean active) +{ + gtk_widget_set_sensitive (GTK_WIDGET(rfd->start_earliest), !active); + gtk_widget_set_sensitive (GTK_WIDGET(rfd->start_relative), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET(rfd->start_date), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET(rfd->start_days), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET(enable_widget), active); +} + +static void +set_sensitive_end_widget (RegisterFilterDialog *rfd, GtkWidget *enable_widget, gboolean active) +{ + gtk_widget_set_sensitive (GTK_WIDGET(rfd->end_latest), !active); + gtk_widget_set_sensitive (GTK_WIDGET(rfd->end_relative), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET(rfd->end_date), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET(rfd->end_days), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET(enable_widget), active); +} + +static void +set_checkbutton_with_blocking (GtkWidget *widget1, GtkWidget *widget2, GFunc function, RegisterFilterDialog *rfd, gboolean active) { PINFO("Block GtkToggleButton %p for setting active %s", - widget, active ? "TRUE" : "FALSE"); - g_signal_handlers_block_by_func (widget, + widget1, active ? "TRUE" : "FALSE"); + g_signal_handlers_block_by_func (widget1, (gpointer)function, rfd); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), active); - g_signal_handlers_unblock_by_func (widget, + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget1), active); + g_signal_handlers_unblock_by_func (widget1, (gpointer)function, rfd); + + if (widget2) + { + PINFO("Block GtkToggleButton %p for setting active %s", + widget2, active ? "TRUE" : "FALSE"); + g_signal_handlers_block_by_func (widget2, + (gpointer)function, rfd); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget2), active); + g_signal_handlers_unblock_by_func (widget2, + (gpointer)function, rfd); + } } /** This function is called whenever the "select all" status button is @@ -731,7 +883,7 @@ gnc_ppr_filter_status_select_all_cb (GtkButton* button, /* Turn on all the check menu items */ for (const auto& action : status_actions) { - set_checkbutton_with_blocking (action.widget, + set_checkbutton_with_blocking (action.widget, nullptr, (GFunc)gnc_ppr_filter_status_one_cb, rfd, TRUE); } @@ -764,7 +916,7 @@ gnc_ppr_filter_status_clear_all_cb (GtkButton* button, /* Turn off all the check menu items */ for (const auto& action : status_actions) { - set_checkbutton_with_blocking (action.widget, + set_checkbutton_with_blocking (action.widget, nullptr, (GFunc)gnc_ppr_filter_status_one_cb, rfd, FALSE); } @@ -775,6 +927,14 @@ gnc_ppr_filter_status_clear_all_cb (GtkButton* button, LEAVE(" "); } +static void +print_info_time64_date (const gchar *text, time64 date) +{ + gchar *date_txt = qof_print_date (date); + PINFO("%s, %s", text, date_txt); + g_free (date_txt); +} + static void get_filter_times (RegisterFilterDialog* rfd) { @@ -782,33 +942,55 @@ get_filter_times (RegisterFilterDialog* rfd) auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page); - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->start_date_choose))) + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->start_date_check))) { time_val = gnc_date_edit_get_date (GNC_DATE_EDIT(rfd->start_date)); time_val = gnc_time64_get_day_start (time_val); fd->start_time = time_val; + fd->start_ap = GNC_ACCOUNTING_PERIOD_INVALID; + print_info_time64_date ("Start date is", fd->start_time); } - else + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->start_relative_check))) { - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->start_date_today))) - fd->start_time = gnc_time64_get_today_start(); - else - fd->start_time = 0; + auto *sdate = gnc_period_select_get_date (GNC_PERIOD_SELECT(rfd->start_relative)); + fd->start_time = gnc_time64_get_day_start_gdate (sdate); + fd->start_ap = gnc_period_select_get_active (GNC_PERIOD_SELECT(rfd->start_relative)); + print_info_time64_date ("Start date relative is", fd->start_time); + g_date_free (sdate); } + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->start_days_check))) + { + fd->start_time = get_time_for_days_ago (fd->start_days, true); + fd->start_ap = GNC_ACCOUNTING_PERIOD_INVALID; + print_info_time64_date ("Start date using days is", fd->start_time); + } + else + fd->start_time = 0; - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->end_date_choose))) + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->end_date_check))) { time_val = gnc_date_edit_get_date (GNC_DATE_EDIT(rfd->end_date)); time_val = gnc_time64_get_day_end (time_val); fd->end_time = time_val; + fd->end_ap = GNC_ACCOUNTING_PERIOD_INVALID; + print_info_time64_date ("End date is", fd->end_time); } - else + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->end_relative_check))) { - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->end_date_today))) - fd->end_time = gnc_time64_get_today_end(); - else - fd->end_time = 0; + auto *edate = gnc_period_select_get_date (GNC_PERIOD_SELECT(rfd->end_relative)); + fd->end_time = gnc_time64_get_day_end_gdate (edate); + fd->end_ap = gnc_period_select_get_active (GNC_PERIOD_SELECT(rfd->end_relative)); + print_info_time64_date ("End date relative is", fd->end_time); + g_date_free (edate); + } + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rfd->end_days_check))) + { + fd->end_time = get_time_for_days_ago (fd->end_days, false); + fd->end_ap = GNC_ACCOUNTING_PERIOD_INVALID; + print_info_time64_date ("End date using days is", fd->end_time); } + else + fd->end_time = 0; } /** This function is called when the radio buttons changes state. This @@ -851,9 +1033,7 @@ gnc_ppr_filter_select_range_cb (GtkRadioButton* button, { gtk_widget_set_sensitive (rfd->table, FALSE); gtk_widget_set_sensitive (rfd->num_days, FALSE); - fd->start_time = 0; - fd->end_time = 0; - fd->days = 0; + set_filterdata_to_defaults (fd, true); } ppr_filter_update_date_query (rfd->plugin_page); LEAVE(" "); @@ -986,6 +1166,169 @@ gnc_ppr_filter_end_cb (GtkWidget* radio, LEAVE(" "); } +static void +ppr_filter_relative_changed_cb (GtkWidget *widget, + RegisterFilterDialog* rfd) +{ + g_return_if_fail (GNC_IS_PERIOD_SELECT(widget)); + g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page)); + + ENTER("Period Select (%p), active_id %d, plugin_page %p", + widget, gnc_period_select_get_active (GNC_PERIOD_SELECT(widget)), + rfd->plugin_page); + + get_filter_times (rfd); + ppr_filter_update_date_query (rfd->plugin_page); + + LEAVE(" "); +} + +/** This function is called when the "days ago" spin button is + * changed which is then saved and updates the time limitation on + * the register query. This is handled by a helper function as + * potentially all widgets will need to be examined. + * + * @param button A pointer to the "days ago" spin button. + * + * @param rfd A pointer to the filter dialog structure. + */ +void +gnc_ppr_filter_start_end_days_changed_cb (GtkSpinButton* button, + RegisterFilterDialog* rfd) +{ + g_return_if_fail (GTK_IS_SPIN_BUTTON(button)); + g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page)); + + ENTER("(button %p, page %p)", button, rfd->plugin_page); + + auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page); + + auto name = gtk_buildable_get_name (GTK_BUILDABLE(button)); + + if (g_strcmp0 (name, "start_days_spin") == 0) + fd->start_days = gtk_spin_button_get_value (GTK_SPIN_BUTTON(button)); + + if (g_strcmp0 (name, "end_days_spin") == 0) + fd->end_days = gtk_spin_button_get_value (GTK_SPIN_BUTTON(button)); + + get_filter_times (rfd); + ppr_filter_update_date_query (rfd->plugin_page); + + LEAVE(" "); +} + +/** This function is called when one of the check buttons for start + * relative or start date is changed. It activates the associated + * widget and deactivates the other. + * + * @param button A pointer to a GtkToggleButton widget. + * + * @param rfd A pointer to the filter dialog structure. + */ +void +gnc_ppr_filter_start_toggle_cb (GtkToggleButton* button, + RegisterFilterDialog* rfd) +{ + g_return_if_fail (GTK_IS_CHECK_BUTTON(button)); + g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page)); + + ENTER("Start toggle button (%p), plugin_page %p", button, rfd->plugin_page); + + auto name = gtk_buildable_get_name (GTK_BUILDABLE(button)); + + gboolean active = gtk_toggle_button_get_active (button); + + gtk_widget_set_sensitive (rfd->start_earliest, !active); + + if (g_strcmp0 (name, "start_date_check") == 0) + { + set_sensitive_start_widget (rfd, rfd->start_date, active); + + set_checkbutton_with_blocking (rfd->start_relative_check, + rfd->start_days_check, + (GFunc)gnc_ppr_filter_start_toggle_cb, + rfd, FALSE); + } + if (g_strcmp0 (name, "start_relative_check") == 0) + { + set_sensitive_start_widget (rfd, rfd->start_relative, active); + + set_checkbutton_with_blocking (rfd->start_date_check, + rfd->start_days_check, + (GFunc)gnc_ppr_filter_start_toggle_cb, + rfd, FALSE); + } + if (g_strcmp0 (name, "start_days_check") == 0) + { + set_sensitive_start_widget (rfd, rfd->start_days, active); + + set_checkbutton_with_blocking (rfd->start_date_check, + rfd->start_relative_check, + (GFunc)gnc_ppr_filter_start_toggle_cb, + rfd, FALSE); + } + get_filter_times (rfd); + ppr_filter_update_date_query (rfd->plugin_page); + + LEAVE(" "); +} + +/** This function is called when one of the check buttons for end + * relative or end date is changed. It activates the associated + * widget and deactivates the other. + * + * @param button A pointer to a GtkToggleButton widget. + * + * @param rfd A pointer to the filter dialog structure. + */ +void +gnc_ppr_filter_end_toggle_cb (GtkToggleButton* button, + RegisterFilterDialog* rfd) +{ + g_return_if_fail (GTK_IS_CHECK_BUTTON(button)); + g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(rfd->plugin_page)); + + ENTER("End toggle button (%p), plugin_page %p", button, rfd->plugin_page); + + auto name = gtk_buildable_get_name (GTK_BUILDABLE(button)); + + gboolean active = gtk_toggle_button_get_active (button); + + gtk_widget_set_sensitive (rfd->end_latest, !active); + + if (g_strcmp0 (name, "end_date_check") == 0) + { + set_sensitive_end_widget (rfd, rfd->end_date, active); + + set_checkbutton_with_blocking (rfd->end_relative_check, + rfd->end_days_check, + (GFunc)gnc_ppr_filter_end_toggle_cb, + rfd, FALSE); + } + if (g_strcmp0 (name, "end_relative_check") == 0) + { + set_sensitive_end_widget (rfd, rfd->end_relative, active); + + set_checkbutton_with_blocking (rfd->end_date_check, + rfd->end_days_check, + (GFunc)gnc_ppr_filter_end_toggle_cb, + rfd, FALSE); + } + if (g_strcmp0 (name, "end_days_check") == 0) + { + set_sensitive_end_widget (rfd, rfd->end_days, active); + + set_checkbutton_with_blocking (rfd->end_date_check, + rfd->end_relative_check, + (GFunc)gnc_ppr_filter_end_toggle_cb, + rfd, FALSE); + } + get_filter_times (rfd); + ppr_filter_update_date_query (rfd->plugin_page); + + LEAVE(" "); +} + /** This function is called whenever the save status is checked * or unchecked. It will allow saving of the filter if required. * @@ -1036,6 +1379,16 @@ gnc_ppr_filter_response_cb (GtkDialog* dialog, auto fd = gnc_plugin_page_register_get_filter_data (rfd->plugin_page); auto gsr = gnc_plugin_page_register_get_gsr (rfd->plugin_page); + if ((fd->start_time > 0 && fd->end_time > 0) && (fd->start_time > fd->end_time)) + { + auto response = gnc_ok_cancel_dialog (GTK_WINDOW(rfd->dialog), + GTK_RESPONSE_CANCEL, + _("The Start date is after the End date.\n" + "Select Cancel to change dates.\n")); + if (response == GTK_RESPONSE_CANCEL) + return; + } + if (response != GTK_RESPONSE_OK) { /* Remove the old status match */ @@ -1043,8 +1396,14 @@ gnc_ppr_filter_response_cb (GtkDialog* dialog, gnc_plugin_register_set_enable_refresh (GNC_PLUGIN_PAGE_REGISTER(rfd->plugin_page), FALSE); ppr_filter_update_status_query (rfd->plugin_page); gnc_plugin_register_set_enable_refresh (GNC_PLUGIN_PAGE_REGISTER(rfd->plugin_page), TRUE); + + fd->start_ap = rfd->original_start_ap; fd->start_time = rfd->original_start_time; + fd->start_days = rfd->original_start_days; + fd->end_ap = rfd->original_end_ap; fd->end_time = rfd->original_end_time; + fd->end_days = rfd->original_end_days; + fd->days = rfd->original_days; fd->save_filter = rfd->original_save_filter; ppr_filter_update_date_query (rfd->plugin_page); @@ -1067,6 +1426,30 @@ gnc_ppr_filter_response_cb (GtkDialog* dialog, LEAVE(" "); } +static GtkWidget * +setup_period_select (GtkBuilder *builder, gboolean start_type, const gchar *hbox_txt) +{ + GtkWidget *period_select = GTK_WIDGET(gnc_period_select_new (start_type)); + + auto hbox = GTK_WIDGET(gtk_builder_get_object (builder, hbox_txt)); + gtk_box_pack_start (GTK_BOX(hbox), period_select, TRUE, TRUE, 0); + gtk_widget_show (period_select); + gnc_period_select_set_active (GNC_PERIOD_SELECT(period_select), GNC_ACCOUNTING_PERIOD_TODAY); + gtk_widget_set_sensitive (GTK_WIDGET(period_select), FALSE); + return period_select; +} + +static GtkWidget * +setup_date_edit (GtkBuilder *builder, const gchar *hbox_txt) +{ + GtkWidget *date_widget = gnc_date_edit_new (gnc_time (nullptr), FALSE, FALSE); + auto hbox = GTK_WIDGET(gtk_builder_get_object (builder, hbox_txt)); + gtk_box_pack_start (GTK_BOX(hbox), date_widget, TRUE, TRUE, 0); + gtk_widget_show (date_widget); + gtk_widget_set_sensitive (GTK_WIDGET(date_widget), FALSE); + return date_widget; +} + static void ppr_filter_dialog_create (RegisterFilterDialog* rfd, FilterData *fd, Query *query) { @@ -1074,10 +1457,10 @@ ppr_filter_dialog_create (RegisterFilterDialog* rfd, FilterData *fd, Query *quer /* Create the dialog */ auto builder = gtk_builder_new(); - gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", - "days_adjustment"); - gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", - "filter_by_dialog"); + gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", "days_adjustment"); + gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", "start_days_adjustment"); + gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", "end_days_adjustment"); + gnc_builder_add_from_file (builder, "gnc-plugin-page-register.glade", "filter_by_dialog"); auto dialog = GTK_WIDGET(gtk_builder_get_object (builder, "filter_by_dialog")); rfd->dialog = dialog; fd->dialog = rfd->dialog; @@ -1149,75 +1532,100 @@ ppr_filter_dialog_create (RegisterFilterDialog* rfd, FilterData *fd, Query *quer rfd->table = table; gtk_widget_set_sensitive (GTK_WIDGET(table), start_time || end_time); - rfd->start_date_choose = GTK_WIDGET(gtk_builder_get_object (builder, "start_date_choose")); - rfd->start_date_today = GTK_WIDGET(gtk_builder_get_object (builder, "start_date_today")); - rfd->end_date_choose = GTK_WIDGET(gtk_builder_get_object (builder, "end_date_choose")); - rfd->end_date_today = GTK_WIDGET(gtk_builder_get_object (builder, "end_date_today")); + rfd->start_earliest = GTK_WIDGET(gtk_builder_get_object (builder, "earliest_label")); + rfd->start_date_check = GTK_WIDGET(gtk_builder_get_object (builder, "start_date_check")); + rfd->start_relative_check = GTK_WIDGET(gtk_builder_get_object (builder, "start_relative_check")); + rfd->start_days_check = GTK_WIDGET(gtk_builder_get_object (builder, "start_days_check")); - bool sensitive; { + rfd->start_relative = setup_period_select (builder, TRUE, "start_relative_hbox"); + rfd->start_date = setup_date_edit (builder, "start_date_hbox"); + rfd->start_days = GTK_WIDGET(gtk_builder_get_object (builder, "start_days_spin")); + /* Start date info */ if (start_time == 0) { - button = GTK_WIDGET(gtk_builder_get_object(builder, "start_date_earliest")); + set_sensitive_start_widget (rfd, rfd->start_earliest, TRUE); time_val = xaccQueryGetEarliestDateFound (query); - sensitive = false; } else { - time_val = start_time; - if ((start_time >= gnc_time64_get_today_start()) && - (start_time <= gnc_time64_get_today_end())) + rfd->original_start_ap = fd->start_ap; + if (fd->start_ap != GNC_ACCOUNTING_PERIOD_INVALID) { - button = rfd->start_date_today; - sensitive = false; + set_sensitive_start_widget (rfd, rfd->start_relative, TRUE); + gnc_period_select_set_active (GNC_PERIOD_SELECT(rfd->start_relative), fd->start_ap); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->start_relative_check), TRUE); + } + else if (fd->start_days != 0) + { + set_sensitive_start_widget (rfd, rfd->start_days, TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->start_days_check), TRUE); + gtk_spin_button_set_value (GTK_SPIN_BUTTON(rfd->start_days), fd->start_days); + rfd->original_start_days = fd->start_days; + } else { - button = rfd->start_date_choose; - sensitive = true; + set_sensitive_start_widget (rfd, rfd->start_date, TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->start_date_check), TRUE); } + time_val = start_time; } - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), TRUE); - rfd->start_date = gnc_date_edit_new (gnc_time (nullptr), FALSE, FALSE); - auto hbox = GTK_WIDGET(gtk_builder_get_object (builder, "start_date_hbox")); - gtk_box_pack_start (GTK_BOX(hbox), rfd->start_date, TRUE, TRUE, 0); - gtk_widget_show (rfd->start_date); - gtk_widget_set_sensitive (GTK_WIDGET(rfd->start_date), bool_to_gboolean (sensitive)); + g_signal_connect (G_OBJECT(rfd->start_relative), "changed", + G_CALLBACK(ppr_filter_relative_changed_cb), rfd); + + if (time_val == 0) + time_val = gnc_time64_get_today_start(); gnc_date_edit_set_time (GNC_DATE_EDIT(rfd->start_date), time_val); g_signal_connect (G_OBJECT(rfd->start_date), "date-changed", G_CALLBACK(ppr_filter_gde_changed_cb), rfd); } + rfd->end_latest = GTK_WIDGET(gtk_builder_get_object (builder, "latest_label")); + rfd->end_date_check = GTK_WIDGET(gtk_builder_get_object (builder, "end_date_check")); + rfd->end_relative_check = GTK_WIDGET(gtk_builder_get_object (builder, "end_relative_check")); + rfd->end_days_check = GTK_WIDGET(gtk_builder_get_object (builder, "end_days_check")); + { + rfd->end_relative = setup_period_select (builder, FALSE, "end_relative_hbox"); + rfd->end_date = setup_date_edit (builder, "end_date_hbox"); + rfd->end_days = GTK_WIDGET(gtk_builder_get_object (builder, "end_days_spin")); + /* End date info */ if (end_time == 0) { - button = GTK_WIDGET(gtk_builder_get_object (builder, "end_date_latest")); + set_sensitive_end_widget (rfd, rfd->end_latest, TRUE); time_val = xaccQueryGetLatestDateFound (query); - sensitive = false; } else { - time_val = end_time; - if ((end_time >= gnc_time64_get_today_start()) && - (end_time <= gnc_time64_get_today_end())) + rfd->original_end_ap = fd->end_ap; + if (fd->end_ap != GNC_ACCOUNTING_PERIOD_INVALID) + { + set_sensitive_end_widget (rfd, rfd->end_relative, TRUE); + gnc_period_select_set_active (GNC_PERIOD_SELECT(rfd->end_relative), fd->end_ap); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->end_relative_check), TRUE); + } + else if (fd->end_days != 0) { - button = rfd->end_date_today; - sensitive = false; + set_sensitive_end_widget (rfd, rfd->end_days, TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->end_days_check), TRUE); + gtk_spin_button_set_value (GTK_SPIN_BUTTON(rfd->end_days), fd->end_days); + rfd->original_end_days = fd->end_days; } else { - button = rfd->end_date_choose; - sensitive = true; + set_sensitive_end_widget (rfd, rfd->end_date, TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rfd->end_date_check), TRUE); } + time_val = end_time; } - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), TRUE); - rfd->end_date = gnc_date_edit_new (gnc_time (nullptr), FALSE, FALSE); - auto hbox = GTK_WIDGET(gtk_builder_get_object (builder, "end_date_hbox")); - gtk_box_pack_start (GTK_BOX(hbox), rfd->end_date, TRUE, TRUE, 0); - gtk_widget_show (rfd->end_date); - gtk_widget_set_sensitive (GTK_WIDGET(rfd->end_date), bool_to_gboolean (sensitive)); + g_signal_connect (G_OBJECT(rfd->end_relative), "changed", + G_CALLBACK(ppr_filter_relative_changed_cb), rfd); + + if (time_val == 0) + time_val = gnc_time64_get_today_end(); gnc_date_edit_set_time (GNC_DATE_EDIT(rfd->end_date), time_val); g_signal_connect (G_OBJECT(rfd->end_date), "date-changed", G_CALLBACK(ppr_filter_gde_changed_cb), rfd); diff --git a/gnucash/gnome/gnc-plugin-page-register-filter.hpp b/gnucash/gnome/gnc-plugin-page-register-filter.hpp index d90620a45f..ad19190696 100644 --- a/gnucash/gnome/gnc-plugin-page-register-filter.hpp +++ b/gnucash/gnome/gnc-plugin-page-register-filter.hpp @@ -34,18 +34,22 @@ #define __GNC_PLUGIN_PAGE_REGISTER_FILTER_HPP #include -#include "gnc-split-reg.h" +#include "gnc-accounting-period.h" #include "gnc-plugin-page.h" #include struct FilterData { - GtkWidget* dialog; - cleared_match_t cleared_match; - time64 start_time; - time64 end_time; - int days; - bool save_filter; + GtkWidget* dialog; + cleared_match_t cleared_match; + GncAccountingPeriod start_ap; + time64 start_time; + int start_days; + GncAccountingPeriod end_ap; + time64 end_time; + int end_days; + int days; + bool save_filter; }; void gnc_ppr_filter_set_tooltip (GncPluginPage* plugin_page, struct FilterData *fd); diff --git a/gnucash/gtkbuilder/gnc-plugin-page-register.glade b/gnucash/gtkbuilder/gnc-plugin-page-register.glade index 72714b4ced..0cc909f290 100644 --- a/gnucash/gtkbuilder/gnc-plugin-page-register.glade +++ b/gnucash/gtkbuilder/gnc-plugin-page-register.glade @@ -7,6 +7,16 @@ 1 10 + + 1100 + 1 + 10 + + + 1100 + 1 + 10 + False 6 @@ -97,7 +107,7 @@ False - Show _number of days + Show _from days ago True True False @@ -155,18 +165,28 @@ If 0, all previous days included - + True False 12 3 6 + + + True + False + + + 0 + 3 + + True False - end + start Start @@ -175,129 +195,139 @@ If 0, all previous days included - - _Earliest + + Re_lative True True False - start True True - + - 1 - 0 + 0 + 1 - - Choo_se Date + + C_hoose Date True True False - start True True - + - 1 - 6 + 0 + 2 - - Toda_y + + _Days ago True True False - start True True - end_date_choose - + - 1 - 5 + 0 + 3 - - _Latest + True - True - False - start - True - True - end_date_choose - + False + + + 1 - 4 + 2 - + True False + + + - 0 + 1 + 1 + + + + + True + True + Valid range is 0 to 1100 days +If 0, all previous days included + 0 + start_days_adjustment + True + + + + 1 3 - + + Rela_tive True - False - end - End + True + False + True + True + 0 - 4 + 5 - - C_hoose Date + + Choo_se Date True True False - start True True - start_date_earliest - + - 1 - 2 + 0 + 6 - - _Today + + Days a_go True True False - start True True - start_date_earliest - + - 1 - 1 + 0 + 7 - + True False @@ -305,12 +335,12 @@ If 0, all previous days included - 2 - 2 + 1 + 6 - + True False @@ -318,36 +348,63 @@ If 0, all previous days included - 2 - 6 + 1 + 5 - - - - - - - - - - - - - - - - + + True + True + Valid range is 0 to 1100 days +If 0, all previous days included + 0 + end_days_adjustment + True + + + + 1 + 7 + - + + True + False + start + 12 + End + + + 0 + 4 + - + + True + False + start + Earliest + + + 1 + 0 + - + + True + False + start + 12 + Latest + + + 1 + 4 +