gnucash stable: Multiple changes pushed

Christopher Lam clam at code.gnucash.org
Sat Apr 22 02:33:24 EDT 2023


Updated	 via  https://github.com/Gnucash/gnucash/commit/81b16aed (commit)
	 via  https://github.com/Gnucash/gnucash/commit/48ca7081 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e26c3d6c (commit)
	from  https://github.com/Gnucash/gnucash/commit/dee27223 (commit)



commit 81b16aedd867898529b8aa01689c668f73365291
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu Apr 13 21:49:21 2023 +0800

    [gnc-tree-view-account.c] add tooltip with balance_limit explanation

diff --git a/gnucash/gnome-utils/gnc-tree-view-account.c b/gnucash/gnome-utils/gnc-tree-view-account.c
index b7fb5d3f12..b3a4d53f5f 100644
--- a/gnucash/gnome-utils/gnc-tree-view-account.c
+++ b/gnucash/gnome-utils/gnc-tree-view-account.c
@@ -24,6 +24,7 @@
 
 #include <config.h>
 
+#include <stdbool.h>
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
 #include <string.h>
@@ -90,6 +91,9 @@ static void acc_color_data_func (GtkTreeViewColumn *col,
 static void gnc_tree_view_account_color_update (gpointer gsettings,
          gchar *key, gpointer user_data);
 
+static gboolean
+gnc_tree_view_tooltip_cb (GtkWidget *widget, gint x, gint y, gboolean keyboard_tip,
+                          GtkTooltip *tooltip, gpointer user_data);
 
 typedef struct GncTreeViewAccountPrivate
 {
@@ -770,6 +774,7 @@ gnc_tree_view_account_new_with_root (Account *root, gboolean show_root)
     ENTER(" ");
     /* Create our view */
     view = g_object_new (GNC_TYPE_TREE_VIEW_ACCOUNT,
+                         "has-tooltip", true,
                          "name", "gnc-id-account-tree", NULL);
 
     priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(GNC_TREE_VIEW_ACCOUNT (view));
@@ -1049,6 +1054,9 @@ gnc_tree_view_account_new_with_root (Account *root, gboolean show_root)
     /* Set account find-as-you-type search function */
     gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW(view), gnc_tree_view_search_compare, NULL, NULL);
 
+    g_signal_connect (G_OBJECT(view), "query-tooltip",
+                      G_CALLBACK(gnc_tree_view_tooltip_cb), NULL);
+
     gtk_widget_show(GTK_WIDGET(view));
     LEAVE("%p", view);
     return GTK_TREE_VIEW(view);
@@ -2891,3 +2899,54 @@ void gnc_tree_view_account_set_editing_finished_cb(GncTreeViewAccount *view,
     gnc_tree_view_set_editing_finished_cb (GNC_TREE_VIEW(view),
             editing_finished_cb, editing_cb_data);
 }
+
+
+static gboolean
+gnc_tree_view_tooltip_cb (GtkWidget *widget, gint x, gint y, gboolean keyboard_tip,
+                          GtkTooltip *tooltip, gpointer user_data)
+{
+    GtkTreeView *tree_view = GTK_TREE_VIEW(widget);
+    GtkTreePath *path  = NULL;
+    GtkTreeViewColumn *column = NULL;
+    gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y, &x, &y);
+    if (keyboard_tip || !gtk_tree_view_get_path_at_pos (tree_view, x, y, &path,
+                                                        &column, NULL, NULL))
+    {
+        gtk_tree_path_free (path);
+        return false;
+    }
+
+    // Get the iter pointing to our current column
+    gboolean show_tooltip = false;
+    GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
+    GtkTreeIter iter;
+    if (gtk_tree_model_get_iter (model, &iter, path) && column)
+    {
+        gchar *ttip = NULL;
+
+        // Select text based on column
+        switch (gtk_tree_view_column_get_sort_column_id (column))
+        {
+        case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_LIMIT:
+            gtk_tree_model_get (model, &iter,
+                                GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_LIMIT_EXPLANATION, &ttip,
+                                -1);
+            break;
+        default:
+            break;
+        }
+
+        // Did we select any text? If yes, display the tooltip
+        if (ttip && *ttip)
+        {
+            show_tooltip = true;
+            gtk_tooltip_set_text (tooltip, ttip);
+            gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, column, NULL);
+        }
+        g_free (ttip);
+    }
+
+    // Clean up the object
+    gtk_tree_path_free (path);
+    return show_tooltip;
+}

commit 48ca708135a7ecbc4ca91781de4fb5ef1ad5d632
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu Apr 13 21:07:08 2023 +0800

    [gnc-tree-model-account.c] GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_LIMIT_EXPLANATION

diff --git a/gnucash/gnome-utils/gnc-tree-model-account.c b/gnucash/gnome-utils/gnc-tree-model-account.c
index 0d993aa2f8..0347b30718 100644
--- a/gnucash/gnome-utils/gnc-tree-model-account.c
+++ b/gnucash/gnome-utils/gnc-tree-model-account.c
@@ -395,6 +395,7 @@ gnc_tree_model_account_get_column_type (GtkTreeModel *tree_model, int index)
     case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_REPORT:
     case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_PERIOD:
     case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_LIMIT:
+    case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_LIMIT_EXPLANATION:
     case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED:
     case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED_REPORT:
     case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED:
@@ -837,6 +838,12 @@ gnc_tree_model_account_get_value (GtkTreeModel *tree_model,
         g_value_take_string (value, string);
         break;
 
+    case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_LIMIT_EXPLANATION:
+        g_value_init (value, G_TYPE_STRING);
+        string = gnc_ui_account_get_balance_limit_explanation (account);
+        g_value_take_string (value, string);
+        break;
+
     case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED:
         g_value_init (value, G_TYPE_STRING);
         string = gnc_ui_account_get_print_balance (xaccAccountGetClearedBalanceInCurrency,
diff --git a/gnucash/gnome-utils/gnc-tree-model-account.h b/gnucash/gnome-utils/gnc-tree-model-account.h
index 5fcd42836f..a9c83d112a 100644
--- a/gnucash/gnome-utils/gnc-tree-model-account.h
+++ b/gnucash/gnome-utils/gnc-tree-model-account.h
@@ -67,6 +67,7 @@ typedef enum
     GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_REPORT,
     GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_PERIOD,
     GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_LIMIT,
+    GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_LIMIT_EXPLANATION,
     GNC_TREE_MODEL_ACCOUNT_COL_CLEARED,
     GNC_TREE_MODEL_ACCOUNT_COL_CLEARED_REPORT,
     GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED,

commit e26c3d6cf419a14a0ef10085776251e594d4da21
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed Apr 12 00:02:59 2023 +0800

    [gnc-ui-balances.c] gnc_ui_account_get_balance_limit_explanation
    
    returns a char* explanation, or NULL

diff --git a/libgnucash/app-utils/gnc-ui-balances.c b/libgnucash/app-utils/gnc-ui-balances.c
index ed857d9696..0451ca7626 100644
--- a/libgnucash/app-utils/gnc-ui-balances.c
+++ b/libgnucash/app-utils/gnc-ui-balances.c
@@ -250,16 +250,20 @@ gnc_ui_account_get_reconciled_balance_as_of_date (Account *account,
                                            xaccAccountGetReconciledBalanceAsOfDate);
 }
 
+// retrieve account's balance to compare against the limit.
+// we use today's date because account may have future dated splits
+static gnc_numeric
+account_balance_for_limit (const Account *account)
+{
+    return gnc_ui_account_get_balance_as_of_date
+        ((Account*)account, gnc_time64_get_day_end (gnc_time (NULL)),
+         xaccAccountGetIncludeSubAccountBalances (account));
+}
+
 static gint
 account_balance_limit_reached (const Account *account, gnc_numeric balance_limit)
 {
-    gboolean inc_sub = xaccAccountGetIncludeSubAccountBalances (account);
-
-    // we use today's date because account may have future dated splits
-    gnc_numeric balance = gnc_ui_account_get_balance_as_of_date (
-                              (Account*)account,
-                              gnc_time64_get_day_end (gnc_time (NULL)),
-                              inc_sub);
+    gnc_numeric balance = account_balance_for_limit (account);
 
     if (gnc_numeric_zero_p (balance))
         return 0;
@@ -271,6 +275,16 @@ account_balance_limit_reached (const Account *account, gnc_numeric balance_limit
     return gnc_numeric_compare (balance, balance_limit);
 }
 
+static gboolean
+get_limit_info (const Account *account, gnc_numeric *limit, gboolean higher)
+{
+    gboolean reverse = gnc_reverse_balance (account);
+    if ((higher && reverse) || (!higher && !reverse))
+        return xaccAccountGetLowerBalanceLimit (account, limit);
+    else
+        return xaccAccountGetHigherBalanceLimit (account, limit);
+}
+
 gboolean
 gnc_ui_account_is_higher_balance_limit_reached (const Account *account,
                                                 gboolean *is_zero)
@@ -281,10 +295,7 @@ gnc_ui_account_is_higher_balance_limit_reached (const Account *account,
 
     g_return_val_if_fail (GNC_IS_ACCOUNT(account), FALSE);
 
-    if (gnc_reverse_balance (account))
-        limit_valid = xaccAccountGetLowerBalanceLimit (account, &balance_limit);
-    else
-        limit_valid = xaccAccountGetHigherBalanceLimit (account, &balance_limit);
+    limit_valid = get_limit_info (account, &balance_limit, TRUE);
 
     if (!limit_valid)
         return retval;
@@ -308,10 +319,7 @@ gnc_ui_account_is_lower_balance_limit_reached (const Account *account,
 
     g_return_val_if_fail (GNC_IS_ACCOUNT(account), FALSE);
 
-    if (gnc_reverse_balance (account))
-        limit_valid = xaccAccountGetHigherBalanceLimit (account, &balance_limit);
-    else
-        limit_valid = xaccAccountGetLowerBalanceLimit (account, &balance_limit);
+    limit_valid = get_limit_info (account, &balance_limit, FALSE);
 
     if (!limit_valid)
         return retval;
@@ -325,33 +333,76 @@ gnc_ui_account_is_lower_balance_limit_reached (const Account *account,
     return retval;
 }
 
-gchar *
-gnc_ui_account_get_balance_limit_icon_name (const Account *account)
+static gchar *
+make_limit_explanation (const Account *account, const char* template_str,
+                        gboolean zero, gboolean higher)
+{
+    gnc_commodity *currency = xaccAccountGetCommodity (account);
+    GNCPrintAmountInfo pinfo = gnc_commodity_print_info (currency, TRUE);
+    gnc_numeric acct_bal = account_balance_for_limit (account);
+    char *fullname = gnc_account_get_full_name (account);
+    char *bal_str = g_strdup (xaccPrintAmount (acct_bal, pinfo));
+    char *rv;
+    if (zero)
+        rv = g_strdup_printf (_(template_str), fullname, bal_str);
+    else
+    {
+        gnc_numeric limit;
+        get_limit_info (account, &limit, higher);
+        if (gnc_reverse_balance (account))
+            limit = gnc_numeric_neg (limit);
+        char *lim_str = g_strdup (xaccPrintAmount (limit, pinfo));
+        rv = g_strdup_printf (_(template_str), fullname, bal_str, lim_str);
+        g_free (lim_str);
+    }
+    g_free (bal_str);
+    g_free (fullname);
+    return rv;
+}
+
+static gchar *
+get_balance_limit_info (const Account *account, gboolean icon)
 {
     gboolean lower_limit_reached, higher_limit_reached;
     gboolean lower_is_zero = FALSE;
     gboolean higher_is_zero = FALSE;
+    const char *higher_template = N_("%s balance is %s, exceeds limit of %s.");
+    const char *lower_template = N_("%s balance is %s, subceeds limit of %s.");
+    const char *zero_template = N_("%s balance is %s, and should be zero.");
 
-    g_return_val_if_fail (GNC_IS_ACCOUNT(account), g_strdup (""));
+    g_return_val_if_fail (GNC_IS_ACCOUNT(account), NULL);
 
     higher_limit_reached = gnc_ui_account_is_higher_balance_limit_reached (account, &higher_is_zero);
 
     // assume the higher value will be set mostly so test that first
     if (higher_limit_reached && !higher_is_zero)
-        return g_strdup ("go-top");
+        return icon ? g_strdup ("go-top") : make_limit_explanation (account, higher_template, FALSE, TRUE);
 
     lower_limit_reached = gnc_ui_account_is_lower_balance_limit_reached (account, &lower_is_zero);
 
     if (lower_limit_reached && (!lower_is_zero || !higher_is_zero))
-        return g_strdup ("go-bottom");
+        return icon ? g_strdup ("go-bottom") : make_limit_explanation (account, lower_template, FALSE, FALSE);
 
     if (higher_limit_reached && !lower_is_zero)
-        return g_strdup ("go-top");
+        return icon ? g_strdup ("go-top") : make_limit_explanation (account, higher_template, FALSE, TRUE);
 
     if ((lower_limit_reached || higher_limit_reached ) && lower_is_zero && higher_is_zero)
-        return g_strdup ("dialog-warning");
+        return icon ? g_strdup ("dialog-warning") : make_limit_explanation (account, zero_template, TRUE, FALSE);
+
+    return NULL;
+}
 
-    return g_strdup ("");
+gchar *
+gnc_ui_account_get_balance_limit_icon_name (const Account *account)
+{
+    char *icon = get_balance_limit_info (account, TRUE);
+    return icon ? icon : g_strdup ("");
+}
+
+gchar *
+gnc_ui_account_get_balance_limit_explanation (const Account *account)
+{
+    return get_balance_limit_info (account, FALSE);
 }
 
 /********************************************************************
diff --git a/libgnucash/app-utils/gnc-ui-balances.h b/libgnucash/app-utils/gnc-ui-balances.h
index f0b4d55166..b80c626275 100644
--- a/libgnucash/app-utils/gnc-ui-balances.h
+++ b/libgnucash/app-utils/gnc-ui-balances.h
@@ -186,4 +186,15 @@ gboolean gnc_ui_account_is_lower_balance_limit_reached (const Account *account,
  */
 gchar * gnc_ui_account_get_balance_limit_icon_name (const Account *account);
 
+
+/** Test the account balance as of today for it passing the
+ *  lower and higher limits if set.
+ *
+ *  @param account A pointer to the account.
+ *
+ *  @return An explanation for balance limit warning, or NULL if there
+ *  are no limits, or balance is within limits.
+ */
+gchar * gnc_ui_account_get_balance_limit_explanation (const Account *account);
+
 #endif /* GNC_UI_BALANCES_H_ */



Summary of changes:
 gnucash/gnome-utils/gnc-tree-model-account.c |  7 ++
 gnucash/gnome-utils/gnc-tree-model-account.h |  1 +
 gnucash/gnome-utils/gnc-tree-view-account.c  | 59 +++++++++++++++++
 libgnucash/app-utils/gnc-ui-balances.c       | 97 +++++++++++++++++++++-------
 libgnucash/app-utils/gnc-ui-balances.h       | 11 ++++
 5 files changed, 152 insertions(+), 23 deletions(-)



More information about the gnucash-changes mailing list