gnucash stable: Multiple changes pushed
John Ralls
jralls at code.gnucash.org
Sun Sep 10 13:45:01 EDT 2023
Updated via https://github.com/Gnucash/gnucash/commit/4dec95e6 (commit)
via https://github.com/Gnucash/gnucash/commit/a09228a8 (commit)
via https://github.com/Gnucash/gnucash/commit/637522fe (commit)
via https://github.com/Gnucash/gnucash/commit/215a16a5 (commit)
via https://github.com/Gnucash/gnucash/commit/e17345d4 (commit)
via https://github.com/Gnucash/gnucash/commit/94db524c (commit)
via https://github.com/Gnucash/gnucash/commit/83ecabeb (commit)
via https://github.com/Gnucash/gnucash/commit/c03b57b8 (commit)
via https://github.com/Gnucash/gnucash/commit/fbf5ab8b (commit)
via https://github.com/Gnucash/gnucash/commit/4ff0ac38 (commit)
via https://github.com/Gnucash/gnucash/commit/58c4d5f0 (commit)
via https://github.com/Gnucash/gnucash/commit/8a60a3cf (commit)
via https://github.com/Gnucash/gnucash/commit/2e1a8bc8 (commit)
via https://github.com/Gnucash/gnucash/commit/a31eefd6 (commit)
via https://github.com/Gnucash/gnucash/commit/c3f56e89 (commit)
via https://github.com/Gnucash/gnucash/commit/acff356f (commit)
via https://github.com/Gnucash/gnucash/commit/fe728708 (commit)
via https://github.com/Gnucash/gnucash/commit/176ff441 (commit)
via https://github.com/Gnucash/gnucash/commit/35946c8e (commit)
via https://github.com/Gnucash/gnucash/commit/eebf5055 (commit)
via https://github.com/Gnucash/gnucash/commit/b5e5a0ed (commit)
via https://github.com/Gnucash/gnucash/commit/a2bd020b (commit)
via https://github.com/Gnucash/gnucash/commit/81475489 (commit)
via https://github.com/Gnucash/gnucash/commit/fc4f4ae6 (commit)
via https://github.com/Gnucash/gnucash/commit/c284f962 (commit)
via https://github.com/Gnucash/gnucash/commit/917b4b24 (commit)
via https://github.com/Gnucash/gnucash/commit/502dcc03 (commit)
via https://github.com/Gnucash/gnucash/commit/e46195cb (commit)
via https://github.com/Gnucash/gnucash/commit/4c916ada (commit)
via https://github.com/Gnucash/gnucash/commit/30b41544 (commit)
from https://github.com/Gnucash/gnucash/commit/ccd6d5cc (commit)
commit 4dec95e64275d8e17b3b1b77d2d71912e293233c
Merge: ccd6d5ccf4 a09228a83e
Author: John Ralls <jralls at ceridwen.us>
Date: Sun Sep 10 10:44:26 2023 -0700
Merge John Ralls's 'more-stock-assistant' into stable
commit a09228a83ef39f50fb80868dc2cfaec0a6fabf8c
Author: John Ralls <jralls at ceridwen.us>
Date: Sun Sep 10 10:22:57 2023 -0700
[stock-txn-asst] Remove superflouos FieldMask::DISABLED tags
From the stock entry of stock split and reverse split templates. Since
there are other flags on the line the DISABLED flag isn't useful.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 7d0ae2a39e..8df4cdd911 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -253,7 +253,7 @@ static const TxnTypeVec long_types
"and increases the cost basis without affecting # units.")
},
{
- FieldMask::DISABLED | FieldMask::AMOUNT_DEBIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
+ FieldMask::AMOUNT_DEBIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
FieldMask::ENABLED_CREDIT | FieldMask::ALLOW_ZERO, // cash_amt
FieldMask::ENABLED_DEBIT | FieldMask::ALLOW_ZERO | FieldMask::CAPITALIZE_DEFAULT, // fees_amt
FieldMask::DISABLED, // dividend_amt
@@ -267,7 +267,7 @@ static const TxnTypeVec long_types
"record the sale using the Stock Transaction Assistant first, then record the split.")
},
{
- FieldMask::DISABLED | FieldMask::AMOUNT_CREDIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
+ FieldMask::AMOUNT_CREDIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
FieldMask::ENABLED_CREDIT | FieldMask::ALLOW_ZERO, // cash_amt
FieldMask::ENABLED_DEBIT | FieldMask::ALLOW_ZERO | FieldMask::CAPITALIZE_DEFAULT, // fees_amt
FieldMask::DISABLED, // dividend_amt
@@ -379,7 +379,7 @@ static const TxnTypeVec short_types
"0.00 value) without affecting # units.")
},
{
- FieldMask::DISABLED | FieldMask::AMOUNT_CREDIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
+ FieldMask::AMOUNT_CREDIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
FieldMask::ENABLED_CREDIT | FieldMask::ALLOW_ZERO, // cash_amt
FieldMask::ENABLED_DEBIT | FieldMask::ALLOW_ZERO | FieldMask::CAPITALIZE_DEFAULT, // fees_amt
FieldMask::DISABLED, // dividend_amt
@@ -393,7 +393,7 @@ static const TxnTypeVec short_types
"record the cover buy using the Stock Transaction Assistant first, then record the split.")
},
{
- FieldMask::DISABLED | FieldMask::AMOUNT_DEBIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
+ FieldMask::AMOUNT_DEBIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
FieldMask::ENABLED_CREDIT | FieldMask::ALLOW_ZERO, // cash_amt
FieldMask::ENABLED_DEBIT | FieldMask::ALLOW_ZERO | FieldMask::CAPITALIZE_DEFAULT, // fees_amt
FieldMask::DISABLED, // dividend_amt
commit 637522fed163982560612761adb134fd1a32571e
Author: John Ralls <jralls at ceridwen.us>
Date: Sat Sep 9 14:30:00 2023 -0700
[stock-txn-asst] Don't report account missing if it's not required.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 008be45063..7d0ae2a39e 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -618,8 +618,11 @@ StockTransactionEntry::set_fieldmask(FieldMask mask)
const char *
StockTransactionEntry::print_account() const
{
+ auto acct_required = m_enabled &&
+ !(m_allow_zero && (gnc_numeric_zero_p(m_value) ||
+ gnc_numeric_check(m_value)));
return m_account ? xaccAccountGetName(m_account) :
- m_enabled && !gnc_numeric_zero_p(m_value) ? _("missing") : "";
+ acct_required ? _("missing") : "";
}
void
commit 215a16a5e8dbd092ae8fd17d61ce86d5c2960fc6
Author: John Ralls <jralls at ceridwen.us>
Date: Sat Sep 9 14:16:05 2023 -0700
[stock-txn-asst] Add multicurrency note to introduction.
Warning the user that they're not supported.
diff --git a/gnucash/gtkbuilder/assistant-stock-transaction.glade b/gnucash/gtkbuilder/assistant-stock-transaction.glade
index 013a3f8c3e..7975d82c33 100644
--- a/gnucash/gtkbuilder/assistant-stock-transaction.glade
+++ b/gnucash/gtkbuilder/assistant-stock-transaction.glade
@@ -19,7 +19,7 @@
<property name="valign">start</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
- <property name="label" translatable="yes">This assistant will help you record a stock transaction. The transaction type (purchase, sale, dividend, distribution, return of capital, stock split) will determine the transaction splits involved in the transaction.</property>
+ <property name="label" translatable="yes">This assistant will help you record a stock transaction. The transaction type (purchase, sale, dividend, distribution, return of capital, stock split) will determine the transaction splits involved in the transaction. Note that the transaction currency will be that of the stock account and that multi-currency transactions are not supported: Only accounts in the transaction currency will be offered for cash, capital gains, dividends, and fees.</property>
<property name="wrap">True</property>
</object>
<packing>
commit e17345d4b6ccbce04a1ec75673987f61cfcc55bf
Author: John Ralls <jralls at ceridwen.us>
Date: Sat Sep 9 13:16:07 2023 -0700
[stock-txn-asst] Include a marker split in the stock account for divs.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index aa7a394bf7..008be45063 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -101,6 +101,8 @@ enum class FieldMask : unsigned
ALLOW_NEGATIVE = 1 << 6,
CAPITALIZE_DEFAULT = 1 << 7, // fees only: capitalize by default into stock acct
CAPGAINS_IN_STOCK = 1 << 8, // capg only: add a balancing split in stock acct
+ MARKER_SPLIT = 1 << 9, // stock only, place a no-amount, no-value split in the
+ // stock account to associate the income.
};
static FieldMask
@@ -191,7 +193,7 @@ static const TxnTypeVec long_types
"placeholder amount and correct it in the transaction later.")
},
{
- FieldMask::DISABLED, // stock_amt
+ FieldMask::MARKER_SPLIT, // stock_amt
FieldMask::ENABLED_DEBIT, // cash_amt
FieldMask::ENABLED_DEBIT | FieldMask::ALLOW_ZERO, // fees_amt
FieldMask::ENABLED_CREDIT, // dividend_amt
@@ -306,7 +308,7 @@ static const TxnTypeVec short_types
"amount and correct it in the transaction later.")
},
{
- FieldMask::DISABLED, // stock_amt
+ FieldMask::MARKER_SPLIT, // stock_amt
FieldMask::ENABLED_CREDIT, // cash_amt
FieldMask::ENABLED_DEBIT | FieldMask::ALLOW_ZERO, // fees_amt
FieldMask::ENABLED_DEBIT, // dividend_amt
@@ -556,6 +558,7 @@ public:
virtual void set_amount(gnc_numeric) {}
virtual gnc_numeric amount() const { return m_value; }
virtual bool has_amount() const { return false; }
+ virtual bool marker_split() const { return false; }
/* Validates that the value and for stock entry the amount meet
* the criteria set for the entry by the field mask.
*
@@ -747,6 +750,7 @@ class StockTransactionStockEntry : public StockTransactionEntry
{
bool m_amount_enabled;
gnc_numeric m_amount;
+ bool m_marker = false;
public:
StockTransactionStockEntry() :
StockTransactionEntry{}, m_amount{gnc_numeric_error(GNC_ERROR_ARG)}
@@ -766,6 +770,7 @@ public:
void create_split(Transaction *trans, AccountVec &account_commits) const override;
std::string amount_str_for_display() const override;
gnc_numeric calculate_price() const override;
+ bool marker_split() const override { return m_marker; }
};
void
@@ -776,6 +781,7 @@ StockTransactionStockEntry::set_fieldmask(FieldMask mask)
m_amount_enabled = mask & (FieldMask::AMOUNT_CREDIT | FieldMask::AMOUNT_DEBIT);
m_debit_side = mask & (FieldMask::ENABLED_DEBIT | FieldMask::AMOUNT_DEBIT);
m_input_new_balance = mask & FieldMask::INPUT_NEW_BALANCE;
+ m_marker = mask & FieldMask::MARKER_SPLIT;
}
@@ -1300,6 +1306,9 @@ StockAssistantModel::generate_list_of_splits() {
}
}
+ if (m_stock_entry->marker_split())
+ m_list_of_splits.push_back(m_stock_entry.get());
+
if (m_cash_entry->enabled())
{
m_cash_entry->validate_amount(m_logger);
commit 94db524c60d67650d5402baca307d794f3a13ff7
Author: John Ralls <jralls at ceridwen.us>
Date: Fri Sep 8 16:23:52 2023 -0700
[stokc-txn-asst] Add default currency to GncAccountSelector
Set the default currency to the transaction currency for creating
new accounts.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index e32e9fd5be..aa7a394bf7 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -1593,6 +1593,8 @@ GncAccountSelector::GncAccountSelector (GtkBuilder *builder, AccountTypeList typ
auto curr_list = accum(null_glist, currency);
gnc_account_sel_set_new_account_ability(GNC_ACCOUNT_SEL(m_selector), true);
gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(m_selector), acct_list, curr_list);
+ gnc_account_sel_set_default_new_commodity(GNC_ACCOUNT_SEL(m_selector), currency);
+ gnc_account_sel_set_new_account_modal (GNC_ACCOUNT_SEL(m_selector), true);
g_list_free(acct_list);
g_list_free(curr_list);
}
commit 83ecabebce46f0ced4b40299a480c6a4a0a76def
Author: John Ralls <jralls at ceridwen.us>
Date: Tue Sep 5 14:08:09 2023 -0700
[stock-txn-asst] Remove unused method.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index f09bbace18..e32e9fd5be 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -2225,7 +2225,6 @@ class GncFinishTreeview
GtkWidget *m_treeview;
public:
GncFinishTreeview(GtkBuilder *builder);
- void set_tooltip_column(int);
/** Extract the information from the StockTransactionEntries in
* the vector created by the model's `make_list_of_splits`
* function and write it into the list view.
@@ -2285,13 +2284,6 @@ GncFinishTreeview::GncFinishTreeview (GtkBuilder *builder) :
gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(m_treeview),
SPLIT_COL_TOOLTIP);}
-void
-GncFinishTreeview::set_tooltip_column(int column)
-{
- gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (m_treeview),
- column);
-}
-
void
GncFinishTreeview::load(const EntryVec& list_of_splits)
{
commit c03b57b8fbf9cb9388efe8d30bc350f9b9a0d988
Author: John Ralls <jralls at ceridwen.us>
Date: Thu Aug 31 18:29:22 2023 -0700
[stock-txn-asst] Doxygen documentation of classes.
And non-trivial functions.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 3411056288..f09bbace18 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -55,7 +55,8 @@
static QofLogModule log_module = GNC_MOD_ASSISTANT;
-/** The Stock Transaction Assistant guides the user through collecting the
+/**@addtogroup Stock Transaction Assistant
+ * The Stock Transaction Assistant guides the user through collecting the
* information needed to properly account for one of several types of securities
* investment transaction, including opening and closing long and short
* positions, oridinary and capital gains dividends, returns of capital,
@@ -70,15 +71,6 @@ static QofLogModule log_module = GNC_MOD_ASSISTANT;
* creates the visuals using a GtkAssistant and a class for each page type, and
* StockAssistantController handles user input events.
*
- * Depending on type a transaction is composed of some of the following splits:
- * A stock split representing the amount of units and their value in currency, a
- * cash split representing the source or disposition of that value, a fees split
- * representing commissions, fees, and taxes paid on the transaction, a dividend
- * entry representing currency paid by the issuer to its holders (or in the case
- * of a short position the currency paid by the short seller to the entity
- * borrowed from compensating them for the dividend that they would have been
- * paid had they not lent the shares), and two capital gains split representing
- * the change in currency value from the opening transaction.
*/
extern "C"
@@ -95,46 +87,8 @@ void stock_assistant_cancel_cb (GtkAssistant *gtkassistant, gpointer user_data)
static const char* GNC_PREFS_GROUP = "dialogs.stock-assistant";
static const char* ASSISTANT_STOCK_TRANSACTION_CM_CLASS = "assistant-stock-transaction";
-enum assistant_pages
-{
- PAGE_INTRO = 0,
- PAGE_TRANSACTION_DETAILS,
- PAGE_TRANSACTION_TYPE,
- PAGE_STOCK_AMOUNT,
- PAGE_STOCK_VALUE,
- PAGE_CASH,
- PAGE_FEES,
- PAGE_DIVIDEND,
- PAGE_CAPGAINS,
- PAGE_FINISH
-};
-
-enum split_cols
-{
- SPLIT_COL_ACCOUNT = 0,
- SPLIT_COL_MEMO,
- SPLIT_COL_TOOLTIP,
- SPLIT_COL_DEBIT,
- SPLIT_COL_CREDIT,
- SPLIT_COL_UNITS,
- SPLIT_COL_UNITS_COLOR,
- NUM_SPLIT_COLS
-};
-/* StockAssistantModel contains a (subclassed) StockTransactionEntry for each split to be created.
- *
- * A StockTransactionEntry contains some boolean parameters that are set from a
- * fieldmask, obtained from the corresponding element in the TxnTypeInfo for the
- * selected transaction type.
- *
- * The available transaction types are populated into
- * StockAssistantModel::m_txn_types by
- * StockAssistantModel::maybe_reset_txn_types() based on the state of the
- * account (long, short, or empty) on the seelected
- * date. StockAssistantModel::set_txn_type() then sets m_txn_type to the
- * selected template and calls StockTransactionEntry::set_fieldmask() on each of
- * its StockTransactionEntry members.
+/** A mask-enumerator for defining what information will be collected for a split.
*/
-
enum class FieldMask : unsigned
{
DISABLED = 0,
@@ -162,8 +116,11 @@ operator &(FieldMask lhs, FieldMask rhs)
return (static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs));
};
-/* The pages displayed by the assistant and which fields are enabled on each
- * page is controlled by TxnTypeInfos, one for each transaction type.
+/** class TxnTypeinfo has no functions. It contains a FieldMask
+ * corresponding to each entry in the model detailing what data will
+ * be collected for a particular transaction type, along with a name
+ * to use in the selector box and an explanation of the transaction
+ * displayed when it is selected.
*/
struct TxnTypeInfo
{
@@ -182,6 +139,7 @@ using AccountVec = std::vector<Account*>;
static const TxnTypeVec starting_types
{
+
{
FieldMask::ENABLED_DEBIT | FieldMask::AMOUNT_DEBIT, // stock_amt
FieldMask::ENABLED_CREDIT, // cash_amt
@@ -471,6 +429,12 @@ public:
const std::string& message() { return m_message; }
};
+/** @class Logger collects diagnostic messages for later display to
+ * the user. Proveds 3 categories: error, warning, and info.
+ *
+ * Functions are simple accessors and setters unless noted.
+ */
+
using Log = std::vector<LogMessage>;
class Logger
@@ -487,6 +451,11 @@ public: // compiler generated ctors & dtor are fine
void infos(std::stringstream& stream) { return write_log(stream, LogMsgType::info); }
void warnings(std::stringstream& stream) { return write_log(stream, LogMsgType::warning); }
void errors(std::stringstream& stream) { return write_log(stream, LogMsgType::error); }
+ /** Compose all of the logged messages into a bullet list, errors
+ * first, then warnings, infos last.
+ *
+ * @return std::string containing the messages.
+ */
std::string report();
};
@@ -538,10 +507,13 @@ Logger::report()
return summary.str();
}
-/** Possibly misnamed. Collects the required information to create a single
- * split in a transaction. This is the base class; there are child classes for
- * many split types.
- */
+/** @class StockTransactionEntry
+ *
+ * Holds the configuration information from the fieldmask and the data
+ * to create a single split. The base class is used for cash splits to
+ * currency accounts. Except as noted the functions are simple
+ * accessors and setters that don't need much documentation.
+*/
class StockTransactionEntry
{
@@ -565,7 +537,10 @@ public:
m_value{gnc_numeric_error(GNC_ERROR_ARG)}, m_memo{nullptr}, m_action{action} {}
StockTransactionEntry(const StockTransactionEntry&) = default;
virtual ~StockTransactionEntry() = default;
-
+ /** Set up the state variables from the FieldMask.
+ *
+ * @param A Fieldmast to configure the StockTransactionEntry.
+ */
virtual void set_fieldmask(FieldMask mask);
virtual bool enabled() const { return m_enabled; }
virtual bool debit_side() const { return m_debit_side; }
@@ -581,14 +556,48 @@ public:
virtual void set_amount(gnc_numeric) {}
virtual gnc_numeric amount() const { return m_value; }
virtual bool has_amount() const { return false; }
+ /* Validates that the value and for stock entry the amount meet
+ * the criteria set for the entry by the field mask.
+ *
+ * @param logger collects any emitted diagnostics.
+ */
virtual void validate_amount(Logger&) const;
virtual void set_balance(gnc_numeric balance) { m_balance = balance; }
virtual gnc_numeric get_balance() const { return m_balance; }
+ /* Creates a GnuCash split from the data in the entry and adds it
+ * to the transaction, adding the account to the account vector so
+ * that it can be committed when the transaction is completed.
+ *
+ * @param trans the transaction to which to add the split
+ * @param commits the list of accounts to have edits committed later.
+ */
virtual void create_split(Transaction* trans, AccountVec& commits) const;
+ /**
+ * @return a string representation of the value.
+ */
virtual const char* print_value() const;
+ /**
+ * @return a string representation of the amount.
+ */
virtual const char* print_amount(gnc_numeric amt) const;
+ /** Generate a string representation of the value. Internally uses
+ * xaccPrintAmount, which writes to a static string, so the result
+ * is copied to a std::string to prevent it being replaced by
+ * subsequent calls.
+ *
+ * @return a std:sstring containing a representation of the value.
+ */
virtual std::string amount_str_for_display() const { return ""; }
+ /** Calculate the price (amount/value) for non-currency
+ * accounts. Note that multiple currencies in stock transaction s
+ * are not supported.
+ *
+ * @return The calculated price for the Stock entry, GNC_ERROR_ARG otherwise.
+ */
virtual gnc_numeric calculate_price() const { return gnc_numeric_error(GNC_ERROR_ARG); }
+ /**
+ * @return a string representation of the price if valid.
+ */
virtual const char* print_price() const;
};
@@ -726,6 +735,14 @@ StockTransactionEntry::print_price() const
return xaccPrintAmount(price, pinfo);
}
+/** Specialized StockTransactionEntry for the stock split. Unlike the
+ * base class it has an amount separate from the value and set amount
+ * can optionally take a post-transaction balance, used to calculate
+ * the amount and split ratio for split and reverse-split
+ * transactions. Its validate_amount method first calls the base class
+ * member to validate the value then performs addtional checks on the
+ * amount and price.
+ */
class StockTransactionStockEntry : public StockTransactionEntry
{
bool m_amount_enabled;
@@ -918,6 +935,12 @@ StockTransactionStockEntry::calculate_price() const
return price;
}
+/** Specialized Entry for the stock account's capital gains split. It
+ * has only a special constructor that copies the capital cains entry
+ * then sets its account from the stock entry and flips the sign so
+ * that if the cash capital gains split is debit-side this one will be
+ * credit-side and vice-versa.
+ */
class StockTransactionStockCapGainsEntry : public StockTransactionEntry
{
public:
@@ -934,6 +957,10 @@ StockTransactionStockCapGainsEntry::StockTransactionStockCapGainsEntry(const Sto
m_account = stk_entry->account();
}
+/** Specialized Entry for fees, taxes, commissions, and so on. It can
+ * optionally create its balancing split in a user-provided account or
+ * as a 0-amount split on the stock account.
+ */
class StockTransactionFeesEntry : public StockTransactionEntry
{
bool m_capitalize;
@@ -1020,7 +1047,12 @@ using EntryVec = std::vector<StockTransactionEntry*>;
static void stock_assistant_model_date_changed_cb(GtkWidget*, void*);
static void stock_assistant_model_description_changed_cb(GtkWidget*, void*);
-/** Manages the data and actions for the assistant. */
+/** @class StockAssistantModel Manages the available transaction types
+ * based on the state of the account, the collection and validation of
+ * input data from the StockAssistantView and conversion of the data
+ * into a GnuCash transaction.
+ */
+
class StockAssistantModel
{
Account* m_acct;
@@ -1063,28 +1095,101 @@ public:
DEBUG ("StockAssistantModel destructor\n");
};
- // consider reset txn_types. return false if txn_types are still
- // current (i.e. transaction_date hasn't changed).
+ /** Selects a TxnTypevec for the user to pick from depending on
+ * whether the account has a positive, negative, or zero share
+ * balance on the selected transaction date.
+ *
+ * @return true if the account balance had changed.
+ */
bool maybe_reset_txn_types ();
+ /** Accessor function.
+ *
+ * @return The currently available transaction types or std::nullopt if it's unset.
+ */
const std::optional<TxnTypeVec>& get_txn_types() { return m_txn_types; }
+ /** Setter
+ *
+ * @param the index into the current Transaction Types indicating the selection.
+ * @return true if the selection succeeded.
+ */
bool set_txn_type (guint type_idx);
+ /** Accessor
+ *
+ * @return true if the transaction type has been set.
+ */
bool txn_type_valid() { return m_txn_type.has_value(); }
+ /** Setter
+ *
+ * @param time64 for the transaction date.
+ */
void set_transaction_date(time64 date) { m_transaction_date = date;}
+ /** Setter
+ *
+ * @param null-terminated string containing the transaction description.
+ */
void set_transaction_desc(const char* desc) { m_transaction_description = desc; }
- std::string get_new_amount_str ();
+ /** Accessor
+ *
+ * @return the selected transaction type or std::nullopt if it hasn't been set.
+ */
const std::optional<TxnTypeInfo>& txn_type() { return m_txn_type; }
+ /** Accessor
+ *
+ * return string representing the new balance in a split/reverse split transaction.
+ */
std::string get_new_amount_str () const;
+ /** Accessor.
+ *
+ * @return the Stock entry.
+ */
StockTransactionEntry* stock_entry() { return m_stock_entry.get(); }
+ /** Accessor.
+ *
+ * @return the Cash entry.
+ */
StockTransactionEntry* cash_entry() { return m_cash_entry.get(); }
+ /** Accessor.
+ *
+ * @return the Fees entry.
+ */
StockTransactionEntry* fees_entry() { return m_fees_entry.get(); }
+ /** Accessor.
+ *
+ * @return the Dividend entry.
+ */
StockTransactionEntry* dividend_entry() { return m_dividend_entry.get(); }
+ /** Accessor.
+ *
+ * @return the Capital Gains entry.
+ */
StockTransactionEntry* capgains_entry() { return m_capgains_entry.get(); }
+ /** Accessor.
+ *
+ * @return the logger.
+ */
Logger& logger() { return m_logger; }
+ /** Generate the proposed list of splits.
+ *
+ * This is used to display the proposal to the user in the last
+ * page of the assistant and to select on which entries to call
+ * `create_split`.
+ *
+ * @return A tuple containing a boolean indicating that the data
+ * passed validation, a string containing diagnostics, and a
+ * vector of the Entries to be used in the transacion.
+ */
std::tuple<bool, std::string, EntryVec> generate_list_of_splits ();
+ /** Generate a GnuCash transaction from the active entries.
+ *
+ * @return A tuple containing a boolean indicating that the
+ * transaction was created and a pointer to the new transaction.
+ */
std::tuple<bool, Transaction*> create_transaction ();
private:
+ /** Private function that adds the calculated price to the book's
+ * price database.
+ */
void add_price (QofBook *book);
- StockTransactionEntry* make_stock_split_info();
};
bool
@@ -1350,7 +1455,9 @@ get_widget (GtkBuilder *builder, const gchar * ID)
return GTK_WIDGET (obj);
}
-/* Editor widgets used in assistant pages. */
+/** C++ wrapper for the GncDateEdit control (see
+ * gnucash/gnome-utils/gnc-date-edit.h).
+ */
class GncDateEdit
{
@@ -1381,6 +1488,9 @@ GncDateEdit::connect(GCallback cb, gpointer data)
g_signal_connect(m_edit, "date_changed", cb, data);
}
+/** C++ wrapper for GncAmountEdit, see
+ * gnucash/gnome-utils/gnc-amount-edit.h.
+ */
class GncAmountEdit
{
GtkWidget *m_edit;
@@ -1449,6 +1559,9 @@ GncAmountEdit::set_owner(gpointer obj)
using AccountTypeList = std::vector<GNCAccountType>;
+/** C++ wrapper for GncAccounSel, see
+ * gnucash/gnome-utils/gnc-account-sel.h.
+ */
class GncAccountSelector
{
GtkWidget* m_selector;
@@ -1507,9 +1620,10 @@ GncAccountSelector::set_sensitive(bool sensitive)
gtk_widget_set_sensitive(m_selector, sensitive);
}
-/* Assistant page classes, one per page. */
-/* When an assistant page (a GtkContainer) is displayed it emits a
+/** GtkContainer focus signal handler.
+ *
+ * When an assistant page (a GtkContainer) is displayed it emits a
* focus signal. This handler grabs the passed-in widget so that it
* will have the initial focus instead of the first item on the
* page. The focus signal is also used by GtkContainer to handle tab
@@ -1524,8 +1638,36 @@ assistant_page_set_focus(GtkWidget* page, [[maybe_unused]]GtkDirectionType type,
gtk_widget_grab_focus(entry);
g_signal_handlers_disconnect_by_data(page, entry);
}
+/** Page classes generate the several pages of the assistant. In
+ * general they have two functions, prepare and connect, plus a
+ * callback for each widget on the page and helper functions.
+ *
+ * Pages are displayed only if the split is enabled in the transaction
+ * info. For most pages that means that the info is set to
+ * ENABLED_CREDIT or ENABLED_DEBIT, but for the stock amount page the
+ * info must be set to AMOUNT_CREDIT or AMOUNT_DEBIT. DISABLED is a
+ * placeholder as 0 is not testable.
+ *
+ * Empty entries in amount edits are treated as 0 if the TxnTypeInfo
+ * for the split has ALLOW_ZERO set. Negative numbers are permitted
+ * only if ALLOW_NEGATIVE is set; that's used for amounts where the
+ * sign cannot be determined from the transaction type (like capital
+ * gains) or where it makes sense for consistency (like the new
+ * balance for a stock split in a short position.)
+ *
+ * Prepare is called before a page is displayed and performs
+ * specializtion for the transaction type and populates widgets with
+ * already-known values; the latter may be available if the user has
+ * visited the page before for this transaction.
+ *
+ * Connect connects the page's widgets signals with the handlers that
+ * transfer data to the model.
+ */
-
+/** The Transaction Type page.
+ *
+ * This page collects the transaction type that's used to select the TxnTypeInfo that drives the rest of the process.
+ */
class PageTransType {
// transaction type page
GtkWidget * m_page;
@@ -1536,6 +1678,12 @@ public:
void prepare(StockAssistantModel* model);
int get_transaction_type_index ();
void set_transaction_types (const TxnTypeVec& txn_types);
+/** Sets the explanation text for the selected transaction type,
+ * allowing the user to make sure that the selected transaction
+ * matches what they want to do.
+ *
+ * @param transaction explanation from the tranaction type's txntypeinfo.
+ */
void set_txn_type_explanation (const gchar *txt);
void connect (StockAssistantModel *model);
void change_txn_type (StockAssistantModel *model);
@@ -1612,6 +1760,11 @@ PageTransType::connect(StockAssistantModel *model)
G_CALLBACK (page_trans_type_changed_cb), model);
}
+/** Transaction Details page. Collects the transaction date (changing
+ * of which may trigger the model to run maybe_change_txn_types if the
+ * balance on the new date is different from the balance on the prior
+ * or default date) and the transaction description.
+ */
class PageTransDeets
{
// transaction details page
@@ -1652,6 +1805,15 @@ PageTransDeets::prepare(StockAssistantModel* model)
g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_description);
}
+/** Stock Amount page. Display and the amount entered depend on the
+ * type of the transaction. It always displays the balanance on the
+ * transaction date before the transaction. For buy and sell
+ * transactions it collects the number of units bought or sold (always
+ * as a positive number) and displays the new balance. For split and
+ * reverse-split transactions it collects the balance after the
+ * transaction and computes the change in the amount of shares and the
+ * split ratio, displaying the latter.
+ */
class PageStockAmount
{
// stock amount page
@@ -1724,6 +1886,10 @@ PageStockAmount::set_stock_amount (std::string new_amount_str)
gtk_label_set_text (GTK_LABEL(m_next_amount), new_amount_str.c_str());
}
+/** Stock Value page. It collects the currency value of the stock
+ * traded and computes and displays the resulting price. It also
+ * collects the memo for the primary stock split.
+ */
class PageStockValue
{
// stock value page
@@ -1787,6 +1953,11 @@ PageStockValue::set_price (const gchar *val)
gtk_label_set_text(GTK_LABEL(this->m_price), val);
};
+/** The Cash page collects the cash account (usually corresponds the
+ * broker's cash management account), the amount of cash, and the memo
+ * for the cash split. Accounts are restricted to types ASSET and
+ * BANK.
+ */
class PageCash
{
// cash page
@@ -1836,6 +2007,11 @@ PageCash::get_memo()
return gtk_entry_get_text(GTK_ENTRY (m_memo));
}
+/** Fees page. Controls for selecting whether to capitalize
+ * (i.e. charge them to the stock value), an account selector
+ * restricted to EXPENSE accounts if not capitalized, an amount and a
+ * memo.
+ */
class PageFees
{
// fees page
@@ -1930,6 +2106,8 @@ PageFees::prepare(StockTransactionEntry* entry)
g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_value.widget());
}
+/** Dividend page, collects an amount, an INCOME account, and a memo.
+ */
class PageDividend
{
// dividend page
@@ -2028,16 +2206,30 @@ PageCapGain::prepare(StockTransactionEntry* entry)
g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_value.widget());
}
-/* The last page of the assistant shows what the resulting transaction will look
- * like.
-*/
-/* The GncFinishtreeview lays out the transaction.*/
+
+enum split_cols
+{
+ SPLIT_COL_ACCOUNT = 0,
+ SPLIT_COL_MEMO,
+ SPLIT_COL_TOOLTIP,
+ SPLIT_COL_DEBIT,
+ SPLIT_COL_CREDIT,
+ SPLIT_COL_UNITS,
+ SPLIT_COL_UNITS_COLOR,
+ NUM_SPLIT_COLS
+};
+
+/* Displays a summary of the transactions as a list. */
class GncFinishTreeview
{
GtkWidget *m_treeview;
public:
GncFinishTreeview(GtkBuilder *builder);
void set_tooltip_column(int);
+ /** Extract the information from the StockTransactionEntries in
+ * the vector created by the model's `make_list_of_splits`
+ * function and write it into the list view.
+ */
void load(const EntryVec& list_of_splits);
};
@@ -2096,7 +2288,8 @@ GncFinishTreeview::GncFinishTreeview (GtkBuilder *builder) :
void
GncFinishTreeview::set_tooltip_column(int column)
{
-
+ gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (m_treeview),
+ column);
}
void
@@ -2139,6 +2332,9 @@ GncFinishTreeview::load(const EntryVec& list_of_splits)
}
}
+/** Finish page. Displays the List View summarizing the transaction
+ * along with any diagnostic messages recorded by the model's logger.
+ */
class PageFinish
{
// finish page
@@ -2164,8 +2360,21 @@ PageFinish::prepare (GtkWidget *window, StockAssistantModel *model)
gtk_assistant_set_page_complete(GTK_ASSISTANT(window), m_page, success);
}
-/* The StockAssistantView contains the pages and manages displaying them one at a time. */
+enum assistant_pages
+{
+ PAGE_INTRO = 0,
+ PAGE_TRANSACTION_DETAILS,
+ PAGE_TRANSACTION_TYPE,
+ PAGE_STOCK_AMOUNT,
+ PAGE_STOCK_VALUE,
+ PAGE_CASH,
+ PAGE_FEES,
+ PAGE_DIVIDEND,
+ PAGE_CAPGAINS,
+ PAGE_FINISH
+};
+/** Contains the pages and manages displaying them one at a time. */
class StockAssistantView {
GtkWidget * m_window;
@@ -2181,7 +2390,18 @@ class StockAssistantView {
public:
StockAssistantView(GtkBuilder *builder, Account* account, GtkWidget *parent);
~StockAssistantView();
+ /** Calls each page's connect function.
+ *
+ * @param The model.
+ */
void connect(StockAssistantModel*);
+ /** Calls the specified page's prepare function. As with connect
+ * the association with the model's entry might be better at the
+ * Assistant level.
+ *
+ * @param page The page who's prepare function to call.
+ * @param model
+ */
void prepare(int page, StockAssistantModel*);
GtkWidget* window() { return m_window; }
};
@@ -2209,6 +2429,12 @@ StockAssistantView::~StockAssistantView()
DEBUG ("StockAssistantView destructor\n");
};
+/** Callback for determining the next page.
+ *
+ * @param current page: Inout parameter.
+ * @param data The model as a void*.
+ */
+
static gint
forward_page_func (gint current_page, void* data)
{
@@ -2298,6 +2524,10 @@ StockAssistantView::prepare(int page, StockAssistantModel* model)
}
}
+/** The overall manager for the assistant, contains the model and view
+ * objects and is responsible for creating, connecting, and destroying
+ * both.
+ */
class StockAssistantController
{
std::unique_ptr<StockAssistantModel> m_model;
commit fbf5ab8b4789ff8e0db6d463fe82dcf1f48fd1c3
Author: John Ralls <jralls at ceridwen.us>
Date: Thu Aug 31 12:24:49 2023 -0700
[stock-txn-asst] Ensure correct memory management flow.
For the StockTransferController and GncGuiManager events.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 8096b40f6c..3411056288 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -1272,6 +1272,7 @@ StockAssistantModel::create_transaction ()
if (!m_ready_to_create)
{
PERR ("errors exist. cannot create transaction.");
+ m_list_of_splits.clear();
return {false, nullptr};
}
auto book = qof_instance_get_book (m_acct);
@@ -1286,6 +1287,7 @@ StockAssistantModel::create_transaction ()
add_price (book);
xaccTransCommitEdit (trans);
std::for_each (accounts.begin(), accounts.end(), xaccAccountCommitEdit);
+ m_list_of_splits.clear();
m_ready_to_create = false;
return {true, trans};
}
@@ -2300,6 +2302,7 @@ class StockAssistantController
{
std::unique_ptr<StockAssistantModel> m_model;
StockAssistantView m_view;
+ bool m_destroying = false;
public:
StockAssistantController (GtkWidget *parent, GtkBuilder* builder, Account* acct)
: m_model{std::make_unique<StockAssistantModel>(acct)},
@@ -2312,6 +2315,7 @@ public:
void connect_signals(GtkBuilder *builder);
void prepare(GtkAssistant* assistant, GtkWidget *page);
void finish();
+ bool destroying() { return m_destroying; }
};
static void stock_assistant_window_destroy_cb(GtkWidget *object, gpointer user_data);
@@ -2320,6 +2324,7 @@ static void close_handler (gpointer user_data);
StockAssistantController::~StockAssistantController()
{
+ m_destroying = true;
gnc_unregister_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, this);
}
@@ -2367,49 +2372,66 @@ stock_assistant_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
info->prepare(assistant, page);
}
-void
-stock_assistant_window_destroy_cb(GtkWidget *object, gpointer user_data)
+
+static void
+stock_assistant_window_destroy_cb (GtkWidget *object, gpointer user_data) //crashes before this gets called.
{
- auto info = static_cast<StockAssistantController*>(user_data);
- gnc_close_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, info);
+ auto controller = static_cast<StockAssistantController*>(user_data);
+ if (controller->destroying())
+ return;
+
+ gnc_close_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, controller);
}
+
void
stock_assistant_finish_cb (GtkAssistant *assistant, gpointer user_data)
{
- auto info = static_cast<StockAssistantController*>(user_data);
- info->finish();
+ auto controller = static_cast<StockAssistantController*>(user_data);
+ controller->finish();
}
void
stock_assistant_cancel_cb (GtkAssistant *assistant, gpointer user_data)
{
- auto info = static_cast<StockAssistantController*>(user_data);
- gnc_close_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, info);
+ auto controller = static_cast<StockAssistantController*>(user_data);
+ if (controller->destroying())
+ return;
+ gnc_close_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, controller);
}
static void
refresh_handler (GHashTable *changes, gpointer user_data)
{
-/* FIXME: This isn't right, we need to examine the changes hash
- table. If the account is destroyed trying to query it will crash.
- auto info = static_cast<StockAssistantController*>(user_data);
+ if (!changes) // None of our watches fired, we don't need to do anything.
+ return;
- if (!GNC_IS_ACCOUNT (info->m_model->m_acct))
+/* We have only one watch so we don't need to check GUIDs. There
+ * should be only one entry, so just get the value and see if it
+ * matches QOF_EVENT_DESTROY.
+ */
+ auto list = g_hash_table_get_values(changes);
+ for (auto node = list; node; node = g_list_next(node))
{
- PWARN ("account %p does not exist anymore. abort", info->m_model->m_acct);
- gnc_close_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, info);
+ auto change{static_cast<EventInfo*>(node->data)};
+ if (change->event_mask & QOF_EVENT_DESTROY)
+ {
+ PWARN ("Stock account destroyed, cancelling assistant.");
+ auto controller = static_cast<StockAssistantController*>(user_data);
+ gnc_close_gui_component_by_data(ASSISTANT_STOCK_TRANSACTION_CM_CLASS, controller);
+ }
}
-*/
}
static void
close_handler (gpointer user_data)
{
- auto info = static_cast<StockAssistantController*>(user_data);
- delete info;
+ auto controller = static_cast<StockAssistantController*>(user_data);
+ if (controller->destroying())
+ return;
+ delete controller;
}
/********************************************************************\
commit 4ff0ac383a52de68f52e352b29678697d2211d7c
Author: John Ralls <jralls at ceridwen.us>
Date: Thu Aug 31 11:41:29 2023 -0700
[stock-txn-asst] Change structs to classes.
With private data members, replacing direct member access with
accessor functions and refactoring functionality away from the
Model, View, and Controller container classes to the classes
that own the members.
This removes the need for RTTI inspection as regular virtual
function dispatch accounts for differences in Entry classes.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index fc5f86cd71..8096b40f6c 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -22,6 +22,7 @@
#include <config.h>
+#include <cstddef>
#include <exception>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
@@ -542,8 +543,9 @@ Logger::report()
* many split types.
*/
-struct StockTransactionEntry
+class StockTransactionEntry
{
+protected:
bool m_enabled;
bool m_debit_side;
bool m_allow_zero;
@@ -554,37 +556,40 @@ struct StockTransactionEntry
const char* m_memo;
const char* m_action;
gnc_numeric m_balance = gnc_numeric_zero();
-
+public:
StockTransactionEntry() :
m_enabled{false}, m_debit_side{false}, m_allow_zero{false}, m_account{nullptr},
m_value{gnc_numeric_error(GNC_ERROR_ARG)}, m_memo{nullptr}, m_action{nullptr} {}
StockTransactionEntry(const char* action) :
m_enabled{false}, m_debit_side{false}, m_allow_zero{false}, m_account{nullptr},
m_value{gnc_numeric_error(GNC_ERROR_ARG)}, m_memo{nullptr}, m_action{action} {}
- StockTransactionEntry(bool debit_side, bool allow_zero, bool allow_negative, Account* account,
- gnc_numeric value, const char* memo, const char* action) :
- m_enabled{true}, m_debit_side{debit_side}, m_allow_zero{allow_zero}, m_allow_negative{allow_negative},
- m_account{account}, m_value{value}, m_memo{memo}, m_action{action} {}
+ StockTransactionEntry(const StockTransactionEntry&) = default;
virtual ~StockTransactionEntry() = default;
virtual void set_fieldmask(FieldMask mask);
+ virtual bool enabled() const { return m_enabled; }
+ virtual bool debit_side() const { return m_debit_side; }
virtual void set_capitalize(bool capitalize) {}
+ virtual bool input_new_balance() const { return m_input_new_balance; }
virtual bool do_capitalize() const { return false; }
virtual void set_account(Account* account) { m_account = account; }
+ virtual Account* account() const { return m_account; }
+ virtual const char* print_account() const;
virtual void set_memo(const char* memo) { m_memo = memo; }
+ virtual const char* memo() const { return m_memo; }
virtual void set_value(gnc_numeric amount);
- virtual gnc_numeric amount() { return m_value; }
- virtual void set_balance(gnc_numeric balance) { m_balance = balance; }
- virtual gnc_numeric get_balance() { return m_balance; }
virtual void set_amount(gnc_numeric) {}
- virtual void create_split(Transaction* trans, AccountVec& commits);
- virtual const char* print_value(GNCPrintAmountInfo info);
- virtual const char* print_amount(gnc_numeric amt);
- virtual std::string amount_str_for_display() { return ""; }
+ virtual gnc_numeric amount() const { return m_value; }
+ virtual bool has_amount() const { return false; }
+ virtual void validate_amount(Logger&) const;
+ virtual void set_balance(gnc_numeric balance) { m_balance = balance; }
+ virtual gnc_numeric get_balance() const { return m_balance; }
+ virtual void create_split(Transaction* trans, AccountVec& commits) const;
+ virtual const char* print_value() const;
+ virtual const char* print_amount(gnc_numeric amt) const;
+ virtual std::string amount_str_for_display() const { return ""; }
virtual gnc_numeric calculate_price() const { return gnc_numeric_error(GNC_ERROR_ARG); }
virtual const char* print_price() const;
- virtual bool has_amount() { return false; }
- virtual void validate_amount(Logger&) const;
};
using StockTransactionEntryPtr = std::unique_ptr<StockTransactionEntry>;
@@ -598,6 +603,12 @@ StockTransactionEntry::set_fieldmask(FieldMask mask)
m_allow_negative = mask & FieldMask::ALLOW_NEGATIVE;
}
+const char *
+StockTransactionEntry::print_account() const
+{
+ return m_account ? xaccAccountGetName(m_account) :
+ m_enabled && !gnc_numeric_zero_p(m_value) ? _("missing") : "";
+}
void
StockTransactionEntry::set_value(gnc_numeric amount)
@@ -641,21 +652,34 @@ StockTransactionEntry::validate_amount(Logger& logger) const
if (!m_allow_zero && !gnc_numeric_positive_p (m_value))
add_error (N_("Amount for %s must be positive."), m_action);
+
+ if (!gnc_numeric_zero_p(m_value) && !m_account)
+ add_error(N_("The %s amount has no associated account."), m_action);
}
const char *
-StockTransactionEntry::print_value(GNCPrintAmountInfo pinfo)
+StockTransactionEntry::print_value() const
{
if (!m_enabled || (gnc_numeric_check(m_value) && m_allow_zero))
return nullptr;
+
if ((gnc_numeric_check(m_value) || gnc_numeric_zero_p(m_value))
&& !m_allow_zero)
return _("missing");
+
+ /* Don't combine this with the first if, it would prevent showing
+ * "missing" when the value is required.
+ */
+ if (!m_account)
+ return nullptr;
+
+ auto currency{gnc_account_get_currency_or_parent(m_account)};
+ auto pinfo{gnc_commodity_print_info(currency, TRUE)};
return xaccPrintAmount(m_value, pinfo);
}
const char *
-StockTransactionEntry::print_amount(gnc_numeric amt)
+StockTransactionEntry::print_amount(gnc_numeric amt) const
{
if (!m_account || gnc_numeric_check(amt))
return nullptr;
@@ -665,7 +689,8 @@ StockTransactionEntry::print_amount(gnc_numeric amt)
}
void
-StockTransactionEntry::create_split(Transaction *trans, AccountVec &account_commits) {
+StockTransactionEntry::create_split(Transaction *trans, AccountVec &account_commits) const
+{
g_return_if_fail(trans);
if (!m_account || gnc_numeric_check(m_value))
return;
@@ -701,11 +726,11 @@ StockTransactionEntry::print_price() const
return xaccPrintAmount(price, pinfo);
}
-struct StockTransactionStockEntry : public StockTransactionEntry
+class StockTransactionStockEntry : public StockTransactionEntry
{
bool m_amount_enabled;
gnc_numeric m_amount;
-
+public:
StockTransactionStockEntry() :
StockTransactionEntry{}, m_amount{gnc_numeric_error(GNC_ERROR_ARG)}
{
@@ -717,13 +742,13 @@ struct StockTransactionStockEntry : public StockTransactionEntry
PINFO("Stock Entry");
}
void set_fieldmask(FieldMask mask) override;
- gnc_numeric amount() override { return m_amount; }
void set_amount(gnc_numeric amount) override;
- void create_split(Transaction *trans, AccountVec &account_commits) override;
- std::string amount_str_for_display() override;
- gnc_numeric calculate_price() const override;
- bool has_amount() override { return m_amount_enabled; }
+ gnc_numeric amount() const override { return m_amount; }
+ bool has_amount() const override { return m_amount_enabled; }
void validate_amount(Logger& logger) const override;
+ void create_split(Transaction *trans, AccountVec &account_commits) const override;
+ std::string amount_str_for_display() const override;
+ gnc_numeric calculate_price() const override;
};
void
@@ -806,7 +831,7 @@ StockTransactionStockEntry::validate_amount(Logger& logger) const
}
std::string
-StockTransactionStockEntry::amount_str_for_display()
+StockTransactionStockEntry::amount_str_for_display() const
{
std::string rv{""};
@@ -841,7 +866,7 @@ StockTransactionStockEntry::amount_str_for_display()
void
-StockTransactionStockEntry::create_split(Transaction *trans, AccountVec &account_commits)
+StockTransactionStockEntry::create_split(Transaction *trans, AccountVec &account_commits) const
{
g_return_if_fail(trans);
if (!m_account)
@@ -893,28 +918,33 @@ StockTransactionStockEntry::calculate_price() const
return price;
}
-struct StockTransactionStockCapGainsEntry : public StockTransactionEntry
+class StockTransactionStockCapGainsEntry : public StockTransactionEntry
{
+public:
StockTransactionStockCapGainsEntry(const StockTransactionEntry* cg_entry,
const StockTransactionEntry* stk_entry);
- gnc_numeric amount() { return gnc_numeric_zero(); }
+ gnc_numeric amount() const { return gnc_numeric_zero(); }
};
StockTransactionStockCapGainsEntry::StockTransactionStockCapGainsEntry(const StockTransactionEntry *cg_entry,
const StockTransactionEntry *stk_entry) :
- StockTransactionEntry(!cg_entry->m_debit_side, cg_entry->m_allow_zero, cg_entry->m_allow_negative,
- stk_entry->m_account, cg_entry->m_value, cg_entry->m_memo, cg_entry->m_action) {}
+ StockTransactionEntry(*cg_entry)
+{
+ m_debit_side = !m_debit_side;
+ m_account = stk_entry->account();
+}
-struct StockTransactionFeesEntry : public StockTransactionEntry
+class StockTransactionFeesEntry : public StockTransactionEntry
{
bool m_capitalize;
-
+public:
StockTransactionFeesEntry() : StockTransactionEntry{}, m_capitalize{false} {}
StockTransactionFeesEntry(const char* action) : StockTransactionEntry{action}, m_capitalize{false} {}
void set_fieldmask(FieldMask mask) override;
void set_capitalize(bool capitalize) override { m_capitalize = capitalize; }
bool do_capitalize() const override { return m_capitalize; }
- void create_split(Transaction *trans, AccountVec &commits) override;
+ void validate_amount(Logger &logger) const override;
+ void create_split(Transaction *trans, AccountVec &commits) const override;
};
void
@@ -925,7 +955,36 @@ StockTransactionFeesEntry::set_fieldmask(FieldMask mask)
}
void
-StockTransactionFeesEntry::create_split(Transaction* trans, AccountVec& commits)
+StockTransactionFeesEntry::validate_amount(Logger& logger) const
+{
+ auto add_error = [&logger](const char* format_str, const char* arg)
+ {
+ char *buf = g_strdup_printf (_(format_str),
+ g_dpgettext2 (nullptr, "Stock Assistant: Page name", arg));
+ logger.error(buf);
+ g_free (buf);
+ };
+
+
+ if (gnc_numeric_check (m_value))
+ {
+ if (!m_allow_zero)
+ add_error (N_("Amount for %s is missing."), m_action);
+ return;
+ }
+
+ if (gnc_numeric_negative_p (m_value) && !m_allow_negative && m_allow_zero)
+ add_error (N_("Amount for %s must not be negative."), m_action);
+
+ if (!m_allow_zero && !gnc_numeric_positive_p (m_value))
+ add_error (N_("Amount for %s must be positive."), m_action);
+
+ if (!gnc_numeric_zero_p(m_value) && !m_account && !m_capitalize)
+ add_error(N_("The %s amount has no associated account."), m_action);
+}
+
+void
+StockTransactionFeesEntry::create_split(Transaction* trans, AccountVec& commits) const
{
g_return_if_fail(trans);
if ((!m_account && !m_capitalize) || gnc_numeric_check(m_value))
@@ -962,13 +1021,10 @@ static void stock_assistant_model_date_changed_cb(GtkWidget*, void*);
static void stock_assistant_model_description_changed_cb(GtkWidget*, void*);
/** Manages the data and actions for the assistant. */
-struct StockAssistantModel
+class StockAssistantModel
{
Account* m_acct;
gnc_commodity* m_currency;
-
- GNCPrintAmountInfo m_curr_pinfo;
-
time64 m_transaction_date;
const char* m_transaction_description;
std::optional<TxnTypeVec> m_txn_types;
@@ -983,10 +1039,15 @@ struct StockAssistantModel
StockTransactionEntryPtr m_stock_cg_entry; // Required at this level for lifetime management
Logger m_logger;
+ std::optional<time64> m_txn_types_date;
+ bool m_ready_to_create = false;
+
+ EntryVec m_list_of_splits;
+
+public:
StockAssistantModel (Account *account) :
m_acct{account},
m_currency{gnc_account_get_currency_or_parent(account)},
- m_curr_pinfo (gnc_commodity_print_info (m_currency, true)),
m_stock_entry{std::make_unique<StockTransactionStockEntry>(NC_ ("Stock Assistant: Page name","Stock"))},
m_cash_entry{std::make_unique<StockTransactionEntry>(NC_ ("Stock Assistant: Page name","Cash"))},
m_fees_entry{std::make_unique<StockTransactionFeesEntry>(NC_ ("Stock Assistant: Page name","Fees"))},
@@ -994,7 +1055,7 @@ struct StockAssistantModel
m_capgains_entry{std::make_unique<StockTransactionEntry>(NC_ ("Stock Assistant: Page name","Capital Gains"))}
{
DEBUG ("StockAssistantModel constructor\n");
- m_stock_entry->m_account = m_acct;
+ m_stock_entry->set_account(m_acct);
};
~StockAssistantModel()
@@ -1005,22 +1066,23 @@ struct StockAssistantModel
// consider reset txn_types. return false if txn_types are still
// current (i.e. transaction_date hasn't changed).
bool maybe_reset_txn_types ();
+ const std::optional<TxnTypeVec>& get_txn_types() { return m_txn_types; }
bool set_txn_type (guint type_idx);
- void set_transaction_date(time64 date) {
- m_transaction_date = date;
- PWARN("Setting tranacaction date to %s", qof_print_date(m_transaction_date));
- }
+ bool txn_type_valid() { return m_txn_type.has_value(); }
+ void set_transaction_date(time64 date) { m_transaction_date = date;}
void set_transaction_desc(const char* desc) { m_transaction_description = desc; }
std::string get_new_amount_str ();
+ const std::optional<TxnTypeInfo>& txn_type() { return m_txn_type; }
+ std::string get_new_amount_str () const;
+ StockTransactionEntry* stock_entry() { return m_stock_entry.get(); }
+ StockTransactionEntry* cash_entry() { return m_cash_entry.get(); }
+ StockTransactionEntry* fees_entry() { return m_fees_entry.get(); }
+ StockTransactionEntry* dividend_entry() { return m_dividend_entry.get(); }
+ StockTransactionEntry* capgains_entry() { return m_capgains_entry.get(); }
+ Logger& logger() { return m_logger; }
std::tuple<bool, std::string, EntryVec> generate_list_of_splits ();
std::tuple<bool, Transaction*> create_transaction ();
-
private:
- std::optional<time64> m_txn_types_date;
- bool m_ready_to_create = false;
-
- EntryVec m_list_of_splits;
-
void add_price (QofBook *book);
StockTransactionEntry* make_stock_split_info();
};
@@ -1112,7 +1174,7 @@ StockAssistantModel::generate_list_of_splits() {
if (last_split_node)
check_txn_date(last_split_node, m_transaction_date, m_logger);
- if (m_stock_entry->m_enabled || m_stock_entry->has_amount())
+ if (m_stock_entry->enabled() || m_stock_entry->has_amount())
{
m_stock_entry->validate_amount(m_logger);
m_list_of_splits.push_back(m_stock_entry.get());
@@ -1133,25 +1195,27 @@ StockAssistantModel::generate_list_of_splits() {
}
}
- if (m_cash_entry->m_enabled)
+ if (m_cash_entry->enabled())
{
m_cash_entry->validate_amount(m_logger);
m_list_of_splits.push_back (m_cash_entry.get());
}
- if (m_fees_entry->m_enabled)
+ if (m_fees_entry->enabled())
{
m_fees_entry->validate_amount(m_logger);
+ if (m_fees_entry->do_capitalize())
+ m_fees_entry->set_account(m_acct);
m_list_of_splits.push_back (m_fees_entry.get());
}
- if (m_dividend_entry->m_enabled)
+ if (m_dividend_entry->enabled())
{
m_dividend_entry->validate_amount(m_logger);
m_list_of_splits.push_back (m_dividend_entry.get());
}
- if (m_capgains_entry->m_enabled)
+ if (m_capgains_entry->enabled())
{
m_stock_cg_entry =
std::make_unique<StockTransactionStockCapGainsEntry>(m_capgains_entry.get(),
@@ -1185,8 +1249,9 @@ StockAssistantModel::generate_list_of_splits() {
else
{
auto imbalance_str = N_("Total Debits of %s does not balance with total Credits of %s.");
- auto debit_str = g_strdup (xaccPrintAmount (debit, m_curr_pinfo));
- auto credit_str = g_strdup (xaccPrintAmount (credit, m_curr_pinfo));
+ auto pinfo{gnc_commodity_print_info (m_currency, true)};
+ auto debit_str = g_strdup (xaccPrintAmount (debit, pinfo));
+ auto credit_str = g_strdup (xaccPrintAmount (credit, pinfo));
auto error_str = g_strdup_printf (_(imbalance_str), debit_str, credit_str);
m_logger.error (error_str);
g_free (error_str);
@@ -1285,9 +1350,10 @@ get_widget (GtkBuilder *builder, const gchar * ID)
/* Editor widgets used in assistant pages. */
-struct GncDateEdit
+class GncDateEdit
{
GtkWidget *m_edit;
+public:
GncDateEdit(GtkBuilder *builder) :
m_edit{gnc_date_edit_new(gnc_time(nullptr), FALSE, FALSE)} {}
void attach(GtkBuilder *builder, const char *table_ID, const char *label_ID,
@@ -1313,10 +1379,10 @@ GncDateEdit::connect(GCallback cb, gpointer data)
g_signal_connect(m_edit, "date_changed", cb, data);
}
-struct GncAmountEdit
+class GncAmountEdit
{
GtkWidget *m_edit;
-
+public:
GncAmountEdit (GtkBuilder *builder, gnc_commodity *commodity);
void attach (GtkBuilder *builder, const char *table_id,
const char *label_ID, int row);
@@ -1381,16 +1447,17 @@ GncAmountEdit::set_owner(gpointer obj)
using AccountTypeList = std::vector<GNCAccountType>;
-struct GncAccountSelector
+class GncAccountSelector
{
GtkWidget* m_selector;
-
+public:
GncAccountSelector (GtkBuilder *builder, AccountTypeList types,
gnc_commodity *currency);
void attach (GtkBuilder *builder, const char *table_id,
const char *label_ID, int row);
void connect (StockTransactionEntry*);
void set (Account *acct) { gnc_account_sel_set_account (GNC_ACCOUNT_SEL (m_selector), acct, TRUE); }
+ void set_sensitive(bool sensitive);
Account *get () { return gnc_account_sel_get_account (GNC_ACCOUNT_SEL (m_selector)); }
};
@@ -1432,6 +1499,12 @@ GncAccountSelector::connect (StockTransactionEntry* entry)
g_signal_connect(m_selector, "account_sel_changed", G_CALLBACK (gnc_account_sel_changed_cb), entry);
}
+void
+GncAccountSelector::set_sensitive(bool sensitive)
+{
+ gtk_widget_set_sensitive(m_selector, sensitive);
+}
+
/* Assistant page classes, one per page. */
/* When an assistant page (a GtkContainer) is displayed it emits a
@@ -1451,11 +1524,12 @@ assistant_page_set_focus(GtkWidget* page, [[maybe_unused]]GtkDirectionType type,
}
-struct PageTransType {
+class PageTransType {
// transaction type page
GtkWidget * m_page;
GtkWidget * m_type;
GtkWidget * m_explanation;
+public:
PageTransType(GtkBuilder *builder);
void prepare(StockAssistantModel* model);
int get_transaction_type_index ();
@@ -1484,10 +1558,11 @@ page_trans_type_changed_cb (GtkWidget* widget, StockAssistantModel *model)
void
PageTransType::prepare(StockAssistantModel *model)
{
- if (!model->m_txn_types)
+ const auto& txn_types{model->get_txn_types()};
+ if (!txn_types)
return;
- set_transaction_types(model->m_txn_types.value());
+ set_transaction_types(txn_types.value());
change_txn_type (model);
g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_type);
}
@@ -1522,10 +1597,10 @@ PageTransType::change_txn_type (StockAssistantModel *model)
if (type_idx < 0) // combo isn't initialized yet.
return;
- if (!model->set_txn_type (type_idx))
+ if (!model->set_txn_type(type_idx))
return;
-
- set_txn_type_explanation (_(model->m_txn_type->explanation));
+ auto txn_type{model->txn_type()};
+ set_txn_type_explanation (_(txn_type->explanation));
}
void
@@ -1535,12 +1610,13 @@ PageTransType::connect(StockAssistantModel *model)
G_CALLBACK (page_trans_type_changed_cb), model);
}
-struct PageTransDeets
+class PageTransDeets
{
// transaction details page
GtkWidget *m_page;
GncDateEdit m_date;
GtkWidget *m_description;
+public:
PageTransDeets (GtkBuilder *builder);
time64 get_date_time () { return m_date.get_date_time(); }
const char* get_description () { return gtk_entry_get_text (GTK_ENTRY (m_description)); }
@@ -1574,7 +1650,7 @@ PageTransDeets::prepare(StockAssistantModel* model)
g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_description);
}
-struct PageStockAmount
+class PageStockAmount
{
// stock amount page
GtkWidget * m_page;
@@ -1584,8 +1660,9 @@ struct PageStockAmount
GtkWidget * m_next_amount_label;
GncAmountEdit m_amount;
GtkWidget * m_amount_label;
+public:
PageStockAmount (GtkBuilder *builder, Account* account);
- void prepare (StockTransactionStockEntry*);
+ void prepare (StockTransactionEntry*);
gnc_numeric get_stock_amount () { return m_amount.get(); }
void set_stock_amount (std::string new_amount_str);
void connect(StockTransactionEntry* entry);
@@ -1604,16 +1681,17 @@ PageStockAmount::PageStockAmount (GtkBuilder *builder, Account* account) :
}
void
-PageStockAmount::prepare (StockTransactionStockEntry* entry)
+PageStockAmount::prepare (StockTransactionEntry* entry)
{
gtk_label_set_text_with_mnemonic
(GTK_LABEL (m_amount_label),
- entry->m_input_new_balance ? _("Ne_w Balance") : _("_Shares"));
+ entry->input_new_balance() ? _("Ne_w Balance") : _("_Shares"));
gtk_label_set_text
(GTK_LABEL (m_next_amount_label),
- entry->m_input_new_balance ? _("Ratio") : _("Next Balance"));
- gtk_label_set_text (GTK_LABEL (m_title),
- entry->m_input_new_balance ?
+ entry->input_new_balance() ? _("Ratio") : _("Next Balance"));
+ gtk_label_set_text
+ (GTK_LABEL (m_title),
+ entry->input_new_balance() ?
_("Enter the new balance of shares after the stock split.") :
_("Enter the number of shares you gained or lost in the transaction."));
gtk_label_set_text (GTK_LABEL (m_prev_amount), entry->print_amount(entry->get_balance()));
@@ -1627,8 +1705,8 @@ static void
page_stock_amount_changed_cb(GtkWidget *widget, StockTransactionEntry* entry)
{
auto me = static_cast<PageStockAmount*>(g_object_get_data (G_OBJECT (widget), "owner"));
- entry->set_amount(me->m_amount.get());
- me->set_stock_amount (entry->amount_str_for_display());
+ entry->set_amount(me->get_stock_amount());
+ me->set_stock_amount(entry->amount_str_for_display());
}
void
@@ -1644,17 +1722,19 @@ PageStockAmount::set_stock_amount (std::string new_amount_str)
gtk_label_set_text (GTK_LABEL(m_next_amount), new_amount_str.c_str());
}
-struct PageStockValue
+class PageStockValue
{
// stock value page
GtkWidget * m_page;
GncAmountEdit m_value;
GtkWidget * m_price;
GtkWidget * m_memo;
+public:
PageStockValue (GtkBuilder *builder, Account* account);
const char* get_memo ();
void connect(StockTransactionEntry* entry);
void prepare(StockTransactionEntry* entry);
+ GncAmountEdit& value_edit() { return m_value; }
void set_price(const gchar *val);
};
@@ -1662,9 +1742,8 @@ static void
page_stock_value_changed_cb(GtkWidget *widget, StockTransactionEntry* entry)
{
auto me = static_cast<PageStockValue*>(g_object_get_data (G_OBJECT (widget), "owner"));
- auto value = me->m_value.get ();
- entry->set_value (value);
- me->set_price (entry->print_price());
+ entry->set_value (me->value_edit().get());
+ me->set_price(entry->print_price());
}
PageStockValue::PageStockValue(GtkBuilder *builder, Account* account)
@@ -1687,7 +1766,7 @@ PageStockValue::connect(StockTransactionEntry* entry)
void
PageStockValue::prepare(StockTransactionEntry* entry)
{
- entry->m_memo = get_memo();
+ entry->set_memo(get_memo());
if (!gnc_numeric_check(m_value.get()))
entry->set_value(m_value.get());
set_price(entry->print_price());
@@ -1706,13 +1785,14 @@ PageStockValue::set_price (const gchar *val)
gtk_label_set_text(GTK_LABEL(this->m_price), val);
};
-struct PageCash
+class PageCash
{
// cash page
GtkWidget * m_page;
GncAccountSelector m_account;
GtkWidget * m_memo;
GncAmountEdit m_value;
+public:
PageCash (GtkBuilder *builder, Account* account);
void connect(StockTransactionEntry* entry);
void prepare(StockTransactionEntry* entry);
@@ -1741,10 +1821,10 @@ PageCash::connect(StockTransactionEntry* entry)
void
PageCash::prepare(StockTransactionEntry* entry)
{
- entry->m_memo = get_memo();
+ entry->set_memo(get_memo());
if (!gnc_numeric_check(m_value.get()))
- entry->set_value (m_value.get());
- entry->m_account = m_account.get();
+ entry->set_value(m_value.get());
+ entry->set_account(m_account.get());
g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_value.widget());
}
@@ -1754,7 +1834,7 @@ PageCash::get_memo()
return gtk_entry_get_text(GTK_ENTRY (m_memo));
}
-struct PageFees
+class PageFees
{
// fees page
GtkWidget * m_page;
@@ -1763,12 +1843,14 @@ struct PageFees
GtkWidget * m_memo;
GncAmountEdit m_value;
Account* m_stock_account;
+public:
PageFees (GtkBuilder *builder, Account* account);
void connect(StockTransactionEntry*);
bool get_capitalize_fees ();
const char* get_memo();
void set_capitalize_fees (bool state);
void set_account (Account *acct) { m_account.set(acct); }
+ Account* stock_account() { return m_stock_account; }
void update_fees_acct_sensitive (bool sensitive);
void prepare(StockTransactionEntry*);
};
@@ -1809,7 +1891,7 @@ PageFees::set_capitalize_fees(bool state)
void
PageFees::update_fees_acct_sensitive(bool sensitive)
{
- gtk_widget_set_sensitive(m_account.m_selector, sensitive);
+ m_account.set_sensitive(sensitive);
}
static void
@@ -1821,8 +1903,8 @@ capitalize_fees_toggled_cb (GtkWidget *widget, StockTransactionEntry *entry)
bool cap = me->get_capitalize_fees();
entry->set_capitalize(cap);
if (cap)
- entry->m_account = me->m_stock_account;
- me->update_fees_acct_sensitive (!cap);
+ entry->set_account(me->stock_account());
+ me->update_fees_acct_sensitive(!cap);
}
void
@@ -1839,20 +1921,21 @@ void
PageFees::prepare(StockTransactionEntry* entry)
{
set_capitalize_fees (entry->do_capitalize());
- entry->m_memo = get_memo();
+ entry->set_memo(get_memo());
if (!gnc_numeric_check(m_value.get()))
entry->set_value (m_value.get());
- entry->m_account = m_account.get();
+ entry->set_account(m_account.get());
g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_value.widget());
}
-struct PageDividend
+class PageDividend
{
// dividend page
GtkWidget *m_page;
GncAccountSelector m_account;
GtkWidget *m_memo;
GncAmountEdit m_value;
+public:
PageDividend (GtkBuilder *builder, Account* account);
void connect(StockTransactionEntry*);
void prepare(StockTransactionEntry*);
@@ -1881,10 +1964,10 @@ PageDividend::connect(StockTransactionEntry* entry)
void
PageDividend::prepare(StockTransactionEntry* entry)
{
- entry->m_memo = get_memo();
+ entry->set_memo(get_memo());
if (!gnc_numeric_check(m_value.get()))
entry->set_value(m_value.get());
- entry->m_account = m_account.get();
+ entry->set_account(m_account.get());
g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_value.widget());
}
@@ -1894,13 +1977,14 @@ PageDividend::get_memo()
return gtk_entry_get_text(GTK_ENTRY (m_memo));
}
-struct PageCapGain
+class PageCapGain
{
// capgains page
GtkWidget * m_page;
GncAccountSelector m_account;
GtkWidget * m_memo;
GncAmountEdit m_value;
+public:
PageCapGain (GtkBuilder *builder, Account* account);
void connect(StockTransactionEntry* entry);
void prepare(StockTransactionEntry* entry);
@@ -1935,10 +2019,10 @@ PageCapGain::connect(StockTransactionEntry*entry)
void
PageCapGain::prepare(StockTransactionEntry* entry)
{
- entry->m_memo = get_memo();
+ entry->set_memo(get_memo());
if (gnc_numeric_check(m_value.get()))
entry->set_value(m_value.get());
- entry->m_account = m_account.get();
+ entry->set_account(m_account.get());
g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_value.widget());
}
@@ -1946,11 +2030,13 @@ PageCapGain::prepare(StockTransactionEntry* entry)
* like.
*/
/* The GncFinishtreeview lays out the transaction.*/
-struct GncFinishTreeview
+class GncFinishTreeview
{
GtkWidget *m_treeview;
+public:
GncFinishTreeview(GtkBuilder *builder);
void set_tooltip_column(int);
+ void load(const EntryVec& list_of_splits);
};
GncFinishTreeview::GncFinishTreeview (GtkBuilder *builder) :
@@ -2002,42 +2088,28 @@ GncFinishTreeview::GncFinishTreeview (GtkBuilder *builder) :
"foreground", SPLIT_COL_UNITS_COLOR,
nullptr);
gtk_tree_view_append_column(view, column);
-}
+ gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(m_treeview),
+ SPLIT_COL_TOOLTIP);}
void
GncFinishTreeview::set_tooltip_column(int column)
{
- gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(m_treeview), column);
-}
-
-struct PageFinish
-{
- // finish page
- GtkWidget * m_page;
- GncFinishTreeview m_view;
- GtkWidget * m_summary;
- PageFinish (GtkBuilder *builder);
- void prepare (GtkWidget *window, StockAssistantModel *model);
-};
-
-PageFinish::PageFinish (GtkBuilder *builder) :
- m_page (get_widget (builder, "finish_page")), m_view (builder),
- m_summary (get_widget (builder, "finish_summary")) {}
+}
void
-PageFinish::prepare (GtkWidget *window, StockAssistantModel *model)
+GncFinishTreeview::load(const EntryVec& list_of_splits)
{
- auto [success, summary, list_of_splits] = model->generate_list_of_splits ();
- auto gtv = GTK_TREE_VIEW(m_view.m_treeview);
+ auto gtv = GTK_TREE_VIEW(m_treeview);
bool negative_in_red = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL,
GNC_PREF_NEGATIVE_IN_RED);
auto list = GTK_LIST_STORE(gtk_tree_view_get_model(gtv));
gtk_list_store_clear(list);
for (const auto &entry : list_of_splits) {
GtkTreeIter iter;
- auto tooltip = (entry->m_memo && *entry->m_memo ?
- g_markup_escape_text(entry->m_memo, -1) : strdup(""));
+ auto memo{entry->memo()};
+ auto tooltip = (memo && *memo ?
+ g_markup_escape_text(memo, -1) : strdup(""));
/* print_value and print_amount rely on xaccPrintAmount that
* uses static memory so the result needs to be copied
* immediately or the second call overwrites the results of
@@ -2045,31 +2117,54 @@ PageFinish::prepare (GtkWidget *window, StockAssistantModel *model)
*/
auto char2str{[](const char* str) -> std::string {
return std::string{ str ? str : "" }; }};
- auto amount{char2str(entry->print_value(model->m_curr_pinfo))};
+ auto amount{char2str(entry->print_value())};
auto units{char2str(entry->has_amount() ?
- entry->print_amount(entry->m_debit_side ? entry->amount() :
+ entry->print_amount(entry->debit_side() ? entry->amount() :
gnc_numeric_neg(entry->amount())) : "")};
- auto units_in_red{negative_in_red && !entry->m_debit_side};
+ auto units_in_red{negative_in_red && !entry->debit_side()};
gtk_list_store_append(list, &iter);
gtk_list_store_set(
list, &iter,
SPLIT_COL_ACCOUNT,
- entry->m_account ? xaccAccountGetName(entry->m_account) : "", SPLIT_COL_MEMO,
- entry->m_memo, SPLIT_COL_TOOLTIP, tooltip, SPLIT_COL_DEBIT,
- entry->m_debit_side ? amount.c_str() : nullptr,
+ entry->print_account(), SPLIT_COL_MEMO,
+ entry->memo(), SPLIT_COL_TOOLTIP, tooltip, SPLIT_COL_DEBIT,
+ entry->debit_side() ? amount.c_str() : nullptr,
SPLIT_COL_CREDIT,
- entry->m_debit_side ? nullptr : amount.c_str(),
+ entry->debit_side() ? nullptr : amount.c_str(),
SPLIT_COL_UNITS, units.c_str(),
SPLIT_COL_UNITS_COLOR, units_in_red ? "red" : nullptr, -1);
g_free(tooltip);
}
+}
+
+class PageFinish
+{
+ // finish page
+ GtkWidget * m_page;
+ GncFinishTreeview m_view;
+ GtkWidget * m_summary;
+public:
+ PageFinish (GtkBuilder *builder);
+ void prepare (GtkWidget *window, StockAssistantModel *model);
+};
+
+PageFinish::PageFinish (GtkBuilder *builder) :
+ m_page (get_widget (builder, "finish_page")), m_view (builder),
+ m_summary (get_widget (builder, "finish_summary")) {}
+
+
+void
+PageFinish::prepare (GtkWidget *window, StockAssistantModel *model)
+{
+ auto [success, summary, list_of_splits] = model->generate_list_of_splits ();
+ m_view.load(list_of_splits);
gtk_label_set_text(GTK_LABEL(m_summary), summary.c_str());
gtk_assistant_set_page_complete(GTK_ASSISTANT(window), m_page, success);
}
/* The StockAssistantView contains the pages and manages displaying them one at a time. */
-struct StockAssistantView {
+class StockAssistantView {
GtkWidget * m_window;
PageTransType m_type_page;
@@ -2081,9 +2176,12 @@ struct StockAssistantView {
PageDividend m_dividend_page;
PageCapGain m_capgain_page;
PageFinish m_finish_page;
-
+public:
StockAssistantView(GtkBuilder *builder, Account* account, GtkWidget *parent);
~StockAssistantView();
+ void connect(StockAssistantModel*);
+ void prepare(int page, StockAssistantModel*);
+ GtkWidget* window() { return m_window; }
};
StockAssistantView::StockAssistantView (GtkBuilder *builder, Account* account, GtkWidget *parent) :
@@ -2094,7 +2192,6 @@ StockAssistantView::StockAssistantView (GtkBuilder *builder, Account* account, G
{
// Set the name for this assistant so it can be easily manipulated with css
gtk_widget_set_name (GTK_WIDGET(m_window), "gnc-id-assistant-stock-transaction");
- m_finish_page.m_view.set_tooltip_column(SPLIT_COL_TOOLTIP);
gtk_window_set_transient_for (GTK_WINDOW (m_window), GTK_WINDOW(parent));
gnc_window_adjust_for_screen (GTK_WINDOW(m_window));
gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(m_window),
@@ -2106,103 +2203,92 @@ StockAssistantView::StockAssistantView (GtkBuilder *builder, Account* account, G
StockAssistantView::~StockAssistantView()
{
gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(m_window));
+ gtk_widget_destroy (m_window);
DEBUG ("StockAssistantView destructor\n");
};
-/* The StockAssistantController manages the event handlers and user input. */
-
-struct StockAssistantController
+static gint
+forward_page_func (gint current_page, void* data)
{
- std::unique_ptr<StockAssistantModel> m_model;
- StockAssistantView m_view;
- StockAssistantController (GtkWidget *parent, GtkBuilder* builder, Account* acct)
- : m_model{std::make_unique<StockAssistantModel>(acct)},
- m_view{builder, acct, parent}
- {
- connect_signals (builder);
- DEBUG ("StockAssistantController constructor\n");
- };
- ~StockAssistantController (){ DEBUG ("StockAssistantController destructor\n"); };
- void connect_signals(GtkBuilder *builder);
- void prepare(GtkAssistant* assistant, GtkWidget *page);
-};
-
-static gint forward_page_func(int32_t, StockAssistantController*);
-static void stock_assistant_window_destroy_cb(GtkWidget *object, gpointer user_data);
-static void refresh_handler (GHashTable *changes, gpointer user_data);
-static void close_handler (gpointer user_data);
+ auto model{static_cast<StockAssistantModel*>(data)};
+ current_page++;
+ if (!model->txn_type_valid())
+ return current_page;
-void
-StockAssistantController::connect_signals (GtkBuilder *builder)
-{
- m_view.m_type_page.connect(m_model.get());
- m_view.m_deets_page.connect(m_model.get());
- m_view.m_stock_amount_page.connect(m_model->m_stock_entry.get());
- m_view.m_stock_value_page.connect(m_model->m_stock_entry.get());
- m_view.m_cash_page.connect(m_model->m_cash_entry.get());
- m_view.m_fees_page.connect(m_model->m_fees_entry.get());
- m_view.m_dividend_page.connect(m_model->m_dividend_entry.get());
- m_view.m_capgain_page.connect(m_model->m_capgains_entry.get());
+ if (!model->stock_entry()->has_amount() && current_page == PAGE_STOCK_AMOUNT)
+ current_page++;
+ if (!model->stock_entry()->enabled() && current_page == PAGE_STOCK_VALUE)
+ current_page++;
+ if (!model->cash_entry()->enabled() && current_page == PAGE_CASH)
+ current_page++;
+ if (!model->fees_entry()->enabled() && current_page == PAGE_FEES)
+ current_page++;
+ if (!model->dividend_entry()->enabled() && current_page == PAGE_DIVIDEND)
+ current_page++;
+ if (!model->capgains_entry()->enabled() && current_page == PAGE_CAPGAINS)
+ current_page++;
- g_signal_connect (m_view.m_window, "destroy", G_CALLBACK (stock_assistant_window_destroy_cb), this);
+ return current_page;
+}
- gtk_assistant_set_forward_page_func (GTK_ASSISTANT(m_view.m_window),
+void
+StockAssistantView::connect(StockAssistantModel* model)
+{
+ m_type_page.connect(model);
+ m_deets_page.connect(model);
+ m_stock_amount_page.connect(model->stock_entry());
+ m_stock_value_page.connect(model->stock_entry());
+ m_cash_page.connect(model->cash_entry());
+ m_fees_page.connect(model->fees_entry());
+ m_dividend_page.connect(model->dividend_entry());
+ m_capgain_page.connect(model->capgains_entry());
+
+ gtk_assistant_set_forward_page_func (GTK_ASSISTANT(m_window),
(GtkAssistantPageFunc)forward_page_func,
- this, nullptr);
- gtk_builder_connect_signals (builder, this); //Stock Assistant View: cancel, close, prepare
-
- auto component_id = gnc_register_gui_component
- (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, refresh_handler, close_handler, this);
- gnc_gui_component_watch_entity_type (component_id, GNC_ID_ACCOUNT,
- QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
+ model, nullptr);
}
void
-StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
+StockAssistantView::prepare(int page, StockAssistantModel* model)
{
- auto currentpage = gtk_assistant_get_current_page(assistant);
-
- switch (currentpage)
+ g_return_if_fail (page < PAGE_STOCK_AMOUNT || model->txn_type_valid());
+ switch (page)
{
case PAGE_TRANSACTION_TYPE:
- if (!m_model->maybe_reset_txn_types())
+ if (!model->maybe_reset_txn_types())
break;
- m_view.m_type_page.prepare(m_model.get());
+ m_type_page.prepare(model);
break;
case PAGE_TRANSACTION_DETAILS:
- m_view.m_deets_page.prepare(m_model.get());
+ m_deets_page.prepare(model);
break;
case PAGE_STOCK_AMOUNT:
{
- auto stock_entry = dynamic_cast<StockTransactionStockEntry*>(m_model->m_stock_entry.get());
- if (stock_entry)
- m_view.m_stock_amount_page.prepare(stock_entry);
+ m_stock_amount_page.prepare(model->stock_entry());
break;
}
case PAGE_STOCK_VALUE:
- m_view.m_stock_value_page.prepare(m_model->m_stock_entry.get());
+ m_stock_value_page.prepare(model->stock_entry());
break;
case PAGE_CASH:
- m_view.m_cash_page.prepare(m_model->m_cash_entry.get());
+ m_cash_page.prepare(model->cash_entry());
break;
case PAGE_FEES:
{
- auto fees_entry = dynamic_cast<StockTransactionFeesEntry*>(m_model->m_fees_entry.get());
- if (fees_entry)
- m_view.m_fees_page.prepare(fees_entry);
+ m_fees_page.prepare(model->fees_entry());
break;
}
case PAGE_DIVIDEND:
- m_view.m_dividend_page.prepare(m_model->m_dividend_entry.get());
+ m_dividend_page.prepare(model->dividend_entry());
break;
case PAGE_CAPGAINS:
{
- m_view.m_capgain_page.prepare(m_model->m_capgains_entry.get());
+ m_capgain_page.prepare(model->capgains_entry());
break;
}
case PAGE_FINISH:
{
- m_view.m_finish_page.prepare (m_view.m_window, m_model.get());
+ m_finish_page.prepare (m_window, model);
break;
}
default:
@@ -2210,17 +2296,69 @@ StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
}
}
+class StockAssistantController
+{
+ std::unique_ptr<StockAssistantModel> m_model;
+ StockAssistantView m_view;
+public:
+ StockAssistantController (GtkWidget *parent, GtkBuilder* builder, Account* acct)
+ : m_model{std::make_unique<StockAssistantModel>(acct)},
+ m_view{builder, acct, parent}
+ {
+ connect_signals (builder);
+ DEBUG ("StockAssistantController constructor\n");
+ };
+ ~StockAssistantController ();
+ void connect_signals(GtkBuilder *builder);
+ void prepare(GtkAssistant* assistant, GtkWidget *page);
+ void finish();
+};
+
+static void stock_assistant_window_destroy_cb(GtkWidget *object, gpointer user_data);
+static void refresh_handler (GHashTable *changes, gpointer user_data);
+static void close_handler (gpointer user_data);
+
+StockAssistantController::~StockAssistantController()
+{
+ gnc_unregister_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, this);
+}
+
+void
+StockAssistantController::connect_signals (GtkBuilder *builder)
+{
+ m_view.connect(m_model.get());
+ gtk_builder_connect_signals (builder, this); //Stock Assistant View: cancel, close, prepare
+ g_signal_connect (m_view.window(), "destroy",
+ G_CALLBACK (stock_assistant_window_destroy_cb), this);
-// These callbacks must be registered with the GtkAssistant so they can't be member functions.
-static void
-stock_assistant_window_destroy_cb (GtkWidget *object, gpointer user_data)
+ auto component_id = gnc_register_gui_component
+ (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, refresh_handler, close_handler, this);
+ gnc_gui_component_watch_entity_type (component_id, GNC_ID_ACCOUNT,
+ QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
+}
+
+void
+StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
{
- auto info = static_cast<StockAssistantController*>(user_data);
- gnc_unregister_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, info);
- delete info;
+ auto currentpage = gtk_assistant_get_current_page(assistant);
+ m_view.prepare(currentpage, m_model.get());
}
+void
+StockAssistantController::finish()
+{
+ g_return_if_fail (m_model->txn_type_valid());
+
+ gnc_suspend_gui_refresh ();
+ [[maybe_unused]] auto [success, trans] = m_model->create_transaction();
+ gnc_resume_gui_refresh ();
+
+ gnc_close_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, this);
+}
+
+// These callbacks must be registered with the GtkAssistant so they can't be member functions.
+/* The StockAssistantController manages the event handlers and user input. */
void
stock_assistant_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
gpointer user_data)
@@ -2229,42 +2367,18 @@ stock_assistant_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
info->prepare(assistant, page);
}
-static gint
-forward_page_func (gint current_page, StockAssistantController* info)
+void
+stock_assistant_window_destroy_cb(GtkWidget *object, gpointer user_data)
{
- auto model = info->m_model.get();
-
- current_page++;
- if (!model->m_txn_type)
- return current_page;
-
- if (!model->m_stock_entry->has_amount() && current_page == PAGE_STOCK_AMOUNT)
- current_page++;
- if (!model->m_stock_entry->m_enabled && current_page == PAGE_STOCK_VALUE)
- current_page++;
- if (!model->m_cash_entry->m_enabled && current_page == PAGE_CASH)
- current_page++;
- if (!model->m_fees_entry->m_enabled && current_page == PAGE_FEES)
- current_page++;
- if (!model->m_dividend_entry->m_enabled && current_page == PAGE_DIVIDEND)
- current_page++;
- if (!model->m_capgains_entry->m_enabled && current_page == PAGE_CAPGAINS)
- current_page++;
-
- return current_page;
+ auto info = static_cast<StockAssistantController*>(user_data);
+ gnc_close_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, info);
}
void
stock_assistant_finish_cb (GtkAssistant *assistant, gpointer user_data)
{
auto info = static_cast<StockAssistantController*>(user_data);
- g_return_if_fail (info->m_model->m_txn_type);
-
- gnc_suspend_gui_refresh ();
- [[maybe_unused]] auto [success, trans] = info->m_model->create_transaction();
- gnc_resume_gui_refresh ();
-
- gnc_close_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, info);
+ info->finish();
}
@@ -2279,20 +2393,23 @@ stock_assistant_cancel_cb (GtkAssistant *assistant, gpointer user_data)
static void
refresh_handler (GHashTable *changes, gpointer user_data)
{
- auto info = static_cast<StockAssistantController*>(user_data);
+/* FIXME: This isn't right, we need to examine the changes hash
+ table. If the account is destroyed trying to query it will crash.
+ auto info = static_cast<StockAssistantController*>(user_data);
if (!GNC_IS_ACCOUNT (info->m_model->m_acct))
{
PWARN ("account %p does not exist anymore. abort", info->m_model->m_acct);
gnc_close_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, info);
}
+*/
}
static void
close_handler (gpointer user_data)
{
auto info = static_cast<StockAssistantController*>(user_data);
- gtk_widget_destroy (info->m_view.m_window);
+ delete info;
}
/********************************************************************\
diff --git a/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp b/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
index aff6d54c4c..06674651e0 100644
--- a/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
+++ b/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
@@ -166,24 +166,22 @@ StockAssistantTest::StockAssistantTest() :
void
StockAssistantTest::instantiate_model(StockAssistantModel &model, const ASTTestCase &t)
{
- model.m_transaction_date = gnc_dmy2time64 (t.dd, t.mm, t.yy);
+ model.set_transaction_date(gnc_dmy2time64 (t.dd, t.mm, t.yy));
model.maybe_reset_txn_types ();
- auto fees_entry = dynamic_cast<StockTransactionFeesEntry*>(model.m_fees_entry.get());
- auto stock_entry = dynamic_cast<StockTransactionStockEntry*>(model.m_stock_entry.get());
model.set_txn_type (t.type_idx);
- model.m_transaction_description = t.desc;
- stock_entry->set_amount(gnc_numeric_create (t.stock_amt, 1));
- model.m_stock_entry->set_value(gnc_numeric_create (t.stock_val, 100));
- model.m_cash_entry->set_value(gnc_numeric_create (t.cash_val, 100));
- model.m_cash_entry->m_account = cash_account;
- model.m_fees_entry->m_account = fees_account;
- fees_entry->m_capitalize = t.capitalize;
- model.m_fees_entry->set_value(gnc_numeric_create (t.fees_val, 100));
- model.m_capgains_entry->m_account = capgains_account;
- model.m_capgains_entry->set_value(gnc_numeric_create (t.capg_val, 100));
- model.m_dividend_entry->m_account = dividend_account;
- model.m_dividend_entry->set_value(gnc_numeric_create (t.divi_val, 100));
+ model.set_transaction_desc(t.desc);
+ model.stock_entry()->set_amount(gnc_numeric_create (t.stock_amt, 1));
+ model.stock_entry()->set_value(gnc_numeric_create (t.stock_val, 100));
+ model.cash_entry()->set_value(gnc_numeric_create (t.cash_val, 100));
+ model.cash_entry()->set_account(cash_account);
+ model.fees_entry()->set_account(fees_account);
+ model.fees_entry()->set_capitalize(t.capitalize);
+ model.fees_entry()->set_value(gnc_numeric_create (t.fees_val, 100));
+ model.capgains_entry()->set_account(capgains_account);
+ model.capgains_entry()->set_value(gnc_numeric_create (t.capg_val, 100));
+ model.dividend_entry()->set_account(dividend_account);
+ model.dividend_entry()->set_value(gnc_numeric_create (t.divi_val, 100));
}
class StockAssistantTestParameterized :
@@ -204,7 +202,7 @@ protected:
TEST_F(StockAssistantTest, testFailureModes)
{
StockAssistantModel model (stock_account);
- model.m_transaction_date = gnc_dmy2time64 (1, 1, 2022);
+ model.set_transaction_date(gnc_dmy2time64 (1, 1, 2022));
// resetting txn_types will work the first time
EXPECT_TRUE (model.maybe_reset_txn_types ());
@@ -213,7 +211,7 @@ TEST_F(StockAssistantTest, testFailureModes)
EXPECT_FALSE (model.maybe_reset_txn_types ());
// set transaction-date to a different date.
- model.m_transaction_date = gnc_dmy2time64 (1, 2, 2022);
+ model.set_transaction_date(gnc_dmy2time64 (1, 2, 2022));
// resetting txn_types will now work.
EXPECT_TRUE (model.maybe_reset_txn_types ());
commit 58c4d5f0ca24b3e7a259175bb6966b705b7acf76
Author: John Ralls <jralls at ceridwen.us>
Date: Tue Aug 29 13:09:47 2023 -0700
[stock-txn-asst] Variable-specific callbacks take an entry pointer.
Prerequisite for making class member variables private.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index e4f000b7df..fc5f86cd71 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -569,6 +569,9 @@ struct StockTransactionEntry
virtual void set_fieldmask(FieldMask mask);
virtual void set_capitalize(bool capitalize) {}
+ virtual bool do_capitalize() const { return false; }
+ virtual void set_account(Account* account) { m_account = account; }
+ virtual void set_memo(const char* memo) { m_memo = memo; }
virtual void set_value(gnc_numeric amount);
virtual gnc_numeric amount() { return m_value; }
virtual void set_balance(gnc_numeric balance) { m_balance = balance; }
@@ -599,10 +602,6 @@ StockTransactionEntry::set_fieldmask(FieldMask mask)
void
StockTransactionEntry::set_value(gnc_numeric amount)
{
- DEBUG ("checking value %s page %s",
- gnc_num_dbg_to_string (amount),
- m_action);
-
if (gnc_numeric_check (amount))
return;
@@ -615,6 +614,7 @@ StockTransactionEntry::set_value(gnc_numeric amount)
{
m_value = amount;
}
+ PINFO("Set %s value to %" PRId64 "/%" PRId64, m_action, m_value.num, m_value.denom);
}
void
@@ -913,6 +913,7 @@ struct StockTransactionFeesEntry : public StockTransactionEntry
StockTransactionFeesEntry(const char* action) : StockTransactionEntry{action}, m_capitalize{false} {}
void set_fieldmask(FieldMask mask) override;
void set_capitalize(bool capitalize) override { m_capitalize = capitalize; }
+ bool do_capitalize() const override { return m_capitalize; }
void create_split(Transaction *trans, AccountVec &commits) override;
};
@@ -957,6 +958,9 @@ StockTransactionFeesEntry::create_split(Transaction* trans, AccountVec& commits
using EntryVec = std::vector<StockTransactionEntry*>;
+static void stock_assistant_model_date_changed_cb(GtkWidget*, void*);
+static void stock_assistant_model_description_changed_cb(GtkWidget*, void*);
+
/** Manages the data and actions for the assistant. */
struct StockAssistantModel
{
@@ -1002,6 +1006,11 @@ struct StockAssistantModel
// current (i.e. transaction_date hasn't changed).
bool maybe_reset_txn_types ();
bool set_txn_type (guint type_idx);
+ void set_transaction_date(time64 date) {
+ m_transaction_date = date;
+ PWARN("Setting tranacaction date to %s", qof_print_date(m_transaction_date));
+ }
+ void set_transaction_desc(const char* desc) { m_transaction_description = desc; }
std::string get_new_amount_str ();
std::tuple<bool, std::string, EntryVec> generate_list_of_splits ();
std::tuple<bool, Transaction*> create_transaction ();
@@ -1240,13 +1249,27 @@ StockAssistantModel::add_price (QofBook *book)
gnc_price_unref (price);
}
+static void
+stock_assistant_model_date_changed_cb(GtkWidget* widget, void* data)
+{
+ auto model{static_cast<StockAssistantModel*>(data)};
+ model->set_transaction_date(gnc_date_edit_get_date_end(GNC_DATE_EDIT(widget)));
+}
+
+static void
+stock_assistant_model_description_changed_cb(GtkWidget* widget, void* data)
+{
+ auto model{static_cast<StockAssistantModel*>(data)};
+ model->set_transaction_desc(gtk_entry_get_text(GTK_ENTRY(widget)));
+}
+
/* ********************* View Classes ************************/
/* ***************** Generic Event Callbacks ****************/
static void
-text_entry_changed_cb (GtkWidget *widget, const gchar **model_text)
+text_entry_changed_cb (GtkWidget *widget, StockTransactionEntry* entry)
{
- *model_text = gtk_entry_get_text (GTK_ENTRY (widget));
+ entry->set_memo(gtk_entry_get_text (GTK_ENTRY (widget)));
}
@@ -1270,16 +1293,9 @@ struct GncDateEdit
void attach(GtkBuilder *builder, const char *table_ID, const char *label_ID,
int row);
time64 get_date_time() { return gnc_date_edit_get_date_end(GNC_DATE_EDIT(m_edit)); }
- void connect(time64 *target);
+ void connect(GCallback, gpointer);
};
-static void
-gnc_date_edit_changed_cb (GtkWidget* widget, time64 *target)
-{
- g_return_if_fail(GNC_IS_DATE_EDIT(widget));
- *target = gnc_date_edit_get_date_end(GNC_DATE_EDIT(widget));
-}
-
void
GncDateEdit::attach(GtkBuilder *builder, const char *table_ID,
const char *label_ID, int row)
@@ -1292,9 +1308,9 @@ GncDateEdit::attach(GtkBuilder *builder, const char *table_ID,
}
void
-GncDateEdit::connect(time64 *time)
+GncDateEdit::connect(GCallback cb, gpointer data)
{
- g_signal_connect(m_edit, "date_changed", G_CALLBACK (gnc_date_edit_changed_cb), time);
+ g_signal_connect(m_edit, "date_changed", cb, data);
}
struct GncAmountEdit
@@ -1308,20 +1324,18 @@ struct GncAmountEdit
return gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT(m_edit));
}
gnc_numeric get ();
- void connect (gnc_numeric *value);
void connect (GCallback cb, gpointer data);
void set_owner (gpointer obj);
};
static void
-gnc_amount_edit_changed_cb (GtkWidget* widget, gnc_numeric *value)
+value_changed_cb (GtkWidget* widget, StockTransactionEntry* entry)
{
g_return_if_fail(GNC_IS_AMOUNT_EDIT(widget));
- gnc_numeric amt;
- if (!gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(widget), &amt, true, nullptr))
- *value = amt;
- else
- *value = gnc_numeric_error(GNC_ERROR_ARG);
+ gnc_numeric value;
+ auto invalid{gnc_amount_edit_expr_is_valid(GNC_AMOUNT_EDIT(widget),
+ &value, true, nullptr)};
+ entry->set_value(invalid ? gnc_numeric_error(GNC_ERROR_ARG) : value);
}
GncAmountEdit::GncAmountEdit (GtkBuilder *builder, gnc_commodity *commodity) :
@@ -1353,12 +1367,6 @@ GncAmountEdit::get ()
return gnc_numeric_error(GNC_ERROR_ARG);
}
-void
-GncAmountEdit::connect (gnc_numeric *value)
-{
- g_signal_connect(m_edit, "changed", G_CALLBACK (gnc_amount_edit_changed_cb), value);
-}
-
void
GncAmountEdit::connect (GCallback cb, gpointer data)
{
@@ -1381,16 +1389,16 @@ struct GncAccountSelector
gnc_commodity *currency);
void attach (GtkBuilder *builder, const char *table_id,
const char *label_ID, int row);
- void connect (Account **acct);
+ void connect (StockTransactionEntry*);
void set (Account *acct) { gnc_account_sel_set_account (GNC_ACCOUNT_SEL (m_selector), acct, TRUE); }
Account *get () { return gnc_account_sel_get_account (GNC_ACCOUNT_SEL (m_selector)); }
};
static void
-gnc_account_sel_changed_cb (GtkWidget* widget, Account **acct)
+gnc_account_sel_changed_cb (GtkWidget* widget, StockTransactionEntry* entry)
{
g_return_if_fail (GNC_IS_ACCOUNT_SEL (widget));
- *acct = gnc_account_sel_get_account (GNC_ACCOUNT_SEL (widget));
+ entry->set_account(gnc_account_sel_get_account (GNC_ACCOUNT_SEL (widget)));
}
GncAccountSelector::GncAccountSelector (GtkBuilder *builder, AccountTypeList types,
@@ -1419,9 +1427,9 @@ GncAccountSelector::attach (GtkBuilder *builder, const char *table_ID,
}
void
-GncAccountSelector::connect (Account **acct)
+GncAccountSelector::connect (StockTransactionEntry* entry)
{
- g_signal_connect(m_selector, "account_sel_changed", G_CALLBACK (gnc_account_sel_changed_cb), acct);
+ g_signal_connect(m_selector, "account_sel_changed", G_CALLBACK (gnc_account_sel_changed_cb), entry);
}
/* Assistant page classes, one per page. */
@@ -1481,7 +1489,7 @@ PageTransType::prepare(StockAssistantModel *model)
set_transaction_types(model->m_txn_types.value());
change_txn_type (model);
- g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_type);
+ g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_type);
}
int
@@ -1536,8 +1544,8 @@ struct PageTransDeets
PageTransDeets (GtkBuilder *builder);
time64 get_date_time () { return m_date.get_date_time(); }
const char* get_description () { return gtk_entry_get_text (GTK_ENTRY (m_description)); }
- void connect (time64 *date, const char **description);
- void prepare(time64 *date, const char** description);
+ void connect (StockAssistantModel*);
+ void prepare(StockAssistantModel*);
};
PageTransDeets::PageTransDeets (GtkBuilder *builder) :
@@ -1549,18 +1557,21 @@ PageTransDeets::PageTransDeets (GtkBuilder *builder) :
}
void
-PageTransDeets::connect(time64 *date, const char **description)
+PageTransDeets::connect(StockAssistantModel* model)
{
- m_date.connect(date);
- g_signal_connect(m_description, "changed", G_CALLBACK (text_entry_changed_cb), description);
+ m_date.connect(G_CALLBACK (stock_assistant_model_date_changed_cb),
+ static_cast<void*>(model));
+ g_signal_connect(m_description, "changed",
+ G_CALLBACK (stock_assistant_model_description_changed_cb),
+ static_cast<void*>(model));
}
void
-PageTransDeets::prepare(time64 *date, const char** description)
+PageTransDeets::prepare(StockAssistantModel* model)
{
- *date = get_date_time();
- *description = get_description();
- g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_description);
+ model->set_transaction_date(get_date_time());
+ model->set_transaction_desc(get_description());
+ g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_description);
}
struct PageStockAmount
@@ -1577,7 +1588,7 @@ struct PageStockAmount
void prepare (StockTransactionStockEntry*);
gnc_numeric get_stock_amount () { return m_amount.get(); }
void set_stock_amount (std::string new_amount_str);
- void connect(StockAssistantModel *model);
+ void connect(StockTransactionEntry* entry);
};
PageStockAmount::PageStockAmount (GtkBuilder *builder, Account* account) :
@@ -1609,21 +1620,21 @@ PageStockAmount::prepare (StockTransactionStockEntry* entry)
if (!gnc_numeric_check(get_stock_amount()))
entry->set_amount(get_stock_amount());
set_stock_amount(entry->amount_str_for_display());
- g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_amount.widget());
+ g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_amount.widget());
}
static void
-page_stock_amount_changed_cb(GtkWidget *widget, StockAssistantModel *model)
+page_stock_amount_changed_cb(GtkWidget *widget, StockTransactionEntry* entry)
{
auto me = static_cast<PageStockAmount*>(g_object_get_data (G_OBJECT (widget), "owner"));
- model->m_stock_entry->set_amount(me->m_amount.get());
- me->set_stock_amount (model->m_stock_entry->amount_str_for_display());
+ entry->set_amount(me->m_amount.get());
+ me->set_stock_amount (entry->amount_str_for_display());
}
void
-PageStockAmount::connect(StockAssistantModel *model)
+PageStockAmount::connect(StockTransactionEntry* entry)
{
- m_amount.connect(G_CALLBACK (page_stock_amount_changed_cb), model);
+ m_amount.connect(G_CALLBACK (page_stock_amount_changed_cb), entry);
m_amount.set_owner(static_cast<gpointer>(this));
}
@@ -1670,7 +1681,7 @@ PageStockValue::connect(StockTransactionEntry* entry)
{
m_value.connect(G_CALLBACK (page_stock_value_changed_cb), entry);
m_value.set_owner (static_cast<gpointer>(this));
- g_signal_connect (m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
+ g_signal_connect (m_memo, "changed", G_CALLBACK(text_entry_changed_cb), entry);
}
void
@@ -1680,7 +1691,7 @@ PageStockValue::prepare(StockTransactionEntry* entry)
if (!gnc_numeric_check(m_value.get()))
entry->set_value(m_value.get());
set_price(entry->print_price());
- g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
+ g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_value.widget());
}
const char *
@@ -1722,9 +1733,9 @@ PageCash::PageCash(GtkBuilder *builder, Account* account)
void
PageCash::connect(StockTransactionEntry* entry)
{
- m_account.connect(&entry->m_account);
- g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
- m_value.connect(&entry->m_value);
+ m_account.connect(entry);
+ g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), entry);
+ m_value.connect(G_CALLBACK(value_changed_cb), entry);
}
void
@@ -1734,7 +1745,7 @@ PageCash::prepare(StockTransactionEntry* entry)
if (!gnc_numeric_check(m_value.get()))
entry->set_value (m_value.get());
entry->m_account = m_account.get();
- g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
+ g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_value.widget());
}
const char *
@@ -1753,14 +1764,13 @@ struct PageFees
GncAmountEdit m_value;
Account* m_stock_account;
PageFees (GtkBuilder *builder, Account* account);
- void connect(StockTransactionFeesEntry*);
+ void connect(StockTransactionEntry*);
bool get_capitalize_fees ();
const char* get_memo();
void set_capitalize_fees (bool state);
- void set_capitalize_fees (StockTransactionFeesEntry*);
void set_account (Account *acct) { m_account.set(acct); }
void update_fees_acct_sensitive (bool sensitive);
- void prepare(StockTransactionFeesEntry*);
+ void prepare(StockTransactionEntry*);
};
PageFees::PageFees(GtkBuilder *builder, Account* account)
@@ -1796,12 +1806,6 @@ PageFees::set_capitalize_fees(bool state)
GTK_TOGGLE_BUTTON(m_capitalize), state);
}
-void
-PageFees::set_capitalize_fees(StockTransactionFeesEntry* entry)
-{
- set_capitalize_fees (entry->m_capitalize);
-}
-
void
PageFees::update_fees_acct_sensitive(bool sensitive)
{
@@ -1809,7 +1813,7 @@ PageFees::update_fees_acct_sensitive(bool sensitive)
}
static void
-capitalize_fees_toggled_cb (GtkWidget *widget, StockTransactionFeesEntry *entry)
+capitalize_fees_toggled_cb (GtkWidget *widget, StockTransactionEntry *entry)
{
g_return_if_fail (entry);
auto me = static_cast<PageFees *>(g_object_get_data (G_OBJECT (widget), "owner"));
@@ -1822,24 +1826,24 @@ capitalize_fees_toggled_cb (GtkWidget *widget, StockTransactionFeesEntry *entry)
}
void
-PageFees::connect(StockTransactionFeesEntry* entry)
+PageFees::connect(StockTransactionEntry* entry)
{
- m_account.connect(&entry->m_account);
- g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
- m_value.connect(&entry->m_value);
+ m_account.connect(entry);
+ g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), entry);
+ m_value.connect(G_CALLBACK(value_changed_cb), entry);
g_object_set_data(G_OBJECT (m_capitalize), "owner", this);
g_signal_connect (m_capitalize, "toggled", G_CALLBACK (capitalize_fees_toggled_cb), entry);
}
void
-PageFees::prepare(StockTransactionFeesEntry* entry)
+PageFees::prepare(StockTransactionEntry* entry)
{
- set_capitalize_fees (entry);
+ set_capitalize_fees (entry->do_capitalize());
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
entry->set_value (m_value.get());
entry->m_account = m_account.get();
- g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
+ g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_value.widget());
}
struct PageDividend
@@ -1869,9 +1873,9 @@ PageDividend::PageDividend(GtkBuilder *builder, Account* account)
void
PageDividend::connect(StockTransactionEntry* entry)
{
- m_account.connect(&entry->m_account);
- g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
- m_value.connect(&entry->m_value);
+ m_account.connect(entry);
+ g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), entry);
+ m_value.connect(G_CALLBACK(value_changed_cb), entry);
}
void
@@ -1881,7 +1885,7 @@ PageDividend::prepare(StockTransactionEntry* entry)
if (!gnc_numeric_check(m_value.get()))
entry->set_value(m_value.get());
entry->m_account = m_account.get();
- g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
+ g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_value.widget());
}
const char *
@@ -1923,9 +1927,9 @@ PageCapGain::get_memo()
void
PageCapGain::connect(StockTransactionEntry*entry)
{
- m_account.connect(&entry->m_account);
- g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
- m_value.connect(&entry->m_value);
+ m_account.connect(entry);
+ g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), entry);
+ m_value.connect(G_CALLBACK(value_changed_cb), entry);
}
void
@@ -1935,7 +1939,7 @@ PageCapGain::prepare(StockTransactionEntry* entry)
if (gnc_numeric_check(m_value.get()))
entry->set_value(m_value.get());
entry->m_account = m_account.get();
- g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
+ g_signal_connect(m_page, "focus", G_CALLBACK(assistant_page_set_focus), m_value.widget());
}
/* The last page of the assistant shows what the resulting transaction will look
@@ -2132,13 +2136,11 @@ void
StockAssistantController::connect_signals (GtkBuilder *builder)
{
m_view.m_type_page.connect(m_model.get());
- m_view.m_deets_page.connect(&m_model->m_transaction_date, &m_model->m_transaction_description);
- m_view.m_stock_amount_page.connect(m_model.get());
+ m_view.m_deets_page.connect(m_model.get());
+ m_view.m_stock_amount_page.connect(m_model->m_stock_entry.get());
m_view.m_stock_value_page.connect(m_model->m_stock_entry.get());
m_view.m_cash_page.connect(m_model->m_cash_entry.get());
- auto fees_entry = dynamic_cast<StockTransactionFeesEntry *>(m_model->m_fees_entry.get());
- if (fees_entry)
- m_view.m_fees_page.connect(fees_entry);
+ m_view.m_fees_page.connect(m_model->m_fees_entry.get());
m_view.m_dividend_page.connect(m_model->m_dividend_entry.get());
m_view.m_capgain_page.connect(m_model->m_capgains_entry.get());
@@ -2168,7 +2170,7 @@ StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
m_view.m_type_page.prepare(m_model.get());
break;
case PAGE_TRANSACTION_DETAILS:
- m_view.m_deets_page.prepare(&m_model->m_transaction_date, &m_model->m_transaction_description);
+ m_view.m_deets_page.prepare(m_model.get());
break;
case PAGE_STOCK_AMOUNT:
{
commit 8a60a3cf0f6633f8e1fee46f618099949d190606
Author: John Ralls <jralls at ceridwen.us>
Date: Tue Aug 29 09:49:34 2023 -0700
[stock-txn-asst] model::calculate_price becomes entry::print_price
Replace multiple-responsibility function in the wrong class with a
single-responsibility function in the right class.
Changes the signature of a couple of PageStockValue functions.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 8deafa6381..e4f000b7df 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -22,6 +22,7 @@
#include <config.h>
+#include <exception>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <cinttypes>
@@ -577,7 +578,8 @@ struct StockTransactionEntry
virtual const char* print_value(GNCPrintAmountInfo info);
virtual const char* print_amount(gnc_numeric amt);
virtual std::string amount_str_for_display() { return ""; }
- virtual gnc_numeric calculate_price() { return gnc_numeric_error(GNC_ERROR_ARG); }
+ virtual gnc_numeric calculate_price() const { return gnc_numeric_error(GNC_ERROR_ARG); }
+ virtual const char* print_price() const;
virtual bool has_amount() { return false; }
virtual void validate_amount(Logger&) const;
};
@@ -687,6 +689,18 @@ StockTransactionEntry::create_split(Transaction *trans, AccountVec &account_com
m_action));
}
+const char *
+StockTransactionEntry::print_price() const
+{
+ auto price{calculate_price()};
+ if (gnc_numeric_check(price))
+//Translators: "N/A" here means that a commodity doesn't have a valid price.
+ return _("N/A");
+ auto currency{gnc_account_get_currency_or_parent(m_account)};
+ auto pinfo{gnc_price_print_info(currency, TRUE)};
+ return xaccPrintAmount(price, pinfo);
+}
+
struct StockTransactionStockEntry : public StockTransactionEntry
{
bool m_amount_enabled;
@@ -707,7 +721,7 @@ struct StockTransactionStockEntry : public StockTransactionEntry
void set_amount(gnc_numeric amount) override;
void create_split(Transaction *trans, AccountVec &account_commits) override;
std::string amount_str_for_display() override;
- gnc_numeric calculate_price() override;
+ gnc_numeric calculate_price() const override;
bool has_amount() override { return m_amount_enabled; }
void validate_amount(Logger& logger) const override;
};
@@ -856,7 +870,7 @@ StockTransactionStockEntry::create_split(Transaction *trans, AccountVec &account
}
gnc_numeric
-StockTransactionStockEntry::calculate_price()
+StockTransactionStockEntry::calculate_price() const
{
if (m_input_new_balance ||
!m_amount_enabled || gnc_numeric_check(m_amount) ||
@@ -989,7 +1003,6 @@ struct StockAssistantModel
bool maybe_reset_txn_types ();
bool set_txn_type (guint type_idx);
std::string get_new_amount_str ();
- std::tuple<bool, gnc_numeric, const char*> calculate_price ();
std::tuple<bool, std::string, EntryVec> generate_list_of_splits ();
std::tuple<bool, Transaction*> create_transaction ();
@@ -1046,17 +1059,6 @@ StockAssistantModel::set_txn_type (guint type_idx)
return true;
};
-std::tuple<bool, gnc_numeric, const char*>
-StockAssistantModel::calculate_price ()
-{
- auto price{m_stock_entry->calculate_price()};
- if (gnc_numeric_check(price))
- return {false, price, nullptr};
- auto pinfo{gnc_price_print_info (m_currency, true)};
- PINFO("Model Price %s", xaccPrintAmount(price, pinfo));
- return {true, price, xaccPrintAmount (price, pinfo)};
-}
-
static void
check_txn_date(GList* last_split_node, time64 txn_date, Logger& logger)
{
@@ -1106,8 +1108,8 @@ StockAssistantModel::generate_list_of_splits() {
m_stock_entry->validate_amount(m_logger);
m_list_of_splits.push_back(m_stock_entry.get());
- auto [has_price, price, price_str] = calculate_price ();
- if (has_price)
+ auto price{m_stock_entry->calculate_price()};
+ if (!gnc_numeric_check(price))
{
// Translators: %s refer to: stock mnemonic, broker currency,
// date of transaction.
@@ -1116,7 +1118,7 @@ StockAssistantModel::generate_list_of_splits() {
auto price_msg = g_strdup_printf
(_(tmpl),
gnc_commodity_get_mnemonic (xaccAccountGetCommodity (m_acct)),
- price_str, date_str);
+ m_stock_entry->print_price(), date_str);
m_logger.info(price_msg);
g_free (date_str);
}
@@ -1217,8 +1219,8 @@ StockAssistantModel::create_transaction ()
void
StockAssistantModel::add_price (QofBook *book)
{
- auto [has_price, p, price_str] = calculate_price ();
- if (!has_price)
+ auto stock_price{m_stock_entry->calculate_price()};
+ if (gnc_numeric_check(stock_price))
return;
auto price = gnc_price_create (book);
@@ -1228,7 +1230,7 @@ StockAssistantModel::add_price (QofBook *book)
gnc_price_set_time64 (price, m_transaction_date);
gnc_price_set_source (price, PRICE_SOURCE_STOCK_TRANSACTION);
gnc_price_set_typestr (price, PRICE_TYPE_UNK);
- gnc_price_set_value (price, p);
+ gnc_price_set_value (price, stock_price);
gnc_price_commit_edit (price);
auto pdb = gnc_pricedb_get_db (book);
@@ -1640,19 +1642,18 @@ struct PageStockValue
GtkWidget * m_memo;
PageStockValue (GtkBuilder *builder, Account* account);
const char* get_memo ();
- void connect(StockAssistantModel *model);
- void prepare(StockTransactionEntry*, StockAssistantModel*);
+ void connect(StockTransactionEntry* entry);
+ void prepare(StockTransactionEntry* entry);
void set_price(const gchar *val);
- void set_price (std::tuple<bool, gnc_numeric, const char*> price_tuple);
};
static void
-page_stock_value_changed_cb(GtkWidget *widget, StockAssistantModel *model)
+page_stock_value_changed_cb(GtkWidget *widget, StockTransactionEntry* entry)
{
auto me = static_cast<PageStockValue*>(g_object_get_data (G_OBJECT (widget), "owner"));
auto value = me->m_value.get ();
- model->m_stock_entry->set_value (value);
- me->set_price (model->calculate_price());
+ entry->set_value (value);
+ me->set_price (entry->print_price());
}
PageStockValue::PageStockValue(GtkBuilder *builder, Account* account)
@@ -1665,20 +1666,20 @@ PageStockValue::PageStockValue(GtkBuilder *builder, Account* account)
}
void
-PageStockValue::connect(StockAssistantModel *model)
+PageStockValue::connect(StockTransactionEntry* entry)
{
- m_value.connect(G_CALLBACK (page_stock_value_changed_cb), model);
+ m_value.connect(G_CALLBACK (page_stock_value_changed_cb), entry);
m_value.set_owner (static_cast<gpointer>(this));
- g_signal_connect (m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &model->m_stock_entry->m_memo);
+ g_signal_connect (m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
}
void
-PageStockValue::prepare(StockTransactionEntry* entry, StockAssistantModel* model)
+PageStockValue::prepare(StockTransactionEntry* entry)
{
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
entry->set_value(m_value.get());
- set_price(model->calculate_price());
+ set_price(entry->print_price());
g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
}
@@ -1694,14 +1695,6 @@ PageStockValue::set_price (const gchar *val)
gtk_label_set_text(GTK_LABEL(this->m_price), val);
};
-void
-PageStockValue::set_price (std::tuple<bool, gnc_numeric, const char*> price_tuple)
-{
- auto [has_price, price, price_str] = price_tuple;
- // Translators: StockAssistant: N/A denotes stock price is not computable
- set_price(has_price ? price_str : _("N/A"));
-}
-
struct PageCash
{
// cash page
@@ -2141,7 +2134,7 @@ StockAssistantController::connect_signals (GtkBuilder *builder)
m_view.m_type_page.connect(m_model.get());
m_view.m_deets_page.connect(&m_model->m_transaction_date, &m_model->m_transaction_description);
m_view.m_stock_amount_page.connect(m_model.get());
- m_view.m_stock_value_page.connect(m_model.get());
+ m_view.m_stock_value_page.connect(m_model->m_stock_entry.get());
m_view.m_cash_page.connect(m_model->m_cash_entry.get());
auto fees_entry = dynamic_cast<StockTransactionFeesEntry *>(m_model->m_fees_entry.get());
if (fees_entry)
@@ -2185,7 +2178,7 @@ StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
break;
}
case PAGE_STOCK_VALUE:
- m_view.m_stock_value_page.prepare(m_model->m_stock_entry.get(), m_model.get());
+ m_view.m_stock_value_page.prepare(m_model->m_stock_entry.get());
break;
case PAGE_CASH:
m_view.m_cash_page.prepare(m_model->m_cash_entry.get());
commit 2e1a8bc8a7a8f75133d219e8c38e2daa0e314393
Author: John Ralls <jralls at ceridwen.us>
Date: Mon Aug 28 16:41:01 2023 -0700
[stock-txn-asst] Separate setting the amount/value and validating it.
Setting happens via callbacks and they were handed direct access
to the member variables so the validation wasn't happening.
Validation also requires a logger and passing that to the callbacks
would be hard.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 10bdd242c4..8deafa6381 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -568,17 +568,18 @@ struct StockTransactionEntry
virtual void set_fieldmask(FieldMask mask);
virtual void set_capitalize(bool capitalize) {}
- virtual void set_value(gnc_numeric amount, Logger& logger);
+ virtual void set_value(gnc_numeric amount);
virtual gnc_numeric amount() { return m_value; }
virtual void set_balance(gnc_numeric balance) { m_balance = balance; }
virtual gnc_numeric get_balance() { return m_balance; }
- virtual void set_amount(gnc_numeric, Logger&) {}
+ virtual void set_amount(gnc_numeric) {}
virtual void create_split(Transaction* trans, AccountVec& commits);
virtual const char* print_value(GNCPrintAmountInfo info);
virtual const char* print_amount(gnc_numeric amt);
virtual std::string amount_str_for_display() { return ""; }
virtual gnc_numeric calculate_price() { return gnc_numeric_error(GNC_ERROR_ARG); }
virtual bool has_amount() { return false; }
+ virtual void validate_amount(Logger&) const;
};
using StockTransactionEntryPtr = std::unique_ptr<StockTransactionEntry>;
@@ -594,12 +595,29 @@ StockTransactionEntry::set_fieldmask(FieldMask mask)
void
-StockTransactionEntry::set_value(gnc_numeric amount, Logger& logger)
+StockTransactionEntry::set_value(gnc_numeric amount)
{
DEBUG ("checking value %s page %s",
gnc_num_dbg_to_string (amount),
m_action);
+ if (gnc_numeric_check (amount))
+ return;
+
+ if (gnc_numeric_negative_p (amount))
+ {
+ m_value = gnc_numeric_neg(amount);
+ m_debit_side = !m_debit_side;
+ }
+ else
+ {
+ m_value = amount;
+ }
+}
+
+void
+StockTransactionEntry::validate_amount(Logger& logger) const
+{
auto add_error = [&logger](const char* format_str, const char* arg)
{
char *buf = g_strdup_printf (_(format_str),
@@ -609,33 +627,18 @@ StockTransactionEntry::set_value(gnc_numeric amount, Logger& logger)
};
- if (gnc_numeric_check (amount))
+ if (gnc_numeric_check (m_value))
{
- add_error (N_("Amount for %s is missing."), m_action);
+ if (!m_allow_zero)
+ add_error (N_("Amount for %s is missing."), m_action);
return;
}
- if (gnc_numeric_negative_p (amount))
- {
- if (m_allow_negative)
- {
- m_value = gnc_numeric_neg(amount);
- m_debit_side = !m_debit_side;
- }
- else
- {
- if (m_allow_zero)
- add_error (N_("Amount for %s must not be negative."), m_action);
- }
- }
+ if (gnc_numeric_negative_p (m_value) && !m_allow_negative && m_allow_zero)
+ add_error (N_("Amount for %s must not be negative."), m_action);
- if (!m_allow_zero && !gnc_numeric_positive_p (amount))
- {
+ if (!m_allow_zero && !gnc_numeric_positive_p (m_value))
add_error (N_("Amount for %s must be positive."), m_action);
- return;
- }
-
- m_value = amount;
}
const char *
@@ -701,11 +704,12 @@ struct StockTransactionStockEntry : public StockTransactionEntry
}
void set_fieldmask(FieldMask mask) override;
gnc_numeric amount() override { return m_amount; }
- void set_amount(gnc_numeric amount, Logger& logger) override;
+ void set_amount(gnc_numeric amount) override;
void create_split(Transaction *trans, AccountVec &account_commits) override;
std::string amount_str_for_display() override;
gnc_numeric calculate_price() override;
bool has_amount() override { return m_amount_enabled; }
+ void validate_amount(Logger& logger) const override;
};
void
@@ -720,15 +724,40 @@ StockTransactionStockEntry::set_fieldmask(FieldMask mask)
void
-StockTransactionStockEntry::set_amount(gnc_numeric amount, Logger& logger)
+StockTransactionStockEntry::set_amount(gnc_numeric amount)
{
- if (!m_amount_enabled)
+ if (!m_amount_enabled || gnc_numeric_check(amount))
+ return;
+
+ if (m_input_new_balance)
+ {
+ if (m_debit_side)
+ m_amount = gnc_numeric_sub_fixed(amount, m_balance);
+ else
+ m_amount = gnc_numeric_sub_fixed(m_balance, amount);
+
+ PINFO("%s set amount for new balance %s", m_memo, print_amount(m_amount));
+ }
+ else
+ {
+ m_amount = amount;
+ PINFO("%s set amount %s", m_memo, print_amount(m_amount));
+ }
+}
+
+void
+StockTransactionStockEntry::validate_amount(Logger& logger) const
+{
+ if (m_enabled)
+ StockTransactionEntry::validate_amount(logger);
+
+ if (!m_amount_enabled)
return;
auto add_error_str = [&logger]
(const char* str) { logger.error (_(str)); };
- if (gnc_numeric_check(amount) || gnc_numeric_zero_p(amount))
+ if (gnc_numeric_check(m_amount) || gnc_numeric_zero_p(m_amount))
{
add_error_str(_("Amount for stock value is missing."));
return;
@@ -736,33 +765,30 @@ StockTransactionStockEntry::set_amount(gnc_numeric amount, Logger& logger)
if (m_input_new_balance)
{
+ auto amount = gnc_numeric_add_fixed(m_debit_side ? m_amount : gnc_numeric_neg(m_amount), m_balance);
auto delta = gnc_numeric_sub_fixed(amount, m_balance);
auto ratio = gnc_numeric_div(amount, m_balance,
GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
- if (m_debit_side)
- m_amount = gnc_numeric_sub_fixed(amount, m_balance);
- else
- m_amount = gnc_numeric_sub_fixed(m_balance, amount);
+
if (gnc_numeric_check(ratio) || !gnc_numeric_positive_p(ratio))
add_error_str(N_("Invalid stock new balance."));
else if (gnc_numeric_negative_p(delta) && m_debit_side)
add_error_str(N_("New balance must be higher than old balance."));
else if (gnc_numeric_positive_p(delta) && !m_debit_side)
add_error_str(N_("New balance must be lower than old balance."));
- PINFO("%s set amount for new balance %s", m_memo, print_amount(m_amount));
+
+ PINFO("Delta %" PRId64 "/%" PRId64 ", Ratio %" PRId64 "/%" PRId64, delta.num, delta.denom, ratio.num, ratio.denom);
return;
}
- if (!gnc_numeric_positive_p(amount))
+ if (!gnc_numeric_positive_p(m_amount))
add_error_str(N_("Stock amount must be positive."));
- auto new_bal = gnc_numeric_add_fixed(m_balance, amount);
+
+ auto new_bal = gnc_numeric_add_fixed(m_balance, m_amount);
if (gnc_numeric_positive_p(m_balance) && gnc_numeric_negative_p(new_bal))
add_error_str(N_("Cannot sell more units than owned."));
else if (gnc_numeric_negative_p(m_balance) && gnc_numeric_positive_p(new_bal))
add_error_str(N_("Cannot cover buy more units than owed."));
-
- m_amount = amount;
- PINFO("%s set amount %s", m_memo, print_amount(m_amount));
}
std::string
@@ -1077,6 +1103,7 @@ StockAssistantModel::generate_list_of_splits() {
if (m_stock_entry->m_enabled || m_stock_entry->has_amount())
{
+ m_stock_entry->validate_amount(m_logger);
m_list_of_splits.push_back(m_stock_entry.get());
auto [has_price, price, price_str] = calculate_price ();
@@ -1096,21 +1123,31 @@ StockAssistantModel::generate_list_of_splits() {
}
if (m_cash_entry->m_enabled)
+ {
+ m_cash_entry->validate_amount(m_logger);
m_list_of_splits.push_back (m_cash_entry.get());
+ }
if (m_fees_entry->m_enabled)
+ {
+ m_fees_entry->validate_amount(m_logger);
m_list_of_splits.push_back (m_fees_entry.get());
+ }
if (m_dividend_entry->m_enabled)
+ {
+ m_dividend_entry->validate_amount(m_logger);
m_list_of_splits.push_back (m_dividend_entry.get());
+ }
if (m_capgains_entry->m_enabled)
{
m_stock_cg_entry =
std::make_unique<StockTransactionStockCapGainsEntry>(m_capgains_entry.get(),
m_stock_entry.get());
+ m_stock_cg_entry->validate_amount(m_logger);
+ m_capgains_entry->validate_amount(m_logger);
m_list_of_splits.push_back(m_stock_cg_entry.get());
-
m_list_of_splits.push_back (m_capgains_entry.get());
}
@@ -1535,7 +1572,7 @@ struct PageStockAmount
GncAmountEdit m_amount;
GtkWidget * m_amount_label;
PageStockAmount (GtkBuilder *builder, Account* account);
- void prepare (StockTransactionStockEntry*, Logger&);
+ void prepare (StockTransactionStockEntry*);
gnc_numeric get_stock_amount () { return m_amount.get(); }
void set_stock_amount (std::string new_amount_str);
void connect(StockAssistantModel *model);
@@ -1554,7 +1591,7 @@ PageStockAmount::PageStockAmount (GtkBuilder *builder, Account* account) :
}
void
-PageStockAmount::prepare (StockTransactionStockEntry* entry, Logger& logger)
+PageStockAmount::prepare (StockTransactionStockEntry* entry)
{
gtk_label_set_text_with_mnemonic
(GTK_LABEL (m_amount_label),
@@ -1568,7 +1605,7 @@ PageStockAmount::prepare (StockTransactionStockEntry* entry, Logger& logger)
_("Enter the number of shares you gained or lost in the transaction."));
gtk_label_set_text (GTK_LABEL (m_prev_amount), entry->print_amount(entry->get_balance()));
if (!gnc_numeric_check(get_stock_amount()))
- entry->set_amount(get_stock_amount(), logger);
+ entry->set_amount(get_stock_amount());
set_stock_amount(entry->amount_str_for_display());
g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_amount.widget());
}
@@ -1577,7 +1614,7 @@ static void
page_stock_amount_changed_cb(GtkWidget *widget, StockAssistantModel *model)
{
auto me = static_cast<PageStockAmount*>(g_object_get_data (G_OBJECT (widget), "owner"));
- model->m_stock_entry->set_amount(me->m_amount.get(), model->m_logger);
+ model->m_stock_entry->set_amount(me->m_amount.get());
me->set_stock_amount (model->m_stock_entry->amount_str_for_display());
}
@@ -1604,7 +1641,7 @@ struct PageStockValue
PageStockValue (GtkBuilder *builder, Account* account);
const char* get_memo ();
void connect(StockAssistantModel *model);
- void prepare(StockTransactionEntry*, StockAssistantModel*, Logger&);
+ void prepare(StockTransactionEntry*, StockAssistantModel*);
void set_price(const gchar *val);
void set_price (std::tuple<bool, gnc_numeric, const char*> price_tuple);
};
@@ -1614,7 +1651,7 @@ page_stock_value_changed_cb(GtkWidget *widget, StockAssistantModel *model)
{
auto me = static_cast<PageStockValue*>(g_object_get_data (G_OBJECT (widget), "owner"));
auto value = me->m_value.get ();
- model->m_stock_entry->set_value (value, model->m_logger);
+ model->m_stock_entry->set_value (value);
me->set_price (model->calculate_price());
}
@@ -1636,11 +1673,11 @@ PageStockValue::connect(StockAssistantModel *model)
}
void
-PageStockValue::prepare(StockTransactionEntry* entry, StockAssistantModel* model, Logger& logger)
+PageStockValue::prepare(StockTransactionEntry* entry, StockAssistantModel* model)
{
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value(m_value.get(), logger);
+ entry->set_value(m_value.get());
set_price(model->calculate_price());
g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
}
@@ -1674,7 +1711,7 @@ struct PageCash
GncAmountEdit m_value;
PageCash (GtkBuilder *builder, Account* account);
void connect(StockTransactionEntry* entry);
- void prepare(StockTransactionEntry* entry, Logger& logger);
+ void prepare(StockTransactionEntry* entry);
const char* get_memo();
};
@@ -1698,11 +1735,11 @@ PageCash::connect(StockTransactionEntry* entry)
}
void
-PageCash::prepare(StockTransactionEntry* entry, Logger& logger)
+PageCash::prepare(StockTransactionEntry* entry)
{
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value (m_value.get(), logger);
+ entry->set_value (m_value.get());
entry->m_account = m_account.get();
g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
}
@@ -1730,7 +1767,7 @@ struct PageFees
void set_capitalize_fees (StockTransactionFeesEntry*);
void set_account (Account *acct) { m_account.set(acct); }
void update_fees_acct_sensitive (bool sensitive);
- void prepare(StockTransactionFeesEntry*, Logger&);
+ void prepare(StockTransactionFeesEntry*);
};
PageFees::PageFees(GtkBuilder *builder, Account* account)
@@ -1802,12 +1839,12 @@ PageFees::connect(StockTransactionFeesEntry* entry)
}
void
-PageFees::prepare(StockTransactionFeesEntry* entry, Logger& logger)
+PageFees::prepare(StockTransactionFeesEntry* entry)
{
set_capitalize_fees (entry);
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value (m_value.get(), logger);
+ entry->set_value (m_value.get());
entry->m_account = m_account.get();
g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
}
@@ -1821,7 +1858,7 @@ struct PageDividend
GncAmountEdit m_value;
PageDividend (GtkBuilder *builder, Account* account);
void connect(StockTransactionEntry*);
- void prepare(StockTransactionEntry*, Logger&);
+ void prepare(StockTransactionEntry*);
const char* get_memo();
};
@@ -1845,11 +1882,11 @@ PageDividend::connect(StockTransactionEntry* entry)
}
void
-PageDividend::prepare(StockTransactionEntry* entry, Logger& logger)
+PageDividend::prepare(StockTransactionEntry* entry)
{
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value(m_value.get(), logger);
+ entry->set_value(m_value.get());
entry->m_account = m_account.get();
g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
}
@@ -1869,7 +1906,7 @@ struct PageCapGain
GncAmountEdit m_value;
PageCapGain (GtkBuilder *builder, Account* account);
void connect(StockTransactionEntry* entry);
- void prepare(StockTransactionEntry* entry, Logger& logger);
+ void prepare(StockTransactionEntry* entry);
const char* get_memo();
};
@@ -1899,11 +1936,11 @@ PageCapGain::connect(StockTransactionEntry*entry)
}
void
-PageCapGain::prepare(StockTransactionEntry* entry, Logger& logger)
+PageCapGain::prepare(StockTransactionEntry* entry)
{
entry->m_memo = get_memo();
if (gnc_numeric_check(m_value.get()))
- entry->set_value(m_value.get(), logger);
+ entry->set_value(m_value.get());
entry->m_account = m_account.get();
g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
}
@@ -2144,28 +2181,28 @@ StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
{
auto stock_entry = dynamic_cast<StockTransactionStockEntry*>(m_model->m_stock_entry.get());
if (stock_entry)
- m_view.m_stock_amount_page.prepare(stock_entry, m_model->m_logger);
+ m_view.m_stock_amount_page.prepare(stock_entry);
break;
}
case PAGE_STOCK_VALUE:
- m_view.m_stock_value_page.prepare(m_model->m_stock_entry.get(), m_model.get(), m_model->m_logger);
+ m_view.m_stock_value_page.prepare(m_model->m_stock_entry.get(), m_model.get());
break;
case PAGE_CASH:
- m_view.m_cash_page.prepare(m_model->m_cash_entry.get(), m_model->m_logger);
+ m_view.m_cash_page.prepare(m_model->m_cash_entry.get());
break;
case PAGE_FEES:
{
auto fees_entry = dynamic_cast<StockTransactionFeesEntry*>(m_model->m_fees_entry.get());
if (fees_entry)
- m_view.m_fees_page.prepare(fees_entry, m_model->m_logger);
+ m_view.m_fees_page.prepare(fees_entry);
break;
}
case PAGE_DIVIDEND:
- m_view.m_dividend_page.prepare(m_model->m_dividend_entry.get(), m_model->m_logger);
+ m_view.m_dividend_page.prepare(m_model->m_dividend_entry.get());
break;
case PAGE_CAPGAINS:
{
- m_view.m_capgain_page.prepare(m_model->m_capgains_entry.get(), m_model->m_logger);
+ m_view.m_capgain_page.prepare(m_model->m_capgains_entry.get());
break;
}
case PAGE_FINISH:
diff --git a/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp b/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
index 09ab9e5c7b..aff6d54c4c 100644
--- a/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
+++ b/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
@@ -173,17 +173,17 @@ StockAssistantTest::instantiate_model(StockAssistantModel &model, const ASTTestC
model.set_txn_type (t.type_idx);
model.m_transaction_description = t.desc;
- stock_entry->set_amount(gnc_numeric_create (t.stock_amt, 1), model.m_logger);
- model.m_stock_entry->m_value = gnc_numeric_create (t.stock_val, 100);
- model.m_cash_entry->m_value = gnc_numeric_create (t.cash_val, 100);
+ stock_entry->set_amount(gnc_numeric_create (t.stock_amt, 1));
+ model.m_stock_entry->set_value(gnc_numeric_create (t.stock_val, 100));
+ model.m_cash_entry->set_value(gnc_numeric_create (t.cash_val, 100));
model.m_cash_entry->m_account = cash_account;
model.m_fees_entry->m_account = fees_account;
fees_entry->m_capitalize = t.capitalize;
- model.m_fees_entry->m_value = gnc_numeric_create (t.fees_val, 100);
+ model.m_fees_entry->set_value(gnc_numeric_create (t.fees_val, 100));
model.m_capgains_entry->m_account = capgains_account;
- model.m_capgains_entry->m_value = gnc_numeric_create (t.capg_val, 100);
+ model.m_capgains_entry->set_value(gnc_numeric_create (t.capg_val, 100));
model.m_dividend_entry->m_account = dividend_account;
- model.m_dividend_entry->m_value = gnc_numeric_create (t.divi_val, 100);
+ model.m_dividend_entry->set_value(gnc_numeric_create (t.divi_val, 100));
}
class StockAssistantTestParameterized :
commit a31eefd6735ba003e34c00796ea553c1c7e0ce23
Author: John Ralls <jralls at ceridwen.us>
Date: Sun Aug 27 16:41:23 2023 -0700
[stock-txn-asst] Fix setting the initial focussed widget.
One can't grab the widget in prepare, the page runs its own focus so
one must handle the page's focus event.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 265a9a4c22..10bdd242c4 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -1265,10 +1265,12 @@ struct GncAmountEdit
GncAmountEdit (GtkBuilder *builder, gnc_commodity *commodity);
void attach (GtkBuilder *builder, const char *table_id,
const char *label_ID, int row);
+ GtkWidget* widget() {
+ return gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT(m_edit));
+ }
gnc_numeric get ();
void connect (gnc_numeric *value);
void connect (GCallback cb, gpointer data);
- void set_focus();
void set_owner (gpointer obj);
};
@@ -1324,12 +1326,6 @@ GncAmountEdit::connect (GCallback cb, gpointer data)
g_signal_connect(m_edit, "changed", cb, data);
}
-void
-GncAmountEdit::set_focus()
-{
- gtk_widget_grab_focus (GTK_WIDGET (gnc_amount_edit_gtk_entry (GNC_AMOUNT_EDIT (m_edit))));
-}
-
void
GncAmountEdit::set_owner(gpointer obj)
{
@@ -1389,7 +1385,24 @@ GncAccountSelector::connect (Account **acct)
g_signal_connect(m_selector, "account_sel_changed", G_CALLBACK (gnc_account_sel_changed_cb), acct);
}
-/* Assistant page classes. */
+/* Assistant page classes, one per page. */
+
+/* When an assistant page (a GtkContainer) is displayed it emits a
+ * focus signal. This handler grabs the passed-in widget so that it
+ * will have the initial focus instead of the first item on the
+ * page. The focus signal is also used by GtkContainer to handle tab
+ * and arrow keys, so we immediately disconnect it to allow them to
+ * function. It's connected in the page's prepare function instead of
+ * the connect one so that it can set the initial focus every time the
+ * user visits the page.
+ */
+static void
+assistant_page_set_focus(GtkWidget* page, [[maybe_unused]]GtkDirectionType type, GtkWidget* entry)
+{
+ gtk_widget_grab_focus(entry);
+ g_signal_handlers_disconnect_by_data(page, entry);
+}
+
struct PageTransType {
// transaction type page
@@ -1401,7 +1414,6 @@ struct PageTransType {
int get_transaction_type_index ();
void set_transaction_types (const TxnTypeVec& txn_types);
void set_txn_type_explanation (const gchar *txt);
- void set_focus() { gtk_widget_grab_focus (m_type); }
void connect (StockAssistantModel *model);
void change_txn_type (StockAssistantModel *model);
};
@@ -1430,7 +1442,7 @@ PageTransType::prepare(StockAssistantModel *model)
set_transaction_types(model->m_txn_types.value());
change_txn_type (model);
- set_focus();
+ g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_type);
}
int
@@ -1485,7 +1497,6 @@ struct PageTransDeets
PageTransDeets (GtkBuilder *builder);
time64 get_date_time () { return m_date.get_date_time(); }
const char* get_description () { return gtk_entry_get_text (GTK_ENTRY (m_description)); }
- void set_focus () { gtk_widget_grab_focus (m_description); }
void connect (time64 *date, const char **description);
void prepare(time64 *date, const char** description);
};
@@ -1510,7 +1521,7 @@ PageTransDeets::prepare(time64 *date, const char** description)
{
*date = get_date_time();
*description = get_description();
- set_focus ();
+ g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_description);
}
struct PageStockAmount
@@ -1559,8 +1570,7 @@ PageStockAmount::prepare (StockTransactionStockEntry* entry, Logger& logger)
if (!gnc_numeric_check(get_stock_amount()))
entry->set_amount(get_stock_amount(), logger);
set_stock_amount(entry->amount_str_for_display());
- m_amount.set_focus();
-
+ g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_amount.widget());
}
static void
@@ -1632,7 +1642,7 @@ PageStockValue::prepare(StockTransactionEntry* entry, StockAssistantModel* model
if (!gnc_numeric_check(m_value.get()))
entry->set_value(m_value.get(), logger);
set_price(model->calculate_price());
- m_value.set_focus();
+ g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
}
const char *
@@ -1694,7 +1704,7 @@ PageCash::prepare(StockTransactionEntry* entry, Logger& logger)
if (!gnc_numeric_check(m_value.get()))
entry->set_value (m_value.get(), logger);
entry->m_account = m_account.get();
- m_value.set_focus();
+ g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
}
const char *
@@ -1794,12 +1804,12 @@ PageFees::connect(StockTransactionFeesEntry* entry)
void
PageFees::prepare(StockTransactionFeesEntry* entry, Logger& logger)
{
- set_capitalize_fees (entry);
- entry->m_memo = get_memo();
- if (!gnc_numeric_check(m_value.get()))
- entry->set_value (m_value.get(), logger);
- entry->m_account = m_account.get();
- m_value.set_focus();
+ set_capitalize_fees (entry);
+ entry->m_memo = get_memo();
+ if (!gnc_numeric_check(m_value.get()))
+ entry->set_value (m_value.get(), logger);
+ entry->m_account = m_account.get();
+ g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
}
struct PageDividend
@@ -1841,7 +1851,7 @@ PageDividend::prepare(StockTransactionEntry* entry, Logger& logger)
if (!gnc_numeric_check(m_value.get()))
entry->set_value(m_value.get(), logger);
entry->m_account = m_account.get();
- m_value.set_focus();
+ g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
}
const char *
@@ -1895,7 +1905,7 @@ PageCapGain::prepare(StockTransactionEntry* entry, Logger& logger)
if (gnc_numeric_check(m_value.get()))
entry->set_value(m_value.get(), logger);
entry->m_account = m_account.get();
- m_value.set_focus();
+ g_signal_connect(m_page, "focus", (GCallback)assistant_page_set_focus, m_value.widget());
}
/* The last page of the assistant shows what the resulting transaction will look
@@ -2040,9 +2050,6 @@ struct StockAssistantView {
StockAssistantView(GtkBuilder *builder, Account* account, GtkWidget *parent);
~StockAssistantView();
- void set_focus (GtkWidget *widget) { gtk_widget_grab_focus (widget); }
- void set_focus_gae (GtkWidget *gae) { set_focus (GTK_WIDGET (gnc_amount_edit_gtk_entry (GNC_AMOUNT_EDIT (gae)))); }
-
};
StockAssistantView::StockAssistantView (GtkBuilder *builder, Account* account, GtkWidget *parent) :
commit c3f56e89e54499d4b6bf5348646ff52ce67f138b
Author: John Ralls <jralls at ceridwen.us>
Date: Sun Aug 27 12:21:40 2023 -0700
[stock-txn-asst] Handle correctly capitalizing fees.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index a6a79dad4c..265a9a4c22 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -887,16 +887,23 @@ void
StockTransactionFeesEntry::create_split(Transaction* trans, AccountVec& commits)
{
g_return_if_fail(trans);
- if (!m_account || !m_capitalize || gnc_numeric_check(m_value))
- return;
+ if ((!m_account && !m_capitalize) || gnc_numeric_check(m_value))
+ return;
auto split = xaccMallocSplit(qof_instance_get_book(trans));
xaccSplitSetParent(split, trans);
- xaccAccountBeginEdit(m_account);
- commits.push_back(m_account);
- xaccSplitSetAccount(split, m_account);
+ if (m_capitalize)
+ {
+ xaccSplitSetAccount(split, commits[0]); // Should be the stock account
+ }
+ else
+ {
+ xaccAccountBeginEdit(m_account);
+ commits.push_back(m_account);
+ xaccSplitSetAccount(split, m_account);
+ xaccSplitSetAmount(split, amount());
+ }
xaccSplitSetMemo(split, m_memo);
xaccSplitSetValue(split, m_debit_side ? m_value : gnc_numeric_neg(m_value));
- xaccSplitSetAmount(split, amount());
PINFO("creating %s split in Acct(%s): Val(%s), Amt(%s) => Val(%s), Amt(%s)",
m_action, m_account ? xaccAccountGetName (m_account) : "Empty!",
gnc_num_dbg_to_string(m_value),
diff --git a/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp b/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
index c380d6da7e..09ab9e5c7b 100644
--- a/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
+++ b/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
@@ -270,6 +270,6 @@ TEST_F(StockAssistantTest, testAggregateResults)
dump_acct (cash_account);
EXPECT_EQ (xaccAccountGetBalance (dividend_account).num, 42000);
EXPECT_EQ (xaccAccountGetBalance (capgains_account).num, -995981);
- EXPECT_EQ (xaccAccountGetBalance (fees_account).num, 5473);
+ EXPECT_EQ (xaccAccountGetBalance (fees_account).num, 4478);
EXPECT_EQ (xaccAccountGetBalance (cash_account).num, 1663049);
}
commit acff356fec1f2b95a22d7b8152b1efcc4a3681b0
Author: John Ralls <jralls at ceridwen.us>
Date: Sun Aug 27 12:19:43 2023 -0700
[stock-txn-asst] Set all the needed parameters for StockCGEntry.
So that it will create the split and do so with the right memo.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 43dace70a3..a6a79dad4c 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -560,9 +560,10 @@ struct StockTransactionEntry
StockTransactionEntry(const char* action) :
m_enabled{false}, m_debit_side{false}, m_allow_zero{false}, m_account{nullptr},
m_value{gnc_numeric_error(GNC_ERROR_ARG)}, m_memo{nullptr}, m_action{action} {}
- StockTransactionEntry(bool debit_side, bool allow_zero, bool allow_negative, Account* account, gnc_numeric value, const char* action) :
- m_enabled{false}, m_debit_side{debit_side}, m_allow_zero{allow_zero}, m_allow_negative{allow_negative},
- m_account{account}, m_value{value}, m_memo{nullptr}, m_action{action} {}
+ StockTransactionEntry(bool debit_side, bool allow_zero, bool allow_negative, Account* account,
+ gnc_numeric value, const char* memo, const char* action) :
+ m_enabled{true}, m_debit_side{debit_side}, m_allow_zero{allow_zero}, m_allow_negative{allow_negative},
+ m_account{account}, m_value{value}, m_memo{memo}, m_action{action} {}
virtual ~StockTransactionEntry() = default;
virtual void set_fieldmask(FieldMask mask);
@@ -862,7 +863,7 @@ struct StockTransactionStockCapGainsEntry : public StockTransactionEntry
StockTransactionStockCapGainsEntry::StockTransactionStockCapGainsEntry(const StockTransactionEntry *cg_entry,
const StockTransactionEntry *stk_entry) :
StockTransactionEntry(!cg_entry->m_debit_side, cg_entry->m_allow_zero, cg_entry->m_allow_negative,
- stk_entry->m_account, cg_entry->m_value, cg_entry->m_action) {}
+ stk_entry->m_account, cg_entry->m_value, cg_entry->m_memo, cg_entry->m_action) {}
struct StockTransactionFeesEntry : public StockTransactionEntry
{
commit fe728708ce7244f3c209b87cbbab3c46a4f35dd5
Author: John Ralls <jralls at ceridwen.us>
Date: Fri Aug 25 13:04:40 2023 -0700
[stock-txn-asst] Move stock amount calculation to StockEntry.
It's StockEntry's responsibility not Model's. This lets us remove
the model parameter from PageStockAmount::prepare. It also requires
that we use StockEntry's set_amount method instead of just setting
m_amount it StockAssistantTest::instantiate_model.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index c9d3e14b3e..43dace70a3 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -24,6 +24,7 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+#include <cinttypes>
#include <memory>
#include <vector>
#include <string>
@@ -546,10 +547,12 @@ struct StockTransactionEntry
bool m_debit_side;
bool m_allow_zero;
bool m_allow_negative;
+ bool m_input_new_balance = false;
Account *m_account;
gnc_numeric m_value;
const char* m_memo;
const char* m_action;
+ gnc_numeric m_balance = gnc_numeric_zero();
StockTransactionEntry() :
m_enabled{false}, m_debit_side{false}, m_allow_zero{false}, m_account{nullptr},
@@ -566,11 +569,14 @@ struct StockTransactionEntry
virtual void set_capitalize(bool capitalize) {}
virtual void set_value(gnc_numeric amount, Logger& logger);
virtual gnc_numeric amount() { return m_value; }
+ virtual void set_balance(gnc_numeric balance) { m_balance = balance; }
+ virtual gnc_numeric get_balance() { return m_balance; }
virtual void set_amount(gnc_numeric, Logger&) {}
virtual void create_split(Transaction* trans, AccountVec& commits);
virtual const char* print_value(GNCPrintAmountInfo info);
virtual const char* print_amount(gnc_numeric amt);
- virtual gnc_numeric calculate_price(bool) { return gnc_numeric_error(GNC_ERROR_ARG); }
+ virtual std::string amount_str_for_display() { return ""; }
+ virtual gnc_numeric calculate_price() { return gnc_numeric_error(GNC_ERROR_ARG); }
virtual bool has_amount() { return false; }
};
@@ -634,6 +640,8 @@ StockTransactionEntry::set_value(gnc_numeric amount, Logger& logger)
const char *
StockTransactionEntry::print_value(GNCPrintAmountInfo pinfo)
{
+ if (!m_enabled || (gnc_numeric_check(m_value) && m_allow_zero))
+ return nullptr;
if ((gnc_numeric_check(m_value) || gnc_numeric_zero_p(m_value))
&& !m_allow_zero)
return _("missing");
@@ -661,7 +669,8 @@ StockTransactionEntry::create_split(Transaction *trans, AccountVec &account_com
account_commits.push_back(m_account);
xaccSplitSetAccount(split, m_account);
xaccSplitSetMemo(split, m_memo);
- xaccSplitSetValue(split, m_debit_side ? m_value : gnc_numeric_neg(m_value));
+ if (m_enabled)
+ xaccSplitSetValue(split, m_debit_side ? m_value : gnc_numeric_neg(m_value));
xaccSplitSetAmount(split, amount());
PINFO("creating %s split in Acct(%s): Val(%s), Amt(%s) => Val(%s), Amt(%s)",
m_action, m_account ? xaccAccountGetName (m_account) : "Empty!",
@@ -693,7 +702,8 @@ struct StockTransactionStockEntry : public StockTransactionEntry
gnc_numeric amount() override { return m_amount; }
void set_amount(gnc_numeric amount, Logger& logger) override;
void create_split(Transaction *trans, AccountVec &account_commits) override;
- gnc_numeric calculate_price(bool new_balance) override;
+ std::string amount_str_for_display() override;
+ gnc_numeric calculate_price() override;
bool has_amount() override { return m_amount_enabled; }
};
@@ -704,6 +714,7 @@ StockTransactionStockEntry::set_fieldmask(FieldMask mask)
m_enabled = mask & (FieldMask::ENABLED_CREDIT | FieldMask::ENABLED_DEBIT);
m_amount_enabled = mask & (FieldMask::AMOUNT_CREDIT | FieldMask::AMOUNT_DEBIT);
m_debit_side = mask & (FieldMask::ENABLED_DEBIT | FieldMask::AMOUNT_DEBIT);
+ m_input_new_balance = mask & FieldMask::INPUT_NEW_BALANCE;
}
@@ -713,32 +724,99 @@ StockTransactionStockEntry::set_amount(gnc_numeric amount, Logger& logger)
if (!m_amount_enabled)
return;
+ auto add_error_str = [&logger]
+ (const char* str) { logger.error (_(str)); };
+
if (gnc_numeric_check(amount) || gnc_numeric_zero_p(amount))
{
- const char* err{_("Amount for stock value is missing.")};
+ add_error_str(_("Amount for stock value is missing."));
+ return;
+ }
- logger.error(err);
+ if (m_input_new_balance)
+ {
+ auto delta = gnc_numeric_sub_fixed(amount, m_balance);
+ auto ratio = gnc_numeric_div(amount, m_balance,
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+ if (m_debit_side)
+ m_amount = gnc_numeric_sub_fixed(amount, m_balance);
+ else
+ m_amount = gnc_numeric_sub_fixed(m_balance, amount);
+ if (gnc_numeric_check(ratio) || !gnc_numeric_positive_p(ratio))
+ add_error_str(N_("Invalid stock new balance."));
+ else if (gnc_numeric_negative_p(delta) && m_debit_side)
+ add_error_str(N_("New balance must be higher than old balance."));
+ else if (gnc_numeric_positive_p(delta) && !m_debit_side)
+ add_error_str(N_("New balance must be lower than old balance."));
+ PINFO("%s set amount for new balance %s", m_memo, print_amount(m_amount));
return;
}
- m_amount = m_debit_side ? amount : gnc_numeric_neg(amount);
- PINFO("%s set amount %s", m_memo, print_amount(amount));
+ if (!gnc_numeric_positive_p(amount))
+ add_error_str(N_("Stock amount must be positive."));
+ auto new_bal = gnc_numeric_add_fixed(m_balance, amount);
+ if (gnc_numeric_positive_p(m_balance) && gnc_numeric_negative_p(new_bal))
+ add_error_str(N_("Cannot sell more units than owned."));
+ else if (gnc_numeric_negative_p(m_balance) && gnc_numeric_positive_p(new_bal))
+ add_error_str(N_("Cannot cover buy more units than owed."));
+
+ m_amount = amount;
+ PINFO("%s set amount %s", m_memo, print_amount(m_amount));
}
+std::string
+StockTransactionStockEntry::amount_str_for_display()
+{
+ std::string rv{""};
+
+ if (gnc_numeric_check (m_amount))
+ return rv;
+
+ if (m_input_new_balance)
+ {
+ auto amount = gnc_numeric_add(m_debit_side ? m_amount : gnc_numeric_neg(m_amount), m_balance,
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+ auto ratio = gnc_numeric_div (amount, m_balance,
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+ PINFO("Computed ratio %" PRId64 "/%" PRId64 "; amount %" PRId64
+ "/%" PRId64 " and balance %" PRId64 "/%" PRId64,
+ ratio.num, ratio.denom, amount.num, amount.denom, m_balance.num, m_balance.denom);
+ if (gnc_numeric_check (ratio) || !gnc_numeric_positive_p (ratio))
+ return rv;
+
+ std::ostringstream ret;
+ ret << ratio.num << ':' << ratio.denom;
+ rv = ret.str();
+ }
+ else
+ {
+ auto amount = m_debit_side ? m_amount : gnc_numeric_neg (m_amount);
+ amount = gnc_numeric_add_fixed (amount, m_balance);
+ rv = print_amount(amount);
+ }
+
+ return rv;
+};
+
+
void
StockTransactionStockEntry::create_split(Transaction *trans, AccountVec &account_commits)
{
g_return_if_fail(trans);
- if (!m_account || gnc_numeric_check(m_value))
- return;
+ if (!m_account)
+ return;
auto split = xaccMallocSplit(qof_instance_get_book(trans));
xaccSplitSetParent(split, trans);
xaccAccountBeginEdit(m_account);
account_commits.push_back(m_account);
xaccSplitSetAccount(split, m_account);
xaccSplitSetMemo(split, m_memo);
- xaccSplitSetValue(split, m_debit_side ? m_value : gnc_numeric_neg(m_value));
- xaccSplitSetAmount(split, m_debit_side ? amount() : gnc_numeric_neg(amount()));
+ if (m_enabled)
+ xaccSplitSetValue(split, m_debit_side ? m_value : gnc_numeric_neg(m_value));
+ if (m_amount_enabled)
+ xaccSplitSetAmount(split, m_debit_side ? m_amount : gnc_numeric_neg(m_amount));
+ if (m_amount_enabled && !m_enabled) // It's a stock split
+ xaccSplitMakeStockSplit(split);
PINFO("creating %s split in Acct(%s): Val(%s), Amt(%s) => Val(%s), Amt(%s)",
m_action, m_account ? xaccAccountGetName (m_account) : "Empty!",
gnc_num_dbg_to_string(m_value),
@@ -751,9 +829,9 @@ StockTransactionStockEntry::create_split(Transaction *trans, AccountVec &account
}
gnc_numeric
-StockTransactionStockEntry::calculate_price(bool new_balance)
+StockTransactionStockEntry::calculate_price()
{
- if (new_balance ||
+ if (m_input_new_balance ||
!m_amount_enabled || gnc_numeric_check(m_amount) ||
!m_enabled || gnc_numeric_check(m_value) ||
gnc_numeric_zero_p(m_amount) || gnc_numeric_zero_p(m_value))
@@ -845,9 +923,6 @@ struct StockAssistantModel
std::optional<TxnTypeInfo> m_txn_type;
- gnc_numeric m_balance_at_date = gnc_numeric_create (1, 0);
-
- bool m_input_new_balance;
StockTransactionEntryPtr m_stock_entry;
StockTransactionEntryPtr m_cash_entry;
StockTransactionEntryPtr m_fees_entry;
@@ -879,11 +954,6 @@ struct StockAssistantModel
// current (i.e. transaction_date hasn't changed).
bool maybe_reset_txn_types ();
bool set_txn_type (guint type_idx);
- std::string get_stock_balance_str ()
- {
- return m_stock_entry->print_amount(m_balance_at_date);
- };
-
std::string get_new_amount_str ();
std::tuple<bool, gnc_numeric, const char*> calculate_price ();
std::tuple<bool, std::string, EntryVec> generate_list_of_splits ();
@@ -902,15 +972,16 @@ private:
bool
StockAssistantModel::maybe_reset_txn_types ()
{
+ auto old_bal = m_stock_entry->get_balance();
auto new_bal = xaccAccountGetBalanceAsOfDate
(m_acct, gnc_time64_get_day_end (m_transaction_date));
if (m_txn_types_date && m_txn_types_date == m_transaction_date &&
- gnc_numeric_equal (m_balance_at_date, new_bal))
+ gnc_numeric_equal (old_bal, new_bal))
return false;
- m_balance_at_date = new_bal;
+ m_stock_entry->set_balance(new_bal);
m_txn_types_date = m_transaction_date;
- m_txn_types = gnc_numeric_zero_p (m_balance_at_date) ? starting_types
- : gnc_numeric_positive_p (m_balance_at_date) ? long_types
+ m_txn_types = gnc_numeric_zero_p (new_bal) ? starting_types
+ : gnc_numeric_positive_p (new_bal) ? long_types
: short_types;
return true;
};
@@ -933,7 +1004,6 @@ StockAssistantModel::set_txn_type (guint type_idx)
return false;
}
- m_input_new_balance = m_txn_type->stock_amount & FieldMask::INPUT_NEW_BALANCE;
m_stock_entry->set_fieldmask(m_txn_type->stock_amount);
m_fees_entry->set_fieldmask(m_txn_type->fees_value);
m_capgains_entry->set_fieldmask(m_txn_type->capgains_value);
@@ -942,42 +1012,10 @@ StockAssistantModel::set_txn_type (guint type_idx)
return true;
};
-std::string
-StockAssistantModel::get_new_amount_str ()
-{
- std::string rv{""};
- auto stock_entry = dynamic_cast<StockTransactionStockEntry*>(m_stock_entry.get());
-
- if (gnc_numeric_check (stock_entry->m_amount))
- return rv;
-
- if (m_input_new_balance)
- {
- auto ratio = gnc_numeric_div (stock_entry->m_amount, m_balance_at_date,
- GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
- if (gnc_numeric_check (ratio) || !gnc_numeric_positive_p (ratio))
- return rv;
-
- std::ostringstream ret;
- ret << ratio.num << ':' << ratio.denom;
- rv = ret.str();
- }
- else
- {
- auto stock_entry = dynamic_cast<StockTransactionStockEntry*>(m_stock_entry.get());
- auto amount = (m_txn_type->stock_amount & FieldMask::ENABLED_CREDIT) ?
- gnc_numeric_neg (stock_entry->m_amount) : stock_entry->m_amount;
- amount = gnc_numeric_add_fixed (amount, m_balance_at_date);
- rv = m_stock_entry->print_amount(amount);
- }
-
- return rv;
-};
-
std::tuple<bool, gnc_numeric, const char*>
StockAssistantModel::calculate_price ()
{
- auto price{m_stock_entry->calculate_price(m_input_new_balance)};
+ auto price{m_stock_entry->calculate_price()};
if (gnc_numeric_check(price))
return {false, price, nullptr};
auto pinfo{gnc_price_print_info (m_currency, true)};
@@ -1010,45 +1048,6 @@ check_txn_date(GList* last_split_node, time64 txn_date, Logger& logger)
}
}
-StockTransactionEntry*
-StockAssistantModel::make_stock_split_info()
-{
- auto add_error_str = [this]
- (const char* str) { m_logger.error (_(str)); };
-
-
- if (m_input_new_balance)
- {
- auto stock_amount = m_stock_entry->amount();
- auto credit_side = (m_txn_type->stock_amount & FieldMask::AMOUNT_CREDIT);
- auto delta = gnc_numeric_sub_fixed(stock_amount, m_balance_at_date);
- auto ratio = gnc_numeric_div(stock_amount, m_balance_at_date,
- GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
- stock_amount = gnc_numeric_sub_fixed(stock_amount, m_balance_at_date);
- m_stock_entry->set_amount(stock_amount, m_logger);
- if (gnc_numeric_check(ratio) || !gnc_numeric_positive_p(ratio))
- add_error_str(N_("Invalid stock new balance."));
- else if (gnc_numeric_negative_p(delta) && !credit_side)
- add_error_str(N_("New balance must be higher than old balance."));
- else if (gnc_numeric_positive_p(delta) && credit_side)
- add_error_str(N_("New balance must be lower than old balance."));
- }
- else if (m_stock_entry->has_amount())
- {
- auto stock_amount = m_stock_entry->amount();
- if (!gnc_numeric_positive_p(stock_amount))
- add_error_str(N_("Stock amount must be positive."));
- auto new_bal = gnc_numeric_add_fixed(m_balance_at_date, stock_amount);
- if (gnc_numeric_positive_p(m_balance_at_date) &&
- gnc_numeric_negative_p(new_bal))
- add_error_str(N_("Cannot sell more units than owned."));
- else if (gnc_numeric_negative_p(m_balance_at_date) &&
- gnc_numeric_positive_p(new_bal))
- add_error_str(N_("Cannot cover buy more units than owed."));
- }
- return m_stock_entry.get();
-}
-
std::tuple<bool, std::string, EntryVec>
StockAssistantModel::generate_list_of_splits() {
if (!m_txn_types || !m_txn_type)
@@ -1068,10 +1067,9 @@ StockAssistantModel::generate_list_of_splits() {
if (last_split_node)
check_txn_date(last_split_node, m_transaction_date, m_logger);
- auto stock_entry{dynamic_cast<StockTransactionStockEntry*>(m_stock_entry.get())};
- if (stock_entry && (stock_entry->m_enabled || stock_entry->m_amount_enabled))
+ if (m_stock_entry->m_enabled || m_stock_entry->has_amount())
{
- m_list_of_splits.push_back (make_stock_split_info());
+ m_list_of_splits.push_back(m_stock_entry.get());
auto [has_price, price, price_str] = calculate_price ();
if (has_price)
@@ -1518,7 +1516,7 @@ struct PageStockAmount
GncAmountEdit m_amount;
GtkWidget * m_amount_label;
PageStockAmount (GtkBuilder *builder, Account* account);
- void prepare (StockTransactionStockEntry*, StockAssistantModel*, Logger&);
+ void prepare (StockTransactionStockEntry*, Logger&);
gnc_numeric get_stock_amount () { return m_amount.get(); }
void set_stock_amount (std::string new_amount_str);
void connect(StockAssistantModel *model);
@@ -1537,23 +1535,22 @@ PageStockAmount::PageStockAmount (GtkBuilder *builder, Account* account) :
}
void
-PageStockAmount::prepare (StockTransactionStockEntry* entry, StockAssistantModel* model,
- Logger& logger)
+PageStockAmount::prepare (StockTransactionStockEntry* entry, Logger& logger)
{
gtk_label_set_text_with_mnemonic
(GTK_LABEL (m_amount_label),
- model->m_input_new_balance ? _("Ne_w Balance") : _("_Shares"));
+ entry->m_input_new_balance ? _("Ne_w Balance") : _("_Shares"));
gtk_label_set_text
(GTK_LABEL (m_next_amount_label),
- model->m_input_new_balance ? _("Ratio") : _("Next Balance"));
+ entry->m_input_new_balance ? _("Ratio") : _("Next Balance"));
gtk_label_set_text (GTK_LABEL (m_title),
- model->m_input_new_balance ?
+ entry->m_input_new_balance ?
_("Enter the new balance of shares after the stock split.") :
_("Enter the number of shares you gained or lost in the transaction."));
- gtk_label_set_text (GTK_LABEL (m_prev_amount), model->get_stock_balance_str().c_str());
+ gtk_label_set_text (GTK_LABEL (m_prev_amount), entry->print_amount(entry->get_balance()));
if (!gnc_numeric_check(get_stock_amount()))
entry->set_amount(get_stock_amount(), logger);
- set_stock_amount(model->get_new_amount_str());
+ set_stock_amount(entry->amount_str_for_display());
m_amount.set_focus();
}
@@ -1563,7 +1560,7 @@ page_stock_amount_changed_cb(GtkWidget *widget, StockAssistantModel *model)
{
auto me = static_cast<PageStockAmount*>(g_object_get_data (G_OBJECT (widget), "owner"));
model->m_stock_entry->set_amount(me->m_amount.get(), model->m_logger);
- me->set_stock_amount (model->get_new_amount_str());
+ me->set_stock_amount (model->m_stock_entry->amount_str_for_display());
}
void
@@ -2132,7 +2129,7 @@ StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
{
auto stock_entry = dynamic_cast<StockTransactionStockEntry*>(m_model->m_stock_entry.get());
if (stock_entry)
- m_view.m_stock_amount_page.prepare(stock_entry, m_model.get(), m_model->m_logger);
+ m_view.m_stock_amount_page.prepare(stock_entry, m_model->m_logger);
break;
}
case PAGE_STOCK_VALUE:
@@ -2193,9 +2190,8 @@ forward_page_func (gint current_page, StockAssistantController* info)
current_page++;
if (!model->m_txn_type)
return current_page;
- auto stock_entry = dynamic_cast<StockTransactionStockEntry*>(model->m_stock_entry.get());
- if (!stock_entry->m_amount_enabled && current_page == PAGE_STOCK_AMOUNT)
+ if (!model->m_stock_entry->has_amount() && current_page == PAGE_STOCK_AMOUNT)
current_page++;
if (!model->m_stock_entry->m_enabled && current_page == PAGE_STOCK_VALUE)
current_page++;
diff --git a/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp b/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
index 636c04bb79..c380d6da7e 100644
--- a/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
+++ b/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
@@ -173,7 +173,7 @@ StockAssistantTest::instantiate_model(StockAssistantModel &model, const ASTTestC
model.set_txn_type (t.type_idx);
model.m_transaction_description = t.desc;
- stock_entry->m_amount = gnc_numeric_create (t.stock_amt * 100, 100);
+ stock_entry->set_amount(gnc_numeric_create (t.stock_amt, 1), model.m_logger);
model.m_stock_entry->m_value = gnc_numeric_create (t.stock_val, 100);
model.m_cash_entry->m_value = gnc_numeric_create (t.cash_val, 100);
model.m_cash_entry->m_account = cash_account;
commit 176ff44128020f2d5d8e79d774a199ce7a607546
Author: John Ralls <jralls at ceridwen.us>
Date: Fri Aug 25 12:09:26 2023 -0700
[stock-txn-asst] Remove StockTransactionSplitInfo
With action a StockTransactionEntry member it's no longer useful.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index eb1a9a65f8..c9d3e14b3e 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -829,26 +829,7 @@ StockTransactionFeesEntry::create_split(Transaction* trans, AccountVec& commits
m_action));
}
-struct StockTransactionSplitInfo
-{
- StockTransactionEntry* m_entry;
- bool m_units_in_red = false;
- static const char* s_missing_str;
-
- StockTransactionSplitInfo(StockTransactionEntry* entry) :
- m_entry{entry}
- {
- DEBUG ("StockTransactionSplitInfo constructor\n");
- }
-
- ~StockTransactionSplitInfo () { DEBUG ("StockTransactionSplitInfo destructor\n"); }
-};
-
-// Translators: (missing) denotes that the amount or account is
-// not provided, or incorrect, in the Stock Transaction Assistant.
-const char *StockTransactionSplitInfo::s_missing_str = N_("(missing)");
-
-using SplitInfoVec = std::vector<StockTransactionSplitInfo>;
+using EntryVec = std::vector<StockTransactionEntry*>;
/** Manages the data and actions for the assistant. */
struct StockAssistantModel
@@ -905,17 +886,17 @@ struct StockAssistantModel
std::string get_new_amount_str ();
std::tuple<bool, gnc_numeric, const char*> calculate_price ();
- std::tuple<bool, std::string, SplitInfoVec> generate_list_of_splits ();
+ std::tuple<bool, std::string, EntryVec> generate_list_of_splits ();
std::tuple<bool, Transaction*> create_transaction ();
private:
std::optional<time64> m_txn_types_date;
bool m_ready_to_create = false;
- SplitInfoVec m_list_of_splits;
+ EntryVec m_list_of_splits;
void add_price (QofBook *book);
- StockTransactionSplitInfo make_stock_split_info();
+ StockTransactionEntry* make_stock_split_info();
};
bool
@@ -1029,23 +1010,22 @@ check_txn_date(GList* last_split_node, time64 txn_date, Logger& logger)
}
}
-StockTransactionSplitInfo
+StockTransactionEntry*
StockAssistantModel::make_stock_split_info()
{
auto add_error_str = [this]
(const char* str) { m_logger.error (_(str)); };
- StockTransactionSplitInfo line{m_stock_entry.get()};
if (m_input_new_balance)
{
- auto stock_amount = line.m_entry->amount();
+ auto stock_amount = m_stock_entry->amount();
auto credit_side = (m_txn_type->stock_amount & FieldMask::AMOUNT_CREDIT);
auto delta = gnc_numeric_sub_fixed(stock_amount, m_balance_at_date);
auto ratio = gnc_numeric_div(stock_amount, m_balance_at_date,
GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
stock_amount = gnc_numeric_sub_fixed(stock_amount, m_balance_at_date);
- line.m_entry->set_amount(stock_amount, m_logger);
+ m_stock_entry->set_amount(stock_amount, m_logger);
if (gnc_numeric_check(ratio) || !gnc_numeric_positive_p(ratio))
add_error_str(N_("Invalid stock new balance."));
else if (gnc_numeric_negative_p(delta) && !credit_side)
@@ -1053,9 +1033,9 @@ StockAssistantModel::make_stock_split_info()
else if (gnc_numeric_positive_p(delta) && credit_side)
add_error_str(N_("New balance must be lower than old balance."));
}
- else if (line.m_entry->has_amount())
+ else if (m_stock_entry->has_amount())
{
- auto stock_amount = line.m_entry->amount();
+ auto stock_amount = m_stock_entry->amount();
if (!gnc_numeric_positive_p(stock_amount))
add_error_str(N_("Stock amount must be positive."));
auto new_bal = gnc_numeric_add_fixed(m_balance_at_date, stock_amount);
@@ -1066,10 +1046,10 @@ StockAssistantModel::make_stock_split_info()
gnc_numeric_positive_p(new_bal))
add_error_str(N_("Cannot cover buy more units than owed."));
}
- return line;
+ return m_stock_entry.get();
}
-std::tuple<bool, std::string, SplitInfoVec>
+std::tuple<bool, std::string, EntryVec>
StockAssistantModel::generate_list_of_splits() {
if (!m_txn_types || !m_txn_type)
return { false, "Error: txn_type not initialized", {} };
@@ -1110,22 +1090,22 @@ StockAssistantModel::generate_list_of_splits() {
}
if (m_cash_entry->m_enabled)
- m_list_of_splits.push_back (StockTransactionSplitInfo{m_cash_entry.get()});
+ m_list_of_splits.push_back (m_cash_entry.get());
if (m_fees_entry->m_enabled)
- m_list_of_splits.push_back (StockTransactionSplitInfo{m_fees_entry.get()});
+ m_list_of_splits.push_back (m_fees_entry.get());
if (m_dividend_entry->m_enabled)
- m_list_of_splits.push_back (StockTransactionSplitInfo{m_dividend_entry.get()});
+ m_list_of_splits.push_back (m_dividend_entry.get());
if (m_capgains_entry->m_enabled)
{
m_stock_cg_entry =
std::make_unique<StockTransactionStockCapGainsEntry>(m_capgains_entry.get(),
m_stock_entry.get());
- m_list_of_splits.push_back(StockTransactionSplitInfo{m_stock_cg_entry.get()});
+ m_list_of_splits.push_back(m_stock_cg_entry.get());
- m_list_of_splits.push_back (StockTransactionSplitInfo{m_capgains_entry.get()});
+ m_list_of_splits.push_back (m_capgains_entry.get());
}
if (gnc_numeric_check(debit) || gnc_numeric_check(credit) ||!gnc_numeric_equal (debit, credit))
@@ -1183,7 +1163,7 @@ StockAssistantModel::create_transaction ()
xaccTransSetDatePostedSecsNormalized (trans, m_transaction_date);
AccountVec accounts;
std::for_each (m_list_of_splits.begin(), m_list_of_splits.end(),
- [&](auto& line){ line.m_entry->create_split (trans, accounts); });
+ [&](auto& entry){ entry->create_split (trans, accounts); });
add_price (book);
xaccTransCommitEdit (trans);
std::for_each (accounts.begin(), accounts.end(), xaccAccountCommitEdit);
@@ -2005,10 +1985,10 @@ PageFinish::prepare (GtkWidget *window, StockAssistantModel *model)
GNC_PREF_NEGATIVE_IN_RED);
auto list = GTK_LIST_STORE(gtk_tree_view_get_model(gtv));
gtk_list_store_clear(list);
- for (const auto &line : list_of_splits) {
+ for (const auto &entry : list_of_splits) {
GtkTreeIter iter;
- auto tooltip = (line.m_entry->m_memo && *line.m_entry->m_memo ?
- g_markup_escape_text(line.m_entry->m_memo, -1) : strdup(""));
+ auto tooltip = (entry->m_memo && *entry->m_memo ?
+ g_markup_escape_text(entry->m_memo, -1) : strdup(""));
/* print_value and print_amount rely on xaccPrintAmount that
* uses static memory so the result needs to be copied
* immediately or the second call overwrites the results of
@@ -2016,20 +1996,20 @@ PageFinish::prepare (GtkWidget *window, StockAssistantModel *model)
*/
auto char2str{[](const char* str) -> std::string {
return std::string{ str ? str : "" }; }};
- auto amount{char2str(line.m_entry->print_value(model->m_curr_pinfo))};
- auto units{char2str(line.m_entry->has_amount() ?
- line.m_entry->print_amount(line.m_entry->m_debit_side ? line.m_entry->amount() :
- gnc_numeric_neg(line.m_entry->amount())) : "")};
- auto units_in_red{negative_in_red && !line.m_entry->m_debit_side};
+ auto amount{char2str(entry->print_value(model->m_curr_pinfo))};
+ auto units{char2str(entry->has_amount() ?
+ entry->print_amount(entry->m_debit_side ? entry->amount() :
+ gnc_numeric_neg(entry->amount())) : "")};
+ auto units_in_red{negative_in_red && !entry->m_debit_side};
gtk_list_store_append(list, &iter);
gtk_list_store_set(
list, &iter,
SPLIT_COL_ACCOUNT,
- line.m_entry->m_account ? xaccAccountGetName(line.m_entry->m_account) : "", SPLIT_COL_MEMO,
- line.m_entry->m_memo, SPLIT_COL_TOOLTIP, tooltip, SPLIT_COL_DEBIT,
- line.m_entry->m_debit_side ? amount.c_str() : nullptr,
+ entry->m_account ? xaccAccountGetName(entry->m_account) : "", SPLIT_COL_MEMO,
+ entry->m_memo, SPLIT_COL_TOOLTIP, tooltip, SPLIT_COL_DEBIT,
+ entry->m_debit_side ? amount.c_str() : nullptr,
SPLIT_COL_CREDIT,
- line.m_entry->m_debit_side ? nullptr : amount.c_str(),
+ entry->m_debit_side ? nullptr : amount.c_str(),
SPLIT_COL_UNITS, units.c_str(),
SPLIT_COL_UNITS_COLOR, units_in_red ? "red" : nullptr, -1);
g_free(tooltip);
commit 35946c8e1cb2612e3cc8e34cf0d5b69f9bca2501
Author: John Ralls <jralls at ceridwen.us>
Date: Fri Aug 25 11:53:02 2023 -0700
[stock-txn-asst] Make action a StockTransactionEntry member.
Instead of a function paramter that's set and translated
inconsistently.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 30cc749368..eb1a9a65f8 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -549,22 +549,25 @@ struct StockTransactionEntry
Account *m_account;
gnc_numeric m_value;
const char* m_memo;
+ const char* m_action;
StockTransactionEntry() :
m_enabled{false}, m_debit_side{false}, m_allow_zero{false}, m_account{nullptr},
- m_value{gnc_numeric_error(GNC_ERROR_ARG)}, m_memo{nullptr} {}
- StockTransactionEntry(bool debit_side, bool allow_zero, bool allow_negative, Account* account, gnc_numeric value) :
+ m_value{gnc_numeric_error(GNC_ERROR_ARG)}, m_memo{nullptr}, m_action{nullptr} {}
+ StockTransactionEntry(const char* action) :
+ m_enabled{false}, m_debit_side{false}, m_allow_zero{false}, m_account{nullptr},
+ m_value{gnc_numeric_error(GNC_ERROR_ARG)}, m_memo{nullptr}, m_action{action} {}
+ StockTransactionEntry(bool debit_side, bool allow_zero, bool allow_negative, Account* account, gnc_numeric value, const char* action) :
m_enabled{false}, m_debit_side{debit_side}, m_allow_zero{allow_zero}, m_allow_negative{allow_negative},
- m_account{account}, m_value{value}, m_memo{nullptr} {}
+ m_account{account}, m_value{value}, m_memo{nullptr}, m_action{action} {}
virtual ~StockTransactionEntry() = default;
virtual void set_fieldmask(FieldMask mask);
virtual void set_capitalize(bool capitalize) {}
- virtual void set_value(gnc_numeric amount, const char* page, Logger& logger);
+ virtual void set_value(gnc_numeric amount, Logger& logger);
virtual gnc_numeric amount() { return m_value; }
virtual void set_amount(gnc_numeric, Logger&) {}
- virtual void create_split(Transaction* trans, const char* action,
- AccountVec& commits);
+ virtual void create_split(Transaction* trans, AccountVec& commits);
virtual const char* print_value(GNCPrintAmountInfo info);
virtual const char* print_amount(gnc_numeric amt);
virtual gnc_numeric calculate_price(bool) { return gnc_numeric_error(GNC_ERROR_ARG); }
@@ -584,11 +587,11 @@ StockTransactionEntry::set_fieldmask(FieldMask mask)
void
-StockTransactionEntry::set_value(gnc_numeric amount, const char* page, Logger& logger)
+StockTransactionEntry::set_value(gnc_numeric amount, Logger& logger)
{
DEBUG ("checking value %s page %s",
gnc_num_dbg_to_string (amount),
- page);
+ m_action);
auto add_error = [&logger](const char* format_str, const char* arg)
{
@@ -601,7 +604,7 @@ StockTransactionEntry::set_value(gnc_numeric amount, const char* page, Logger& l
if (gnc_numeric_check (amount))
{
- add_error (N_("Amount for %s is missing."), page);
+ add_error (N_("Amount for %s is missing."), m_action);
return;
}
@@ -615,13 +618,13 @@ StockTransactionEntry::set_value(gnc_numeric amount, const char* page, Logger& l
else
{
if (m_allow_zero)
- add_error (N_("Amount for %s must not be negative."), page);
+ add_error (N_("Amount for %s must not be negative."), m_action);
}
}
if (!m_allow_zero && !gnc_numeric_positive_p (amount))
{
- add_error (N_("Amount for %s must be positive."), page);
+ add_error (N_("Amount for %s must be positive."), m_action);
return;
}
@@ -648,8 +651,7 @@ StockTransactionEntry::print_amount(gnc_numeric amt)
}
void
-StockTransactionEntry::create_split(Transaction *trans, const char* action,
- AccountVec &account_commits) {
+StockTransactionEntry::create_split(Transaction *trans, AccountVec &account_commits) {
g_return_if_fail(trans);
if (!m_account || gnc_numeric_check(m_value))
return;
@@ -662,14 +664,14 @@ StockTransactionEntry::create_split(Transaction *trans, const char* action,
xaccSplitSetValue(split, m_debit_side ? m_value : gnc_numeric_neg(m_value));
xaccSplitSetAmount(split, amount());
PINFO("creating %s split in Acct(%s): Val(%s), Amt(%s) => Val(%s), Amt(%s)",
- action, m_account ? xaccAccountGetName (m_account) : "Empty!",
+ m_action, m_account ? xaccAccountGetName (m_account) : "Empty!",
gnc_num_dbg_to_string(m_value),
gnc_num_dbg_to_string(amount()),
gnc_num_dbg_to_string(xaccSplitGetValue(split)),
gnc_num_dbg_to_string(xaccSplitGetAmount(split)));
gnc_set_num_action(nullptr, split, nullptr,
g_dpgettext2(nullptr, "Stock Assistant: Action field",
- action));
+ m_action));
}
struct StockTransactionStockEntry : public StockTransactionEntry
@@ -678,15 +680,19 @@ struct StockTransactionStockEntry : public StockTransactionEntry
gnc_numeric m_amount;
StockTransactionStockEntry() :
- StockTransactionEntry{},
- m_amount{gnc_numeric_error(GNC_ERROR_ARG)} {
+ StockTransactionEntry{}, m_amount{gnc_numeric_error(GNC_ERROR_ARG)}
+ {
+ PINFO("Stock Entry");
+ }
+ StockTransactionStockEntry(const char* action) :
+ StockTransactionEntry{action}, m_amount{gnc_numeric_error(GNC_ERROR_ARG)}
+ {
PINFO("Stock Entry");
}
void set_fieldmask(FieldMask mask) override;
gnc_numeric amount() override { return m_amount; }
void set_amount(gnc_numeric amount, Logger& logger) override;
- void create_split(Transaction *trans, const char* action,
- AccountVec &account_commits) override;
+ void create_split(Transaction *trans, AccountVec &account_commits) override;
gnc_numeric calculate_price(bool new_balance) override;
bool has_amount() override { return m_amount_enabled; }
};
@@ -720,8 +726,7 @@ StockTransactionStockEntry::set_amount(gnc_numeric amount, Logger& logger)
}
void
-StockTransactionStockEntry::create_split(Transaction *trans, const char* action,
- AccountVec &account_commits)
+StockTransactionStockEntry::create_split(Transaction *trans, AccountVec &account_commits)
{
g_return_if_fail(trans);
if (!m_account || gnc_numeric_check(m_value))
@@ -735,14 +740,14 @@ StockTransactionStockEntry::create_split(Transaction *trans, const char* action,
xaccSplitSetValue(split, m_debit_side ? m_value : gnc_numeric_neg(m_value));
xaccSplitSetAmount(split, m_debit_side ? amount() : gnc_numeric_neg(amount()));
PINFO("creating %s split in Acct(%s): Val(%s), Amt(%s) => Val(%s), Amt(%s)",
- action, m_account ? xaccAccountGetName (m_account) : "Empty!",
+ m_action, m_account ? xaccAccountGetName (m_account) : "Empty!",
gnc_num_dbg_to_string(m_value),
gnc_num_dbg_to_string(amount()),
gnc_num_dbg_to_string(xaccSplitGetValue(split)),
gnc_num_dbg_to_string(xaccSplitGetAmount(split)));
gnc_set_num_action(nullptr, split, nullptr,
g_dpgettext2(nullptr, "Stock Assistant: Action field",
- action));
+ m_action));
}
gnc_numeric
@@ -779,19 +784,17 @@ struct StockTransactionStockCapGainsEntry : public StockTransactionEntry
StockTransactionStockCapGainsEntry::StockTransactionStockCapGainsEntry(const StockTransactionEntry *cg_entry,
const StockTransactionEntry *stk_entry) :
StockTransactionEntry(!cg_entry->m_debit_side, cg_entry->m_allow_zero, cg_entry->m_allow_negative,
- stk_entry->m_account, cg_entry->m_value) {}
+ stk_entry->m_account, cg_entry->m_value, cg_entry->m_action) {}
struct StockTransactionFeesEntry : public StockTransactionEntry
{
bool m_capitalize;
- StockTransactionFeesEntry() :
- StockTransactionEntry{},
- m_capitalize{false} {}
+ StockTransactionFeesEntry() : StockTransactionEntry{}, m_capitalize{false} {}
+ StockTransactionFeesEntry(const char* action) : StockTransactionEntry{action}, m_capitalize{false} {}
void set_fieldmask(FieldMask mask) override;
void set_capitalize(bool capitalize) override { m_capitalize = capitalize; }
- void create_split(Transaction *trans, const char *action,
- AccountVec &commits) override;
+ void create_split(Transaction *trans, AccountVec &commits) override;
};
void
@@ -802,8 +805,7 @@ StockTransactionFeesEntry::set_fieldmask(FieldMask mask)
}
void
-StockTransactionFeesEntry::create_split(Transaction* trans, const char* action,
- AccountVec& commits)
+StockTransactionFeesEntry::create_split(Transaction* trans, AccountVec& commits)
{
g_return_if_fail(trans);
if (!m_account || !m_capitalize || gnc_numeric_check(m_value))
@@ -817,25 +819,24 @@ StockTransactionFeesEntry::create_split(Transaction* trans, const char* action,
xaccSplitSetValue(split, m_debit_side ? m_value : gnc_numeric_neg(m_value));
xaccSplitSetAmount(split, amount());
PINFO("creating %s split in Acct(%s): Val(%s), Amt(%s) => Val(%s), Amt(%s)",
- action, m_account ? xaccAccountGetName (m_account) : "Empty!",
+ m_action, m_account ? xaccAccountGetName (m_account) : "Empty!",
gnc_num_dbg_to_string(m_value),
gnc_num_dbg_to_string(amount()),
gnc_num_dbg_to_string(xaccSplitGetValue(split)),
gnc_num_dbg_to_string(xaccSplitGetAmount(split)));
gnc_set_num_action(nullptr, split, nullptr,
g_dpgettext2(nullptr, "Stock Assistant: Action field",
- action));
+ m_action));
}
struct StockTransactionSplitInfo
{
StockTransactionEntry* m_entry;
bool m_units_in_red = false;
- const char* m_action;
static const char* s_missing_str;
- StockTransactionSplitInfo(StockTransactionEntry* entry, const char* page) :
- m_entry{entry}, m_action{page}
+ StockTransactionSplitInfo(StockTransactionEntry* entry) :
+ m_entry{entry}
{
DEBUG ("StockTransactionSplitInfo constructor\n");
}
@@ -878,11 +879,11 @@ struct StockAssistantModel
m_acct{account},
m_currency{gnc_account_get_currency_or_parent(account)},
m_curr_pinfo (gnc_commodity_print_info (m_currency, true)),
- m_stock_entry{std::make_unique<StockTransactionStockEntry>()},
- m_cash_entry{std::make_unique<StockTransactionEntry>()},
- m_fees_entry{std::make_unique<StockTransactionFeesEntry>()},
- m_dividend_entry{std::make_unique<StockTransactionEntry>()},
- m_capgains_entry{std::make_unique<StockTransactionEntry>()}
+ m_stock_entry{std::make_unique<StockTransactionStockEntry>(NC_ ("Stock Assistant: Page name","Stock"))},
+ m_cash_entry{std::make_unique<StockTransactionEntry>(NC_ ("Stock Assistant: Page name","Cash"))},
+ m_fees_entry{std::make_unique<StockTransactionFeesEntry>(NC_ ("Stock Assistant: Page name","Fees"))},
+ m_dividend_entry{std::make_unique<StockTransactionEntry>(NC_ ("Stock Assistant: Page name","Dividend"))},
+ m_capgains_entry{std::make_unique<StockTransactionEntry>(NC_ ("Stock Assistant: Page name","Capital Gains"))}
{
DEBUG ("StockAssistantModel constructor\n");
m_stock_entry->m_account = m_acct;
@@ -1034,8 +1035,7 @@ StockAssistantModel::make_stock_split_info()
auto add_error_str = [this]
(const char* str) { m_logger.error (_(str)); };
- StockTransactionSplitInfo line{m_stock_entry.get(),
- NC_ ("Stock Assistant: Page name", "stock value")};
+ StockTransactionSplitInfo line{m_stock_entry.get()};
if (m_input_new_balance)
{
@@ -1110,26 +1110,22 @@ StockAssistantModel::generate_list_of_splits() {
}
if (m_cash_entry->m_enabled)
- m_list_of_splits.push_back (StockTransactionSplitInfo{m_cash_entry.get(),
- NC_ ("Stock Assistant: Page name", "cash")});
+ m_list_of_splits.push_back (StockTransactionSplitInfo{m_cash_entry.get()});
if (m_fees_entry->m_enabled)
- m_list_of_splits.push_back (StockTransactionSplitInfo{m_fees_entry.get(),
- NC_ ("Stock Assistant: Page name", "fees")});
+ m_list_of_splits.push_back (StockTransactionSplitInfo{m_fees_entry.get()});
if (m_dividend_entry->m_enabled)
- m_list_of_splits.push_back (StockTransactionSplitInfo{m_dividend_entry.get(),
- NC_ ("Stock Assistant: Page name", "dividend")});
+ m_list_of_splits.push_back (StockTransactionSplitInfo{m_dividend_entry.get()});
if (m_capgains_entry->m_enabled)
{
m_stock_cg_entry =
std::make_unique<StockTransactionStockCapGainsEntry>(m_capgains_entry.get(),
m_stock_entry.get());
- m_list_of_splits.push_back(StockTransactionSplitInfo{m_stock_cg_entry.get(),
- NC_ ("Stock Assistant: Page name", "capital gains")});
- m_list_of_splits.push_back (StockTransactionSplitInfo{m_capgains_entry.get(),
- NC_ ("Stock Assistant: Page name", "capital gains")});
+ m_list_of_splits.push_back(StockTransactionSplitInfo{m_stock_cg_entry.get()});
+
+ m_list_of_splits.push_back (StockTransactionSplitInfo{m_capgains_entry.get()});
}
if (gnc_numeric_check(debit) || gnc_numeric_check(credit) ||!gnc_numeric_equal (debit, credit))
@@ -1187,7 +1183,7 @@ StockAssistantModel::create_transaction ()
xaccTransSetDatePostedSecsNormalized (trans, m_transaction_date);
AccountVec accounts;
std::for_each (m_list_of_splits.begin(), m_list_of_splits.end(),
- [&](auto& line){ line.m_entry->create_split (trans, line.m_action, accounts); });
+ [&](auto& line){ line.m_entry->create_split (trans, accounts); });
add_price (book);
xaccTransCommitEdit (trans);
std::for_each (accounts.begin(), accounts.end(), xaccAccountCommitEdit);
@@ -1623,7 +1619,7 @@ page_stock_value_changed_cb(GtkWidget *widget, StockAssistantModel *model)
{
auto me = static_cast<PageStockValue*>(g_object_get_data (G_OBJECT (widget), "owner"));
auto value = me->m_value.get ();
- model->m_stock_entry->set_value (value, "stocks", model->m_logger);
+ model->m_stock_entry->set_value (value, model->m_logger);
me->set_price (model->calculate_price());
}
@@ -1649,7 +1645,7 @@ PageStockValue::prepare(StockTransactionEntry* entry, StockAssistantModel* model
{
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value(m_value.get(), "stock", logger);
+ entry->set_value(m_value.get(), logger);
set_price(model->calculate_price());
m_value.set_focus();
}
@@ -1711,7 +1707,7 @@ PageCash::prepare(StockTransactionEntry* entry, Logger& logger)
{
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value (m_value.get(), "cash", logger);
+ entry->set_value (m_value.get(), logger);
entry->m_account = m_account.get();
m_value.set_focus();
}
@@ -1816,7 +1812,7 @@ PageFees::prepare(StockTransactionFeesEntry* entry, Logger& logger)
set_capitalize_fees (entry);
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value (m_value.get(), "fees", logger);
+ entry->set_value (m_value.get(), logger);
entry->m_account = m_account.get();
m_value.set_focus();
}
@@ -1858,7 +1854,7 @@ PageDividend::prepare(StockTransactionEntry* entry, Logger& logger)
{
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value(m_value.get(), "dividend", logger);
+ entry->set_value(m_value.get(), logger);
entry->m_account = m_account.get();
m_value.set_focus();
}
@@ -1912,7 +1908,7 @@ PageCapGain::prepare(StockTransactionEntry* entry, Logger& logger)
{
entry->m_memo = get_memo();
if (gnc_numeric_check(m_value.get()))
- entry->set_value(m_value.get(), "capgains", logger);
+ entry->set_value(m_value.get(), logger);
entry->m_account = m_account.get();
m_value.set_focus();
}
commit eebf505548823ae856106c2683121b5327fdf332
Author: John Ralls <jralls at ceridwen.us>
Date: Thu Aug 24 11:32:59 2023 -0700
[stock-txn-asst] Reformat explanation messages to remove long lines.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index c40e3dd575..30cc749368 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -225,7 +225,9 @@ static const TxnTypeVec long_types
// Translators: this is a stock transaction describing new
// sale of stock, and recording capital gain/loss
N_("Sell"),
- N_("Selling stock long, and record capital gain/loss.\n\nIf you are unable to calculate capital gains you can enter a placeholder amount and correct it in the transaction later.")
+ N_("Selling stock long, and record capital gain/loss."
+ "\n\nIf you are unable to calculate capital gains you can enter a"
+ "placeholder amount and correct it in the transaction later.")
},
{
FieldMask::DISABLED, // stock_amt
@@ -236,8 +238,8 @@ static const TxnTypeVec long_types
// Translators: this is a stock transaction describing
// dividends issued to holder
N_("Dividend"),
- N_("Company issues cash dividends to holder.\n\nAny dividend being \
-reinvested must be subsequently recorded as a regular stock purchase.")
+ N_("Company issues cash dividends to holder.\n\nAny dividend being "
+ "reinvested must be subsequently recorded as a regular stock purchase.")
},
{
FieldMask::ENABLED_CREDIT, // stock_amt
@@ -259,7 +261,9 @@ reinvested must be subsequently recorded as a regular stock purchase.")
// Translators: this is a stock transaction describing return
// of capital, reclassifying a dividend into return of capital
N_("Return of capital (reclassification)"),
- N_("Company returns capital, reducing the cost basis without affecting # units. A distribution previously recorded as a dividend is reclassified to return of capital, often due to end-of-year tax information.")
+ N_("Company returns capital, reducing the cost basis without affecting # units. "
+ "A distribution previously recorded as a dividend is reclassified to return "
+ "of capital, often due to end-of-year tax information.")
},
{
FieldMask::ENABLED_DEBIT, // stock_amt
@@ -270,7 +274,8 @@ reinvested must be subsequently recorded as a regular stock purchase.")
// Translators: this is a stock transaction describing a
// notional distribution recorded as dividend
N_("Notional distribution (dividend)"),
- N_("Company issues a notional distribution, which is recorded as dividend income and increases the cost basis without affecting # units.")
+ N_("Company issues a notional distribution, which is recorded as dividend "
+ "income and increases the cost basis without affecting # units.")
},
{
FieldMask::ENABLED_DEBIT, // stock_amt
@@ -281,7 +286,8 @@ reinvested must be subsequently recorded as a regular stock purchase.")
// Translators: this is a stock transaction describing a
// notional distribution recorded as capital gain
N_("Notional distribution (capital gain)"),
- N_("Company issues a notional distribution, which is recorded as capital gain and increases the cost basis without affecting # units.")
+ N_("Company issues a notional distribution, which is recorded as capital gain "
+ "and increases the cost basis without affecting # units.")
},
{
FieldMask::DISABLED | FieldMask::AMOUNT_DEBIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
@@ -292,7 +298,10 @@ reinvested must be subsequently recorded as a regular stock purchase.")
// Translators: this is a stock transaction describing a stock
// split
N_("Stock split"),
- N_("Company issues additional units, thereby reducing the stock price by a divisor, while keeping the total monetary value of the overall investment constant..\n\nIf the reverse split results in a cash in lieu for remainder units, please record the sale using the Stock Transaction Assistant first, then record the split.")
+ N_("Company issues additional units, thereby reducing the stock price by a divisor "
+ ", while keeping the total monetary value of the overall investment constant. "
+ "\n\nIf the split results in a cash in lieu for remainder units, please "
+ "record the sale using the Stock Transaction Assistant first, then record the split.")
},
{
FieldMask::DISABLED | FieldMask::AMOUNT_CREDIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
@@ -302,7 +311,10 @@ reinvested must be subsequently recorded as a regular stock purchase.")
FieldMask::DISABLED, // capg_amt
// Translators: this is a stock transaction describing a reverse split
N_("Reverse split"),
- N_("Company redeems units, thereby increasing the stock price by a multiple, while keeping the total monetary value of the overall investment constant.\n\nIf the reverse split results in a cash in lieu for remainder units, please record the sale using the Stock Transaction Assistant first, then record the reverse split.")
+ N_("Company redeems units, thereby increasing the stock price by a multiple, while "
+ "keeping the total monetary value of the overall investment constant.\n\nIf the "
+ "reverse split results in a cash in lieu for remainder units, please record the "
+ "sale using the Stock Transaction Assistant first, then record the reverse split.")
}
};
@@ -328,7 +340,9 @@ static const TxnTypeVec short_types
// Translators: this is a stock transaction describing cover
// buying stock, and recording capital gain/loss
N_("Buy to cover short"),
- N_("Buy back stock to cover short position, and record capital gain/loss.\n\nIf you are unable to calculate capital gains you can enter a placeholder amount and correct it in the transaction later.")
+ N_("Buy back stock to cover short position, and record capital gain/loss. "
+ "\n\nIf you are unable to calculate capital gains you can enter a placeholder "
+ "amount and correct it in the transaction later.")
},
{
FieldMask::DISABLED, // stock_amt
@@ -339,7 +353,8 @@ static const TxnTypeVec short_types
// Translators: this is a stock transaction describing
// dividends retrieved from holder when shorting stock
N_("Compensatory dividend"),
- N_("Company issues dividends, and the short stock holder must make a compensatory payment for the dividend.")
+ N_("Company issues dividends, and the short stock holder must make a compensatory "
+ "payment for the dividend.")
},
{
FieldMask::ENABLED_DEBIT, // stock_amt
@@ -350,7 +365,9 @@ static const TxnTypeVec short_types
// Translators: this is a stock transaction describing return
// of capital retrieved from holder when shorting stock
N_("Compensatory return of capital"),
- N_("Company returns capital, and the short stock holder must make a compensatory payment for the returned capital. This reduces the cost basis (less negative, towards 0.00 value) without affecting # units.")
+ N_("Company returns capital, and the short stock holder must make a compensatory "
+ "payment for the returned capital. This reduces the cost basis (less negative, "
+ "towards 0.00 value) without affecting # units.")
},
{
FieldMask::ENABLED_DEBIT, // stock_amt
@@ -362,7 +379,11 @@ static const TxnTypeVec short_types
// reclassifying a compensatory dividend into compensatory
// return of capital when shorting stock
N_("Compensatory return of capital (reclassification)"),
- N_("Company returns capital, and the short stock holder must make a compensatory payment for the returned capital. This reduces the cost basis (less negative, towards 0.00 value) without affecting # units. A distribution previously recorded as a compensatory dividend is reclassified to compensatory return of capital, often due to end-of-year tax information.")
+ N_("Company returns capital, and the short stock holder must make a compensatory "
+ "payment for the returned capital. This reduces the cost basis (less negative, "
+ "towards 0.00 value) without affecting # units. A distribution previously recorded "
+ "as a compensatory dividend is reclassified to compensatory return of capital,"
+ "often due to end-of-year tax information.")
},
{
FieldMask::ENABLED_CREDIT, // stock_amt
@@ -374,7 +395,10 @@ static const TxnTypeVec short_types
// notional distribution recorded as dividend when shorting
// stock
N_("Compensatory notional distribution (dividend)"),
- N_("Company issues a notional distribution, and the short stock holder must make a compensatory payment for the notional distribution. This is recorded as a loss/negative dividend income amount, and increases the cost basis (more negative, away from 0.00 value) without affecting # units.")
+ N_("Company issues a notional distribution, and the short stock holder must make a "
+ "compensatory payment for the notional distribution. This is recorded as a "
+ "loss/negative dividend income amount, and increases the cost basis (more "
+ "negative, away from 0.00 value) without affecting # units.")
},
{
FieldMask::ENABLED_CREDIT, // stock_amt
@@ -386,7 +410,10 @@ static const TxnTypeVec short_types
// notional distribution recorded as capital gain when
// shorting stock
N_("Compensatory notional distribution (capital gain)"),
- N_("Company issues a notional distribution, and the short stock holder must make a compensatory payment for the notional distribution. This is recorded as a capital loss amount, and increases the cost basis (more negative, away from 0.00 value) without affecting # units.")
+ N_("Company issues a notional distribution, and the short stock holder must make "
+ "a compensatory payment for the notional distribution. This is recorded as a "
+ "capital loss amount, and increases the cost basis (more negative, away from "
+ "0.00 value) without affecting # units.")
},
{
FieldMask::DISABLED | FieldMask::AMOUNT_CREDIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
@@ -397,7 +424,10 @@ static const TxnTypeVec short_types
// Translators: this is a stock transaction describing a stock
// split when shorting stock
N_("Stock split"),
- N_("Company issues additional units, thereby reducing the stock price by a divisor, while keeping the total monetary value of the overall investment constant.\n\nIf the reverse split results in a cash in lieu for remainder units, please record the cover buy using the Stock Transaction Assistant first, then record the split.")
+ N_("Company issues additional units, thereby reducing the stock price by a divisor, "
+ "while keeping the total monetary value of the overall investment constant. "
+ "\n\nIf the split results in a cash in lieu for remainder units, please "
+ "record the cover buy using the Stock Transaction Assistant first, then record the split.")
},
{
FieldMask::DISABLED | FieldMask::AMOUNT_DEBIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
@@ -408,7 +438,10 @@ static const TxnTypeVec short_types
// Translators: this is a stock transaction describing a
// reverse split when shorting stock.
N_("Reverse split"),
- N_("Company redeems units, thereby increasing the stock price by a multiple, while keeping the total monetary value of the overall investment constant.\n\nIf the reverse split results in a cash in lieu for remainder units, please record the cover buy using the Stock Transaction Assistant first, then record the reverse split.")
+ N_("Company redeems units, thereby increasing the stock price by a multiple, while "
+ "keeping the total monetary value of the overall investment constant.\n\nIf the "
+ "reverse split results in a cash in lieu for remainder units, please record the "
+ "cover buy using the Stock Transaction Assistant first, then record the reverse split.")
}
};
commit b5e5a0ed2f35bcef5c069e1b0289cd70a9b03e73
Author: John Ralls <jralls at ceridwen.us>
Date: Thu Aug 24 11:24:14 2023 -0700
[stock-txn-asst] Add notes about cash-in-lieu and capgains.
Cash in lieu must be reported as a separate transaction. There was
already a note about that in reverse splits, apply it to regular
splits.
Add suggestion to enter a placeholder number when one can't
immediately calculate the capital gain on a sale or cover buy.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index f045280b97..c40e3dd575 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -225,7 +225,7 @@ static const TxnTypeVec long_types
// Translators: this is a stock transaction describing new
// sale of stock, and recording capital gain/loss
N_("Sell"),
- N_("Selling stock long, and record capital gain/loss.")
+ N_("Selling stock long, and record capital gain/loss.\n\nIf you are unable to calculate capital gains you can enter a placeholder amount and correct it in the transaction later.")
},
{
FieldMask::DISABLED, // stock_amt
@@ -292,7 +292,7 @@ reinvested must be subsequently recorded as a regular stock purchase.")
// Translators: this is a stock transaction describing a stock
// split
N_("Stock split"),
- N_("Company issues additional units, thereby reducing the stock price by a divisor, while keeping the total monetary value of the overall investment constant.")
+ N_("Company issues additional units, thereby reducing the stock price by a divisor, while keeping the total monetary value of the overall investment constant..\n\nIf the reverse split results in a cash in lieu for remainder units, please record the sale using the Stock Transaction Assistant first, then record the split.")
},
{
FieldMask::DISABLED | FieldMask::AMOUNT_CREDIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
@@ -302,11 +302,7 @@ reinvested must be subsequently recorded as a regular stock purchase.")
FieldMask::DISABLED, // capg_amt
// Translators: this is a stock transaction describing a reverse split
N_("Reverse split"),
- N_("Company redeems units, thereby increasing the stock price by a \
-multiple, while keeping the total monetary value of the overall investment \
-constant.\n\nIf the reverse split results in a cash in lieu for remainder \
-units, please record the sale using the Stock Transaction Assistant first, then \
-record the reverse split.")
+ N_("Company redeems units, thereby increasing the stock price by a multiple, while keeping the total monetary value of the overall investment constant.\n\nIf the reverse split results in a cash in lieu for remainder units, please record the sale using the Stock Transaction Assistant first, then record the reverse split.")
}
};
@@ -332,7 +328,7 @@ static const TxnTypeVec short_types
// Translators: this is a stock transaction describing cover
// buying stock, and recording capital gain/loss
N_("Buy to cover short"),
- N_("Buy back stock to cover short position, and record capital gain/loss.")
+ N_("Buy back stock to cover short position, and record capital gain/loss.\n\nIf you are unable to calculate capital gains you can enter a placeholder amount and correct it in the transaction later.")
},
{
FieldMask::DISABLED, // stock_amt
@@ -401,7 +397,7 @@ static const TxnTypeVec short_types
// Translators: this is a stock transaction describing a stock
// split when shorting stock
N_("Stock split"),
- N_("Company issues additional units, thereby reducing the stock price by a divisor, while keeping the total monetary value of the overall investment constant.")
+ N_("Company issues additional units, thereby reducing the stock price by a divisor, while keeping the total monetary value of the overall investment constant.\n\nIf the reverse split results in a cash in lieu for remainder units, please record the cover buy using the Stock Transaction Assistant first, then record the split.")
},
{
FieldMask::DISABLED | FieldMask::AMOUNT_DEBIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
@@ -412,11 +408,7 @@ static const TxnTypeVec short_types
// Translators: this is a stock transaction describing a
// reverse split when shorting stock.
N_("Reverse split"),
- N_("Company redeems units, thereby increasing the stock price by \
-a multiple, while keeping the total monetary value of the overall investment \
-constant.\n\nIf the reverse split results in a cash in lieu for remainder \
-units, please record the cover buy using the Stock Transaction Assistant first, \
-then record the reverse split.")
+ N_("Company redeems units, thereby increasing the stock price by a multiple, while keeping the total monetary value of the overall investment constant.\n\nIf the reverse split results in a cash in lieu for remainder units, please record the cover buy using the Stock Transaction Assistant first, then record the reverse split.")
}
};
commit a2bd020b13b9575e7d60bd532def58398418d9d0
Author: John Ralls <jralls at ceridwen.us>
Date: Sun Aug 20 15:48:24 2023 -0700
[stock-txn-asst] Call gettext on the transaction type explanation.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index bd95a94bc5..f045280b97 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -1459,7 +1459,7 @@ PageTransType::change_txn_type (StockAssistantModel *model)
if (!model->set_txn_type (type_idx))
return;
- set_txn_type_explanation (model->m_txn_type->explanation);
+ set_txn_type_explanation (_(model->m_txn_type->explanation));
}
void
commit 814754891fde3fda6c21a71a04351f77d1106b76
Author: John Ralls <jralls at ceridwen.us>
Date: Mon Aug 14 18:06:04 2023 -0700
[stock-txn-asst] Don't generate stock splitinfo if no stock split.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index c0e5565bcc..bd95a94bc5 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -670,8 +670,7 @@ void
StockTransactionStockEntry::set_fieldmask(FieldMask mask)
{
StockTransactionEntry::set_fieldmask(mask);
- m_enabled = mask & (FieldMask::ENABLED_CREDIT | FieldMask::ENABLED_DEBIT |
- FieldMask::AMOUNT_CREDIT | FieldMask::AMOUNT_DEBIT);
+ m_enabled = mask & (FieldMask::ENABLED_CREDIT | FieldMask::ENABLED_DEBIT);
m_amount_enabled = mask & (FieldMask::AMOUNT_CREDIT | FieldMask::AMOUNT_DEBIT);
m_debit_side = mask & (FieldMask::ENABLED_DEBIT | FieldMask::AMOUNT_DEBIT);
}
@@ -1064,22 +1063,25 @@ StockAssistantModel::generate_list_of_splits() {
if (last_split_node)
check_txn_date(last_split_node, m_transaction_date, m_logger);
-
- m_list_of_splits.push_back (make_stock_split_info());
-
- auto [has_price, price, price_str] = calculate_price ();
- if (has_price)
+ auto stock_entry{dynamic_cast<StockTransactionStockEntry*>(m_stock_entry.get())};
+ if (stock_entry && (stock_entry->m_enabled || stock_entry->m_amount_enabled))
{
- // Translators: %s refer to: stock mnemonic, broker currency,
- // date of transaction.
- auto tmpl = N_("A price of 1 %s = %s on %s will be recorded.");
- auto date_str = qof_print_date (m_transaction_date);
- auto price_msg = g_strdup_printf
- (_(tmpl),
- gnc_commodity_get_mnemonic (xaccAccountGetCommodity (m_acct)),
- price_str, date_str);
- m_logger.info(price_msg);
- g_free (date_str);
+ m_list_of_splits.push_back (make_stock_split_info());
+
+ auto [has_price, price, price_str] = calculate_price ();
+ if (has_price)
+ {
+ // Translators: %s refer to: stock mnemonic, broker currency,
+ // date of transaction.
+ auto tmpl = N_("A price of 1 %s = %s on %s will be recorded.");
+ auto date_str = qof_print_date (m_transaction_date);
+ auto price_msg = g_strdup_printf
+ (_(tmpl),
+ gnc_commodity_get_mnemonic (xaccAccountGetCommodity (m_acct)),
+ price_str, date_str);
+ m_logger.info(price_msg);
+ g_free (date_str);
+ }
}
if (m_cash_entry->m_enabled)
commit fc4f4ae6d7784d6ac1e6f66e92993ec68b35fdea
Author: John Ralls <jralls at ceridwen.us>
Date: Mon Aug 14 16:48:14 2023 -0700
Bug 799054 - Stock Assist not functioning
* Get the sign right when calculating new shares
* Fix displaying values and units on the summary page
* Don't display "missing" for values when the user skips
entering a 0 value.
* Create the Stock-account's fees split (when capitalizing)
and cap-gains split.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 12e85a9001..c0e5565bcc 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -404,7 +404,7 @@ static const TxnTypeVec short_types
N_("Company issues additional units, thereby reducing the stock price by a divisor, while keeping the total monetary value of the overall investment constant.")
},
{
- FieldMask::DISABLED | FieldMask::ENABLED_DEBIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
+ FieldMask::DISABLED | FieldMask::AMOUNT_DEBIT | FieldMask::INPUT_NEW_BALANCE, // stock_amt
FieldMask::ENABLED_CREDIT | FieldMask::ALLOW_ZERO, // cash_amt
FieldMask::ENABLED_DEBIT | FieldMask::ALLOW_ZERO | FieldMask::CAPITALIZE_DEFAULT, // fees_amt
FieldMask::DISABLED, // dividend_amt
@@ -543,6 +543,7 @@ struct StockTransactionEntry
virtual const char* print_value(GNCPrintAmountInfo info);
virtual const char* print_amount(gnc_numeric amt);
virtual gnc_numeric calculate_price(bool) { return gnc_numeric_error(GNC_ERROR_ARG); }
+ virtual bool has_amount() { return false; }
};
using StockTransactionEntryPtr = std::unique_ptr<StockTransactionEntry>;
@@ -599,14 +600,14 @@ StockTransactionEntry::set_value(gnc_numeric amount, const char* page, Logger& l
return;
}
- m_value = m_debit_side ? amount : gnc_numeric_neg (amount);
+ m_value = amount;
}
const char *
StockTransactionEntry::print_value(GNCPrintAmountInfo pinfo)
{
- if (gnc_numeric_check(m_value) ||
- (gnc_numeric_zero_p(m_value) && !m_allow_zero))
+ if ((gnc_numeric_check(m_value) || gnc_numeric_zero_p(m_value))
+ && !m_allow_zero)
return _("missing");
return xaccPrintAmount(m_value, pinfo);
}
@@ -636,7 +637,7 @@ StockTransactionEntry::create_split(Transaction *trans, const char* action,
xaccSplitSetValue(split, m_debit_side ? m_value : gnc_numeric_neg(m_value));
xaccSplitSetAmount(split, amount());
PINFO("creating %s split in Acct(%s): Val(%s), Amt(%s) => Val(%s), Amt(%s)",
- action, xaccAccountGetName (m_account),
+ action, m_account ? xaccAccountGetName (m_account) : "Empty!",
gnc_num_dbg_to_string(m_value),
gnc_num_dbg_to_string(amount()),
gnc_num_dbg_to_string(xaccSplitGetValue(split)),
@@ -659,7 +660,10 @@ struct StockTransactionStockEntry : public StockTransactionEntry
void set_fieldmask(FieldMask mask) override;
gnc_numeric amount() override { return m_amount; }
void set_amount(gnc_numeric amount, Logger& logger) override;
+ void create_split(Transaction *trans, const char* action,
+ AccountVec &account_commits) override;
gnc_numeric calculate_price(bool new_balance) override;
+ bool has_amount() override { return m_amount_enabled; }
};
void
@@ -672,6 +676,7 @@ StockTransactionStockEntry::set_fieldmask(FieldMask mask)
m_debit_side = mask & (FieldMask::ENABLED_DEBIT | FieldMask::AMOUNT_DEBIT);
}
+
void
StockTransactionStockEntry::set_amount(gnc_numeric amount, Logger& logger)
{
@@ -686,10 +691,36 @@ StockTransactionStockEntry::set_amount(gnc_numeric amount, Logger& logger)
return;
}
- m_amount = amount;
+ m_amount = m_debit_side ? amount : gnc_numeric_neg(amount);
PINFO("%s set amount %s", m_memo, print_amount(amount));
}
+void
+StockTransactionStockEntry::create_split(Transaction *trans, const char* action,
+ AccountVec &account_commits)
+{
+ g_return_if_fail(trans);
+ if (!m_account || gnc_numeric_check(m_value))
+ return;
+ auto split = xaccMallocSplit(qof_instance_get_book(trans));
+ xaccSplitSetParent(split, trans);
+ xaccAccountBeginEdit(m_account);
+ account_commits.push_back(m_account);
+ xaccSplitSetAccount(split, m_account);
+ xaccSplitSetMemo(split, m_memo);
+ xaccSplitSetValue(split, m_debit_side ? m_value : gnc_numeric_neg(m_value));
+ xaccSplitSetAmount(split, m_debit_side ? amount() : gnc_numeric_neg(amount()));
+ PINFO("creating %s split in Acct(%s): Val(%s), Amt(%s) => Val(%s), Amt(%s)",
+ action, m_account ? xaccAccountGetName (m_account) : "Empty!",
+ gnc_num_dbg_to_string(m_value),
+ gnc_num_dbg_to_string(amount()),
+ gnc_num_dbg_to_string(xaccSplitGetValue(split)),
+ gnc_num_dbg_to_string(xaccSplitGetAmount(split)));
+ gnc_set_num_action(nullptr, split, nullptr,
+ g_dpgettext2(nullptr, "Stock Assistant: Action field",
+ action));
+}
+
gnc_numeric
StockTransactionStockEntry::calculate_price(bool new_balance)
{
@@ -699,8 +730,19 @@ StockTransactionStockEntry::calculate_price(bool new_balance)
gnc_numeric_zero_p(m_amount) || gnc_numeric_zero_p(m_value))
return gnc_numeric_error(GNC_ERROR_ARG);
- return gnc_numeric_div(m_debit_side ? m_value : gnc_numeric_neg(m_value), m_amount,
- GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
+ auto price = gnc_numeric_div(m_value, m_amount,
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
+
+ auto comm{xaccAccountGetCommodity(m_account)};
+ auto curr{gnc_account_get_currency_or_parent(m_account)};
+ auto ainfo{gnc_commodity_print_info (comm, true)};
+ auto pinfo{gnc_price_print_info (curr, true)};
+ auto vinfo{gnc_commodity_print_info (curr, true)};
+
+ PINFO("Calculated price %s from value %s and amount %s",
+ xaccPrintAmount(price, pinfo), xaccPrintAmount(m_value, vinfo),
+ xaccPrintAmount(m_amount, ainfo));
+ return price;
}
struct StockTransactionStockCapGainsEntry : public StockTransactionEntry
@@ -739,8 +781,26 @@ void
StockTransactionFeesEntry::create_split(Transaction* trans, const char* action,
AccountVec& commits)
{
- if (!m_capitalize)
- StockTransactionEntry::create_split(trans, action, commits);
+ g_return_if_fail(trans);
+ if (!m_account || !m_capitalize || gnc_numeric_check(m_value))
+ return;
+ auto split = xaccMallocSplit(qof_instance_get_book(trans));
+ xaccSplitSetParent(split, trans);
+ xaccAccountBeginEdit(m_account);
+ commits.push_back(m_account);
+ xaccSplitSetAccount(split, m_account);
+ xaccSplitSetMemo(split, m_memo);
+ xaccSplitSetValue(split, m_debit_side ? m_value : gnc_numeric_neg(m_value));
+ xaccSplitSetAmount(split, amount());
+ PINFO("creating %s split in Acct(%s): Val(%s), Amt(%s) => Val(%s), Amt(%s)",
+ action, m_account ? xaccAccountGetName (m_account) : "Empty!",
+ gnc_num_dbg_to_string(m_value),
+ gnc_num_dbg_to_string(amount()),
+ gnc_num_dbg_to_string(xaccSplitGetValue(split)),
+ gnc_num_dbg_to_string(xaccSplitGetAmount(split)));
+ gnc_set_num_action(nullptr, split, nullptr,
+ g_dpgettext2(nullptr, "Stock Assistant: Action field",
+ action));
}
struct StockTransactionSplitInfo
@@ -915,6 +975,7 @@ StockAssistantModel::calculate_price ()
if (gnc_numeric_check(price))
return {false, price, nullptr};
auto pinfo{gnc_price_print_info (m_currency, true)};
+ PINFO("Model Price %s", xaccPrintAmount(price, pinfo));
return {true, price, xaccPrintAmount (price, pinfo)};
}
@@ -951,21 +1012,16 @@ StockAssistantModel::make_stock_split_info()
StockTransactionSplitInfo line{m_stock_entry.get(),
NC_ ("Stock Assistant: Page name", "stock value")};
- auto stock_entry = dynamic_cast<StockTransactionStockEntry*>(m_stock_entry.get());
- bool negative_in_red = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL,
- GNC_PREF_NEGATIVE_IN_RED);
if (m_input_new_balance)
{
- auto& stock_amount = stock_entry->m_amount;
+ auto stock_amount = line.m_entry->amount();
auto credit_side = (m_txn_type->stock_amount & FieldMask::AMOUNT_CREDIT);
auto delta = gnc_numeric_sub_fixed(stock_amount, m_balance_at_date);
auto ratio = gnc_numeric_div(stock_amount, m_balance_at_date,
GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
stock_amount = gnc_numeric_sub_fixed(stock_amount, m_balance_at_date);
line.m_entry->set_amount(stock_amount, m_logger);
- line.m_units_in_red =
- negative_in_red && gnc_numeric_negative_p(stock_amount);
if (gnc_numeric_check(ratio) || !gnc_numeric_positive_p(ratio))
add_error_str(N_("Invalid stock new balance."));
else if (gnc_numeric_negative_p(delta) && !credit_side)
@@ -973,15 +1029,11 @@ StockAssistantModel::make_stock_split_info()
else if (gnc_numeric_positive_p(delta) && credit_side)
add_error_str(N_("New balance must be lower than old balance."));
}
- else if (stock_entry->m_amount_enabled)
+ else if (line.m_entry->has_amount())
{
- auto& stock_amount = stock_entry->m_amount;
+ auto stock_amount = line.m_entry->amount();
if (!gnc_numeric_positive_p(stock_amount))
add_error_str(N_("Stock amount must be positive."));
- if (m_txn_type->stock_amount & FieldMask::AMOUNT_CREDIT)
- stock_amount = gnc_numeric_neg(stock_amount);
- line.m_units_in_red =
- negative_in_red && gnc_numeric_negative_p(stock_amount);
auto new_bal = gnc_numeric_add_fixed(m_balance_at_date, stock_amount);
if (gnc_numeric_positive_p(m_balance_at_date) &&
gnc_numeric_negative_p(new_bal))
@@ -1053,16 +1105,6 @@ StockAssistantModel::generate_list_of_splits() {
NC_ ("Stock Assistant: Page name", "capital gains")});
}
- std::for_each(m_list_of_splits.begin(), m_list_of_splits.end(),
- [&debit, &credit](const auto& splitinfo) {
- if (splitinfo.m_entry->m_debit_side)
- debit = gnc_numeric_add(debit, splitinfo.m_entry->m_value,
- GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
- else
- credit = gnc_numeric_add(credit, splitinfo.m_entry->m_value,
- GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
- });
-
if (gnc_numeric_check(debit) || gnc_numeric_check(credit) ||!gnc_numeric_equal (debit, credit))
{
const char *err_act = NULL, *err_reason = NULL;
@@ -1661,6 +1703,7 @@ struct PageFees
GncAccountSelector m_account;
GtkWidget * m_memo;
GncAmountEdit m_value;
+ Account* m_stock_account;
PageFees (GtkBuilder *builder, Account* account);
void connect(StockTransactionFeesEntry*);
bool get_capitalize_fees ();
@@ -1678,7 +1721,8 @@ PageFees::PageFees(GtkBuilder *builder, Account* account)
get_widget(builder, "capitalize_fees_checkbutton")),
m_account(builder, {ACCT_TYPE_EXPENSE}, gnc_account_get_currency_or_parent(account)),
m_memo(get_widget(builder, "fees_memo_entry")),
- m_value(builder, gnc_account_get_currency_or_parent(account))
+ m_value(builder, gnc_account_get_currency_or_parent(account)),
+ m_stock_account(account)
{
m_account.attach (builder, "fees_table", "fees_account_label", 1);
m_value.attach(builder, "fees_table", "fees_label", 2);
@@ -1724,6 +1768,8 @@ capitalize_fees_toggled_cb (GtkWidget *widget, StockTransactionFeesEntry *entry)
g_return_if_fail (me);
bool cap = me->get_capitalize_fees();
entry->set_capitalize(cap);
+ if (cap)
+ entry->m_account = me->m_stock_account;
me->update_fees_acct_sensitive (!cap);
}
@@ -1804,8 +1850,8 @@ struct PageCapGain
GtkWidget * m_memo;
GncAmountEdit m_value;
PageCapGain (GtkBuilder *builder, Account* account);
- void connect(StockTransactionStockCapGainsEntry* entry);
- void prepare(StockTransactionStockCapGainsEntry* entry, Logger& logger);
+ void connect(StockTransactionEntry* entry);
+ void prepare(StockTransactionEntry* entry, Logger& logger);
const char* get_memo();
};
@@ -1827,7 +1873,7 @@ PageCapGain::get_memo()
void
-PageCapGain::connect(StockTransactionStockCapGainsEntry*entry)
+PageCapGain::connect(StockTransactionEntry*entry)
{
m_account.connect(&entry->m_account);
g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
@@ -1835,7 +1881,7 @@ PageCapGain::connect(StockTransactionStockCapGainsEntry*entry)
}
void
-PageCapGain::prepare(StockTransactionStockCapGainsEntry* entry, Logger& logger)
+PageCapGain::prepare(StockTransactionEntry* entry, Logger& logger)
{
entry->m_memo = get_memo();
if (gnc_numeric_check(m_value.get()))
@@ -1932,21 +1978,37 @@ PageFinish::prepare (GtkWidget *window, StockAssistantModel *model)
{
auto [success, summary, list_of_splits] = model->generate_list_of_splits ();
auto gtv = GTK_TREE_VIEW(m_view.m_treeview);
+ bool negative_in_red = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL,
+ GNC_PREF_NEGATIVE_IN_RED);
auto list = GTK_LIST_STORE(gtk_tree_view_get_model(gtv));
gtk_list_store_clear(list);
for (const auto &line : list_of_splits) {
GtkTreeIter iter;
- auto tooltip = g_markup_escape_text(line.m_entry->m_memo, -1);
+ auto tooltip = (line.m_entry->m_memo && *line.m_entry->m_memo ?
+ g_markup_escape_text(line.m_entry->m_memo, -1) : strdup(""));
+ /* print_value and print_amount rely on xaccPrintAmount that
+ * uses static memory so the result needs to be copied
+ * immediately or the second call overwrites the results of
+ * the first one.
+ */
+ auto char2str{[](const char* str) -> std::string {
+ return std::string{ str ? str : "" }; }};
+ auto amount{char2str(line.m_entry->print_value(model->m_curr_pinfo))};
+ auto units{char2str(line.m_entry->has_amount() ?
+ line.m_entry->print_amount(line.m_entry->m_debit_side ? line.m_entry->amount() :
+ gnc_numeric_neg(line.m_entry->amount())) : "")};
+ auto units_in_red{negative_in_red && !line.m_entry->m_debit_side};
gtk_list_store_append(list, &iter);
gtk_list_store_set(
- list, &iter, SPLIT_COL_ACCOUNT,
- xaccAccountGetName(line.m_entry->m_account), SPLIT_COL_MEMO,
+ list, &iter,
+ SPLIT_COL_ACCOUNT,
+ line.m_entry->m_account ? xaccAccountGetName(line.m_entry->m_account) : "", SPLIT_COL_MEMO,
line.m_entry->m_memo, SPLIT_COL_TOOLTIP, tooltip, SPLIT_COL_DEBIT,
- line.m_entry->m_debit_side ? line.m_entry->print_value(model->m_curr_pinfo) : nullptr,
+ line.m_entry->m_debit_side ? amount.c_str() : nullptr,
SPLIT_COL_CREDIT,
- line.m_entry->m_debit_side ? nullptr : line.m_entry->print_value(model->m_curr_pinfo),
- SPLIT_COL_UNITS, line.m_entry->print_amount(line.m_entry->amount()),
- SPLIT_COL_UNITS_COLOR, line.m_units_in_red ? "red" : nullptr, -1);
+ line.m_entry->m_debit_side ? nullptr : amount.c_str(),
+ SPLIT_COL_UNITS, units.c_str(),
+ SPLIT_COL_UNITS_COLOR, units_in_red ? "red" : nullptr, -1);
g_free(tooltip);
}
gtk_label_set_text(GTK_LABEL(m_summary), summary.c_str());
@@ -2033,9 +2095,7 @@ StockAssistantController::connect_signals (GtkBuilder *builder)
if (fees_entry)
m_view.m_fees_page.connect(fees_entry);
m_view.m_dividend_page.connect(m_model->m_dividend_entry.get());
- auto capgains_entry = dynamic_cast<StockTransactionStockCapGainsEntry *>(m_model->m_capgains_entry.get());
- if (capgains_entry)
- m_view.m_capgain_page.connect(capgains_entry);
+ m_view.m_capgain_page.connect(m_model->m_capgains_entry.get());
g_signal_connect (m_view.m_window, "destroy", G_CALLBACK (stock_assistant_window_destroy_cb), this);
@@ -2090,9 +2150,7 @@ StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
break;
case PAGE_CAPGAINS:
{
- auto capgain_entry = dynamic_cast<StockTransactionStockCapGainsEntry*>(m_model->m_capgains_entry.get());
- if (capgain_entry)
- m_view.m_capgain_page.prepare(capgain_entry, m_model->m_logger);
+ m_view.m_capgain_page.prepare(m_model->m_capgains_entry.get(), m_model->m_logger);
break;
}
case PAGE_FINISH:
diff --git a/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp b/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
index 22433f0fdd..636c04bb79 100644
--- a/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
+++ b/gnucash/gnome/test/gtest-assistant-stock-transaction.cpp
@@ -259,7 +259,8 @@ TEST_F(StockAssistantTest, testAggregateResults)
auto [success_txn, txn] = model.create_transaction ();
EXPECT_TRUE (success_txn);
- EXPECT_EQ (xaccAccountGetBalance (stock_account).num, t.new_bal * 100);
+ EXPECT_EQ (xaccAccountGetBalance (stock_account).num, t.new_bal * 100) <<
+ t.dd << '/' << t.mm << '/' << t.yy << ": " << t.desc;
}
dump_acct (stock_account);
@@ -269,6 +270,6 @@ TEST_F(StockAssistantTest, testAggregateResults)
dump_acct (cash_account);
EXPECT_EQ (xaccAccountGetBalance (dividend_account).num, 42000);
EXPECT_EQ (xaccAccountGetBalance (capgains_account).num, -995981);
- EXPECT_EQ (xaccAccountGetBalance (fees_account).num, 4478);
+ EXPECT_EQ (xaccAccountGetBalance (fees_account).num, 5473);
EXPECT_EQ (xaccAccountGetBalance (cash_account).num, 1663049);
}
commit c284f96286e106b47046c3de8438cb105a4d358e
Author: John Ralls <jralls at ceridwen.us>
Date: Fri Aug 11 15:09:51 2023 -0700
[asst-stock-txn] Fix typo.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 5c5d2a26f4..12e85a9001 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -703,15 +703,15 @@ StockTransactionStockEntry::calculate_price(bool new_balance)
GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
}
-struct StockTransactionsStockCapGainsEntry : public StockTransactionEntry
+struct StockTransactionStockCapGainsEntry : public StockTransactionEntry
{
- StockTransactionsStockCapGainsEntry(const StockTransactionEntry* cg_entry,
+ StockTransactionStockCapGainsEntry(const StockTransactionEntry* cg_entry,
const StockTransactionEntry* stk_entry);
gnc_numeric amount() { return gnc_numeric_zero(); }
};
-StockTransactionsStockCapGainsEntry::StockTransactionsStockCapGainsEntry(const StockTransactionEntry* cg_entry,
- const StockTransactionEntry* stk_entry) :
+StockTransactionStockCapGainsEntry::StockTransactionStockCapGainsEntry(const StockTransactionEntry *cg_entry,
+ const StockTransactionEntry *stk_entry) :
StockTransactionEntry(!cg_entry->m_debit_side, cg_entry->m_allow_zero, cg_entry->m_allow_negative,
stk_entry->m_account, cg_entry->m_value) {}
@@ -1045,7 +1045,7 @@ StockAssistantModel::generate_list_of_splits() {
if (m_capgains_entry->m_enabled)
{
m_stock_cg_entry =
- std::make_unique<StockTransactionsStockCapGainsEntry>(m_capgains_entry.get(),
+ std::make_unique<StockTransactionStockCapGainsEntry>(m_capgains_entry.get(),
m_stock_entry.get());
m_list_of_splits.push_back(StockTransactionSplitInfo{m_stock_cg_entry.get(),
NC_ ("Stock Assistant: Page name", "capital gains")});
@@ -1804,8 +1804,8 @@ struct PageCapGain
GtkWidget * m_memo;
GncAmountEdit m_value;
PageCapGain (GtkBuilder *builder, Account* account);
- void connect(StockTransactionsStockCapGainsEntry* entry);
- void prepare(StockTransactionsStockCapGainsEntry* entry, Logger& logger);
+ void connect(StockTransactionStockCapGainsEntry* entry);
+ void prepare(StockTransactionStockCapGainsEntry* entry, Logger& logger);
const char* get_memo();
};
@@ -1827,7 +1827,7 @@ PageCapGain::get_memo()
void
-PageCapGain::connect(StockTransactionsStockCapGainsEntry*entry)
+PageCapGain::connect(StockTransactionStockCapGainsEntry*entry)
{
m_account.connect(&entry->m_account);
g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
@@ -1835,7 +1835,7 @@ PageCapGain::connect(StockTransactionsStockCapGainsEntry*entry)
}
void
-PageCapGain::prepare(StockTransactionsStockCapGainsEntry* entry, Logger& logger)
+PageCapGain::prepare(StockTransactionStockCapGainsEntry* entry, Logger& logger)
{
entry->m_memo = get_memo();
if (gnc_numeric_check(m_value.get()))
@@ -2033,7 +2033,7 @@ StockAssistantController::connect_signals (GtkBuilder *builder)
if (fees_entry)
m_view.m_fees_page.connect(fees_entry);
m_view.m_dividend_page.connect(m_model->m_dividend_entry.get());
- auto capgains_entry = dynamic_cast<StockTransactionsStockCapGainsEntry *>(m_model->m_capgains_entry.get());
+ auto capgains_entry = dynamic_cast<StockTransactionStockCapGainsEntry *>(m_model->m_capgains_entry.get());
if (capgains_entry)
m_view.m_capgain_page.connect(capgains_entry);
@@ -2090,7 +2090,7 @@ StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
break;
case PAGE_CAPGAINS:
{
- auto capgain_entry = dynamic_cast<StockTransactionsStockCapGainsEntry*>(m_model->m_capgains_entry.get());
+ auto capgain_entry = dynamic_cast<StockTransactionStockCapGainsEntry*>(m_model->m_capgains_entry.get());
if (capgain_entry)
m_view.m_capgain_page.prepare(capgain_entry, m_model->m_logger);
break;
commit 917b4b247c136b6a8d89911ee592383cc304c846
Author: John Ralls <jralls at ceridwen.us>
Date: Thu Aug 10 16:58:49 2023 -0700
[stock-txn-asst] Fix sell-side stock amounts.
It was setting a negative amount in one too many places.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index a7da9ead4e..5c5d2a26f4 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -686,12 +686,7 @@ StockTransactionStockEntry::set_amount(gnc_numeric amount, Logger& logger)
return;
}
- bool neg{gnc_numeric_negative_p(amount) == TRUE};
-
- if ((m_debit_side && !neg) || (!m_debit_side && neg))
- m_amount = amount;
- else
- m_amount = gnc_numeric_neg(amount);
+ m_amount = amount;
PINFO("%s set amount %s", m_memo, print_amount(amount));
}
@@ -704,7 +699,7 @@ StockTransactionStockEntry::calculate_price(bool new_balance)
gnc_numeric_zero_p(m_amount) || gnc_numeric_zero_p(m_value))
return gnc_numeric_error(GNC_ERROR_ARG);
- return gnc_numeric_div(m_value, m_amount,
+ return gnc_numeric_div(m_debit_side ? m_value : gnc_numeric_neg(m_value), m_amount,
GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
}
commit 502dcc03ce683563f45e0f0d748aa69b0cada541
Author: John Ralls <jralls at ceridwen.us>
Date: Sun Aug 6 14:36:20 2023 -0700
[stock-txn-asst] Extract Logger class
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index c5b2a0b56a..a7da9ead4e 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -420,6 +420,96 @@ then record the reverse split.")
}
};
+enum class LogMsgType
+{
+ info,
+ warning,
+ error
+};
+
+class LogMessage
+{
+ LogMsgType m_type;
+ const std::string m_message;
+public:
+ LogMessage(LogMsgType type, std::string&& message) :
+ m_type{type}, m_message(std::move(message)) {}
+ LogMessage(LogMsgType type, const char* message) :
+ m_type{type}, m_message(message) {}
+ LogMessage(const LogMessage&) = default;
+ LogMessage(LogMessage&&) = default;
+ ~LogMessage() = default;
+ LogMsgType type() { return m_type; }
+ const std::string& message() { return m_message; }
+};
+
+using Log = std::vector<LogMessage>;
+
+class Logger
+{
+ Log m_log;
+public: // compiler generated ctors & dtor are fine
+ void info(const char* message) { m_log.emplace_back(LogMsgType::info, message); }
+ void warn(const char* message) { m_log.emplace_back(LogMsgType::warning, message); }
+ void error(const char* message) { m_log.emplace_back(LogMsgType::error, message); }
+ void clear() { m_log.clear(); }
+ bool has_errors();
+ bool has_warnings();
+ void write_log(std::stringstream& stream, LogMsgType type);
+ void infos(std::stringstream& stream) { return write_log(stream, LogMsgType::info); }
+ void warnings(std::stringstream& stream) { return write_log(stream, LogMsgType::warning); }
+ void errors(std::stringstream& stream) { return write_log(stream, LogMsgType::error); }
+ std::string report();
+};
+
+void
+Logger::write_log(std::stringstream& stream, LogMsgType type)
+{
+ std::for_each(m_log.begin(), m_log.end(),
+ [&](auto& msg){
+ if (msg.type() == type)
+ stream << "\n * " << msg.message();
+ });
+}
+
+bool
+Logger::has_warnings()
+{
+ return std::any_of(m_log.begin(), m_log.end(),
+ [](auto& msg){ return msg.type() == LogMsgType::warning;
+ });
+}
+
+bool
+Logger::has_errors()
+{
+ return std::any_of(m_log.begin(), m_log.end(),
+ [](auto& msg){ return msg.type() == LogMsgType::error;
+ });
+}
+
+std::string
+Logger::report()
+{
+ std::stringstream summary;
+ if (!has_errors())
+ {
+ summary << _("No errors found. Click Apply to create transaction.");
+ infos(summary);
+ }
+ else
+ {
+ summary << _("The following errors must be fixed:");
+ errors(summary);
+ }
+ if (has_warnings())
+ {
+ summary << "\n\n" << _("The following warnings exist:");
+ warnings(summary);
+ }
+ return summary.str();
+}
+
/** Possibly misnamed. Collects the required information to create a single
* split in a transaction. This is the base class; there are child classes for
* many split types.
@@ -445,9 +535,9 @@ struct StockTransactionEntry
virtual void set_fieldmask(FieldMask mask);
virtual void set_capitalize(bool capitalize) {}
- virtual void set_value(gnc_numeric amount, const char* page, StringVec& errors);
+ virtual void set_value(gnc_numeric amount, const char* page, Logger& logger);
virtual gnc_numeric amount() { return m_value; }
- virtual void set_amount(gnc_numeric, StringVec&) {}
+ virtual void set_amount(gnc_numeric, Logger&) {}
virtual void create_split(Transaction* trans, const char* action,
AccountVec& commits);
virtual const char* print_value(GNCPrintAmountInfo info);
@@ -468,17 +558,17 @@ StockTransactionEntry::set_fieldmask(FieldMask mask)
void
-StockTransactionEntry::set_value(gnc_numeric amount, const char* page, StringVec& errors)
+StockTransactionEntry::set_value(gnc_numeric amount, const char* page, Logger& logger)
{
DEBUG ("checking value %s page %s",
gnc_num_dbg_to_string (amount),
page);
- auto add_error = [&errors](const char* format_str, const char* arg)
+ auto add_error = [&logger](const char* format_str, const char* arg)
{
char *buf = g_strdup_printf (_(format_str),
g_dpgettext2 (nullptr, "Stock Assistant: Page name", arg));
- errors.emplace_back (buf);
+ logger.error(buf);
g_free (buf);
};
@@ -568,7 +658,7 @@ struct StockTransactionStockEntry : public StockTransactionEntry
}
void set_fieldmask(FieldMask mask) override;
gnc_numeric amount() override { return m_amount; }
- void set_amount(gnc_numeric amount, StringVec& errors) override;
+ void set_amount(gnc_numeric amount, Logger& logger) override;
gnc_numeric calculate_price(bool new_balance) override;
};
@@ -583,7 +673,7 @@ StockTransactionStockEntry::set_fieldmask(FieldMask mask)
}
void
-StockTransactionStockEntry::set_amount(gnc_numeric amount, StringVec& errors)
+StockTransactionStockEntry::set_amount(gnc_numeric amount, Logger& logger)
{
if (!m_amount_enabled)
return;
@@ -592,7 +682,7 @@ StockTransactionStockEntry::set_amount(gnc_numeric amount, StringVec& errors)
{
const char* err{_("Amount for stock value is missing.")};
- errors.emplace_back(err);
+ logger.error(err);
return;
}
@@ -703,7 +793,7 @@ struct StockAssistantModel
StockTransactionEntryPtr m_dividend_entry;
StockTransactionEntryPtr m_capgains_entry;
StockTransactionEntryPtr m_stock_cg_entry; // Required at this level for lifetime management
- StringVec m_errors, m_warnings, m_infos;
+ Logger m_logger;
StockAssistantModel (Account *account) :
m_acct{account},
@@ -746,7 +836,6 @@ private:
void add_price (QofBook *book);
StockTransactionSplitInfo make_stock_split_info();
- std::string summary_message();
};
bool
@@ -835,7 +924,7 @@ StockAssistantModel::calculate_price ()
}
static void
-check_txn_date(GList* last_split_node, time64 txn_date, StringVec& warnings)
+check_txn_date(GList* last_split_node, time64 txn_date, Logger& logger)
{
auto last_split = static_cast<const Split *>(last_split_node->data);
auto last_split_date = xaccTransGetDate(xaccSplitGetParent(last_split));
@@ -852,7 +941,7 @@ check_txn_date(GList* last_split_node, time64 txn_date, StringVec& warnings)
"of transactions dated after the new entry. Please review all transactions "
"to ensure proper recording."),
new_date_str, last_split_date_str);
- warnings.push_back(warn_txt);
+ logger.warn(warn_txt);
g_free(warn_txt);
g_free(new_date_str);
g_free(last_split_date_str);
@@ -863,7 +952,7 @@ StockTransactionSplitInfo
StockAssistantModel::make_stock_split_info()
{
auto add_error_str = [this]
- (const char* str) { m_errors.emplace_back (_(str)); };
+ (const char* str) { m_logger.error (_(str)); };
StockTransactionSplitInfo line{m_stock_entry.get(),
NC_ ("Stock Assistant: Page name", "stock value")};
@@ -879,7 +968,7 @@ StockAssistantModel::make_stock_split_info()
auto ratio = gnc_numeric_div(stock_amount, m_balance_at_date,
GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
stock_amount = gnc_numeric_sub_fixed(stock_amount, m_balance_at_date);
- line.m_entry->set_amount(stock_amount, m_errors);
+ line.m_entry->set_amount(stock_amount, m_logger);
line.m_units_in_red =
negative_in_red && gnc_numeric_negative_p(stock_amount);
if (gnc_numeric_check(ratio) || !gnc_numeric_positive_p(ratio))
@@ -909,38 +998,12 @@ StockAssistantModel::make_stock_split_info()
return line;
}
-std::string
-StockAssistantModel::summary_message()
-{
- std::ostringstream summary;
- auto summary_add = [&summary](auto a) { summary << "\n⢠" << a; };
- if (m_errors.empty())
- {
- summary << _("No errors found. Click Apply to create transaction.");
- std::for_each (m_infos.begin(), m_infos.end(), summary_add);
- }
- else
- {
- summary << _("The following errors must be fixed:");
- std::for_each (m_errors.begin(), m_errors.end(), summary_add);
- }
- if (!m_warnings.empty())
- {
- summary << "\n\n" << _("The following warnings exist:");
- std::for_each (m_warnings.begin(), m_warnings.end(), summary_add);
- }
-
- return summary.str();
-}
-
std::tuple<bool, std::string, SplitInfoVec>
StockAssistantModel::generate_list_of_splits() {
if (!m_txn_types || !m_txn_type)
return { false, "Error: txn_type not initialized", {} };
- m_warnings.clear();
- m_errors.clear();
- m_infos.clear();
+ m_logger.clear();
m_list_of_splits.clear();
gnc_numeric debit = gnc_numeric_zero ();
@@ -952,7 +1015,7 @@ StockAssistantModel::generate_list_of_splits() {
// to review them.
auto last_split_node = g_list_last (xaccAccountGetSplitList (m_acct));
if (last_split_node)
- check_txn_date(last_split_node, m_transaction_date, m_warnings);
+ check_txn_date(last_split_node, m_transaction_date, m_logger);
m_list_of_splits.push_back (make_stock_split_info());
@@ -968,7 +1031,7 @@ StockAssistantModel::generate_list_of_splits() {
(_(tmpl),
gnc_commodity_get_mnemonic (xaccAccountGetCommodity (m_acct)),
price_str, date_str);
- m_infos.emplace_back (price_msg);
+ m_logger.info(price_msg);
g_free (date_str);
}
@@ -1022,7 +1085,7 @@ StockAssistantModel::generate_list_of_splits() {
if (err_act)
{
auto err_str = g_strdup_printf (N_("Transaction can't balance, %s is error value %s"), err_act, err_reason);
- m_errors.emplace_back(err_str);
+ m_logger.error(err_str);
g_free (err_str);
}
else
@@ -1031,7 +1094,7 @@ StockAssistantModel::generate_list_of_splits() {
auto debit_str = g_strdup (xaccPrintAmount (debit, m_curr_pinfo));
auto credit_str = g_strdup (xaccPrintAmount (credit, m_curr_pinfo));
auto error_str = g_strdup_printf (_(imbalance_str), debit_str, credit_str);
- m_errors.emplace_back (error_str);
+ m_logger.error (error_str);
g_free (error_str);
g_free (credit_str);
g_free (debit_str);
@@ -1040,8 +1103,8 @@ StockAssistantModel::generate_list_of_splits() {
// generate final summary message. Collates a header, the errors
// and warnings. Then allow completion if errors is empty.
- m_ready_to_create = m_errors.empty();
- return { m_ready_to_create, summary_message(), m_list_of_splits };
+ m_ready_to_create = !m_logger.has_errors();
+ return { m_ready_to_create, m_logger.report(), m_list_of_splits };
}
std::tuple<bool, Transaction*>
@@ -1415,7 +1478,7 @@ struct PageStockAmount
GncAmountEdit m_amount;
GtkWidget * m_amount_label;
PageStockAmount (GtkBuilder *builder, Account* account);
- void prepare (StockTransactionStockEntry*, StockAssistantModel*, StringVec&);
+ void prepare (StockTransactionStockEntry*, StockAssistantModel*, Logger&);
gnc_numeric get_stock_amount () { return m_amount.get(); }
void set_stock_amount (std::string new_amount_str);
void connect(StockAssistantModel *model);
@@ -1435,7 +1498,7 @@ PageStockAmount::PageStockAmount (GtkBuilder *builder, Account* account) :
void
PageStockAmount::prepare (StockTransactionStockEntry* entry, StockAssistantModel* model,
- StringVec& errors)
+ Logger& logger)
{
gtk_label_set_text_with_mnemonic
(GTK_LABEL (m_amount_label),
@@ -1449,7 +1512,7 @@ PageStockAmount::prepare (StockTransactionStockEntry* entry, StockAssistantModel
_("Enter the number of shares you gained or lost in the transaction."));
gtk_label_set_text (GTK_LABEL (m_prev_amount), model->get_stock_balance_str().c_str());
if (!gnc_numeric_check(get_stock_amount()))
- entry->set_amount(get_stock_amount(), errors);
+ entry->set_amount(get_stock_amount(), logger);
set_stock_amount(model->get_new_amount_str());
m_amount.set_focus();
@@ -1459,7 +1522,7 @@ static void
page_stock_amount_changed_cb(GtkWidget *widget, StockAssistantModel *model)
{
auto me = static_cast<PageStockAmount*>(g_object_get_data (G_OBJECT (widget), "owner"));
- model->m_stock_entry->set_amount(me->m_amount.get(), model->m_errors);
+ model->m_stock_entry->set_amount(me->m_amount.get(), model->m_logger);
me->set_stock_amount (model->get_new_amount_str());
}
@@ -1486,7 +1549,7 @@ struct PageStockValue
PageStockValue (GtkBuilder *builder, Account* account);
const char* get_memo ();
void connect(StockAssistantModel *model);
- void prepare(StockTransactionEntry*, StockAssistantModel*, StringVec&);
+ void prepare(StockTransactionEntry*, StockAssistantModel*, Logger&);
void set_price(const gchar *val);
void set_price (std::tuple<bool, gnc_numeric, const char*> price_tuple);
};
@@ -1496,7 +1559,7 @@ page_stock_value_changed_cb(GtkWidget *widget, StockAssistantModel *model)
{
auto me = static_cast<PageStockValue*>(g_object_get_data (G_OBJECT (widget), "owner"));
auto value = me->m_value.get ();
- model->m_stock_entry->set_value (value, "stocks", model->m_errors);
+ model->m_stock_entry->set_value (value, "stocks", model->m_logger);
me->set_price (model->calculate_price());
}
@@ -1518,11 +1581,11 @@ PageStockValue::connect(StockAssistantModel *model)
}
void
-PageStockValue::prepare(StockTransactionEntry* entry, StockAssistantModel* model, StringVec& errors)
+PageStockValue::prepare(StockTransactionEntry* entry, StockAssistantModel* model, Logger& logger)
{
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value(m_value.get(), "stock", errors);
+ entry->set_value(m_value.get(), "stock", logger);
set_price(model->calculate_price());
m_value.set_focus();
}
@@ -1556,7 +1619,7 @@ struct PageCash
GncAmountEdit m_value;
PageCash (GtkBuilder *builder, Account* account);
void connect(StockTransactionEntry* entry);
- void prepare(StockTransactionEntry* entry, StringVec& errors);
+ void prepare(StockTransactionEntry* entry, Logger& logger);
const char* get_memo();
};
@@ -1580,11 +1643,11 @@ PageCash::connect(StockTransactionEntry* entry)
}
void
-PageCash::prepare(StockTransactionEntry* entry, StringVec& errors)
+PageCash::prepare(StockTransactionEntry* entry, Logger& logger)
{
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value (m_value.get(), "cash", errors);
+ entry->set_value (m_value.get(), "cash", logger);
entry->m_account = m_account.get();
m_value.set_focus();
}
@@ -1611,7 +1674,7 @@ struct PageFees
void set_capitalize_fees (StockTransactionFeesEntry*);
void set_account (Account *acct) { m_account.set(acct); }
void update_fees_acct_sensitive (bool sensitive);
- void prepare(StockTransactionFeesEntry*, StringVec&);
+ void prepare(StockTransactionFeesEntry*, Logger&);
};
PageFees::PageFees(GtkBuilder *builder, Account* account)
@@ -1680,12 +1743,12 @@ PageFees::connect(StockTransactionFeesEntry* entry)
}
void
-PageFees::prepare(StockTransactionFeesEntry* entry, StringVec& errors)
+PageFees::prepare(StockTransactionFeesEntry* entry, Logger& logger)
{
set_capitalize_fees (entry);
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value (m_value.get(), "fees", errors);
+ entry->set_value (m_value.get(), "fees", logger);
entry->m_account = m_account.get();
m_value.set_focus();
}
@@ -1699,7 +1762,7 @@ struct PageDividend
GncAmountEdit m_value;
PageDividend (GtkBuilder *builder, Account* account);
void connect(StockTransactionEntry*);
- void prepare(StockTransactionEntry*, StringVec&);
+ void prepare(StockTransactionEntry*, Logger&);
const char* get_memo();
};
@@ -1723,11 +1786,11 @@ PageDividend::connect(StockTransactionEntry* entry)
}
void
-PageDividend::prepare(StockTransactionEntry* entry, StringVec& errors)
+PageDividend::prepare(StockTransactionEntry* entry, Logger& logger)
{
entry->m_memo = get_memo();
if (!gnc_numeric_check(m_value.get()))
- entry->set_value(m_value.get(), "dividend", errors);
+ entry->set_value(m_value.get(), "dividend", logger);
entry->m_account = m_account.get();
m_value.set_focus();
}
@@ -1747,7 +1810,7 @@ struct PageCapGain
GncAmountEdit m_value;
PageCapGain (GtkBuilder *builder, Account* account);
void connect(StockTransactionsStockCapGainsEntry* entry);
- void prepare(StockTransactionsStockCapGainsEntry* entry, StringVec& errors);
+ void prepare(StockTransactionsStockCapGainsEntry* entry, Logger& logger);
const char* get_memo();
};
@@ -1777,11 +1840,11 @@ PageCapGain::connect(StockTransactionsStockCapGainsEntry*entry)
}
void
-PageCapGain::prepare(StockTransactionsStockCapGainsEntry* entry, StringVec& errors)
+PageCapGain::prepare(StockTransactionsStockCapGainsEntry* entry, Logger& logger)
{
entry->m_memo = get_memo();
if (gnc_numeric_check(m_value.get()))
- entry->set_value(m_value.get(), "capgains", errors);
+ entry->set_value(m_value.get(), "capgains", logger);
entry->m_account = m_account.get();
m_value.set_focus();
}
@@ -2011,30 +2074,30 @@ StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
{
auto stock_entry = dynamic_cast<StockTransactionStockEntry*>(m_model->m_stock_entry.get());
if (stock_entry)
- m_view.m_stock_amount_page.prepare(stock_entry, m_model.get(), m_model->m_errors);
+ m_view.m_stock_amount_page.prepare(stock_entry, m_model.get(), m_model->m_logger);
break;
}
case PAGE_STOCK_VALUE:
- m_view.m_stock_value_page.prepare(m_model->m_stock_entry.get(), m_model.get(), m_model->m_errors);
+ m_view.m_stock_value_page.prepare(m_model->m_stock_entry.get(), m_model.get(), m_model->m_logger);
break;
case PAGE_CASH:
- m_view.m_cash_page.prepare(m_model->m_cash_entry.get(), m_model->m_errors);
+ m_view.m_cash_page.prepare(m_model->m_cash_entry.get(), m_model->m_logger);
break;
case PAGE_FEES:
{
auto fees_entry = dynamic_cast<StockTransactionFeesEntry*>(m_model->m_fees_entry.get());
if (fees_entry)
- m_view.m_fees_page.prepare(fees_entry, m_model->m_errors);
+ m_view.m_fees_page.prepare(fees_entry, m_model->m_logger);
break;
}
case PAGE_DIVIDEND:
- m_view.m_dividend_page.prepare(m_model->m_dividend_entry.get(), m_model->m_errors);
+ m_view.m_dividend_page.prepare(m_model->m_dividend_entry.get(), m_model->m_logger);
break;
case PAGE_CAPGAINS:
{
auto capgain_entry = dynamic_cast<StockTransactionsStockCapGainsEntry*>(m_model->m_capgains_entry.get());
if (capgain_entry)
- m_view.m_capgain_page.prepare(capgain_entry, m_model->m_errors);
+ m_view.m_capgain_page.prepare(capgain_entry, m_model->m_logger);
break;
}
case PAGE_FINISH:
commit e46195cba7410e1383524f5d33f3b89158c7f042
Author: John Ralls <jralls at ceridwen.us>
Date: Sat Aug 5 17:12:09 2023 -0700
[stock-txn-asst] Move prepare details into Assistant Page member funcs.
Substantially simplifies the code by reducing the needed indirection.
In most cases the StockTransactionEntry has everything the page needs
and can be passed as a parameter, further simplifying the code.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index da5545cfa0..c5b2a0b56a 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -1321,6 +1321,7 @@ PageTransType::prepare(StockAssistantModel *model)
set_transaction_types(model->m_txn_types.value());
change_txn_type (model);
+ set_focus();
}
int
@@ -1377,6 +1378,7 @@ struct PageTransDeets
const char* get_description () { return gtk_entry_get_text (GTK_ENTRY (m_description)); }
void set_focus () { gtk_widget_grab_focus (m_description); }
void connect (time64 *date, const char **description);
+ void prepare(time64 *date, const char** description);
};
PageTransDeets::PageTransDeets (GtkBuilder *builder) :
@@ -1394,6 +1396,14 @@ PageTransDeets::connect(time64 *date, const char **description)
g_signal_connect(m_description, "changed", G_CALLBACK (text_entry_changed_cb), description);
}
+void
+PageTransDeets::prepare(time64 *date, const char** description)
+{
+ *date = get_date_time();
+ *description = get_description();
+ set_focus ();
+}
+
struct PageStockAmount
{
// stock amount page
@@ -1405,7 +1415,7 @@ struct PageStockAmount
GncAmountEdit m_amount;
GtkWidget * m_amount_label;
PageStockAmount (GtkBuilder *builder, Account* account);
- void prepare (bool input_new_balance, const std::string prev_balance);
+ void prepare (StockTransactionStockEntry*, StockAssistantModel*, StringVec&);
gnc_numeric get_stock_amount () { return m_amount.get(); }
void set_stock_amount (std::string new_amount_str);
void connect(StockAssistantModel *model);
@@ -1424,19 +1434,25 @@ PageStockAmount::PageStockAmount (GtkBuilder *builder, Account* account) :
}
void
-PageStockAmount::prepare (bool input_new_balance, const std::string prev_balance)
+PageStockAmount::prepare (StockTransactionStockEntry* entry, StockAssistantModel* model,
+ StringVec& errors)
{
gtk_label_set_text_with_mnemonic
(GTK_LABEL (m_amount_label),
- input_new_balance ? _("Ne_w Balance") : _("_Shares"));
+ model->m_input_new_balance ? _("Ne_w Balance") : _("_Shares"));
gtk_label_set_text
(GTK_LABEL (m_next_amount_label),
- input_new_balance ? _("Ratio") : _("Next Balance"));
+ model->m_input_new_balance ? _("Ratio") : _("Next Balance"));
gtk_label_set_text (GTK_LABEL (m_title),
- input_new_balance ?
+ model->m_input_new_balance ?
_("Enter the new balance of shares after the stock split.") :
_("Enter the number of shares you gained or lost in the transaction."));
- gtk_label_set_text (GTK_LABEL (m_prev_amount), prev_balance.c_str());
+ gtk_label_set_text (GTK_LABEL (m_prev_amount), model->get_stock_balance_str().c_str());
+ if (!gnc_numeric_check(get_stock_amount()))
+ entry->set_amount(get_stock_amount(), errors);
+ set_stock_amount(model->get_new_amount_str());
+ m_amount.set_focus();
+
}
static void
@@ -1469,7 +1485,8 @@ struct PageStockValue
GtkWidget * m_memo;
PageStockValue (GtkBuilder *builder, Account* account);
const char* get_memo ();
- void connect (StockAssistantModel *model);
+ void connect(StockAssistantModel *model);
+ void prepare(StockTransactionEntry*, StockAssistantModel*, StringVec&);
void set_price(const gchar *val);
void set_price (std::tuple<bool, gnc_numeric, const char*> price_tuple);
};
@@ -1500,6 +1517,16 @@ PageStockValue::connect(StockAssistantModel *model)
g_signal_connect (m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &model->m_stock_entry->m_memo);
}
+void
+PageStockValue::prepare(StockTransactionEntry* entry, StockAssistantModel* model, StringVec& errors)
+{
+ entry->m_memo = get_memo();
+ if (!gnc_numeric_check(m_value.get()))
+ entry->set_value(m_value.get(), "stock", errors);
+ set_price(model->calculate_price());
+ m_value.set_focus();
+}
+
const char *
PageStockValue::get_memo()
{
@@ -1528,7 +1555,8 @@ struct PageCash
GtkWidget * m_memo;
GncAmountEdit m_value;
PageCash (GtkBuilder *builder, Account* account);
- void connect(Account **account, const char **memo, gnc_numeric *value);
+ void connect(StockTransactionEntry* entry);
+ void prepare(StockTransactionEntry* entry, StringVec& errors);
const char* get_memo();
};
@@ -1544,11 +1572,21 @@ PageCash::PageCash(GtkBuilder *builder, Account* account)
}
void
-PageCash::connect(Account **account, const char **memo, gnc_numeric *value)
+PageCash::connect(StockTransactionEntry* entry)
+{
+ m_account.connect(&entry->m_account);
+ g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
+ m_value.connect(&entry->m_value);
+}
+
+void
+PageCash::prepare(StockTransactionEntry* entry, StringVec& errors)
{
- m_account.connect(account);
- g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), memo);
- m_value.connect(value);
+ entry->m_memo = get_memo();
+ if (!gnc_numeric_check(m_value.get()))
+ entry->set_value (m_value.get(), "cash", errors);
+ entry->m_account = m_account.get();
+ m_value.set_focus();
}
const char *
@@ -1566,13 +1604,14 @@ struct PageFees
GtkWidget * m_memo;
GncAmountEdit m_value;
PageFees (GtkBuilder *builder, Account* account);
- void connect(StockAssistantModel *model);
+ void connect(StockTransactionFeesEntry*);
bool get_capitalize_fees ();
const char* get_memo();
void set_capitalize_fees (bool state);
- void set_capitalize_fees (StockAssistantModel *model);
+ void set_capitalize_fees (StockTransactionFeesEntry*);
void set_account (Account *acct) { m_account.set(acct); }
void update_fees_acct_sensitive (bool sensitive);
+ void prepare(StockTransactionFeesEntry*, StringVec&);
};
PageFees::PageFees(GtkBuilder *builder, Account* account)
@@ -1608,10 +1647,9 @@ PageFees::set_capitalize_fees(bool state)
}
void
-PageFees::set_capitalize_fees(StockAssistantModel *model)
+PageFees::set_capitalize_fees(StockTransactionFeesEntry* entry)
{
- auto fees_entry = dynamic_cast<StockTransactionFeesEntry*>(model->m_fees_entry.get());
- set_capitalize_fees (fees_entry->m_capitalize);
+ set_capitalize_fees (entry->m_capitalize);
}
void
@@ -1621,24 +1659,35 @@ PageFees::update_fees_acct_sensitive(bool sensitive)
}
static void
-capitalize_fees_toggled_cb (GtkWidget *widget, StockAssistantModel *model)
+capitalize_fees_toggled_cb (GtkWidget *widget, StockTransactionFeesEntry *entry)
{
- g_return_if_fail (model && model->m_txn_type);
+ g_return_if_fail (entry);
auto me = static_cast<PageFees *>(g_object_get_data (G_OBJECT (widget), "owner"));
g_return_if_fail (me);
bool cap = me->get_capitalize_fees();
- model->m_fees_entry->set_capitalize(cap);
+ entry->set_capitalize(cap);
me->update_fees_acct_sensitive (!cap);
}
void
-PageFees::connect(StockAssistantModel *model)
+PageFees::connect(StockTransactionFeesEntry* entry)
{
- m_account.connect(&model->m_fees_entry->m_account);
- g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &model->m_fees_entry->m_memo);
- m_value.connect(&model->m_fees_entry->m_value);
+ m_account.connect(&entry->m_account);
+ g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
+ m_value.connect(&entry->m_value);
g_object_set_data(G_OBJECT (m_capitalize), "owner", this);
- g_signal_connect (m_capitalize, "toggled", G_CALLBACK (capitalize_fees_toggled_cb), model);
+ g_signal_connect (m_capitalize, "toggled", G_CALLBACK (capitalize_fees_toggled_cb), entry);
+}
+
+void
+PageFees::prepare(StockTransactionFeesEntry* entry, StringVec& errors)
+{
+ set_capitalize_fees (entry);
+ entry->m_memo = get_memo();
+ if (!gnc_numeric_check(m_value.get()))
+ entry->set_value (m_value.get(), "fees", errors);
+ entry->m_account = m_account.get();
+ m_value.set_focus();
}
struct PageDividend
@@ -1649,7 +1698,8 @@ struct PageDividend
GtkWidget *m_memo;
GncAmountEdit m_value;
PageDividend (GtkBuilder *builder, Account* account);
- void connect(Account **account, const char **memo, gnc_numeric *value);
+ void connect(StockTransactionEntry*);
+ void prepare(StockTransactionEntry*, StringVec&);
const char* get_memo();
};
@@ -1665,11 +1715,21 @@ PageDividend::PageDividend(GtkBuilder *builder, Account* account)
void
-PageDividend::connect(Account **account, const char **memo, gnc_numeric *value)
+PageDividend::connect(StockTransactionEntry* entry)
{
- m_account.connect(account);
- g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), memo);
- m_value.connect(value);
+ m_account.connect(&entry->m_account);
+ g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
+ m_value.connect(&entry->m_value);
+}
+
+void
+PageDividend::prepare(StockTransactionEntry* entry, StringVec& errors)
+{
+ entry->m_memo = get_memo();
+ if (!gnc_numeric_check(m_value.get()))
+ entry->set_value(m_value.get(), "dividend", errors);
+ entry->m_account = m_account.get();
+ m_value.set_focus();
}
const char *
@@ -1686,7 +1746,8 @@ struct PageCapGain
GtkWidget * m_memo;
GncAmountEdit m_value;
PageCapGain (GtkBuilder *builder, Account* account);
- void connect(Account **account, const char **memo, gnc_numeric *value);
+ void connect(StockTransactionsStockCapGainsEntry* entry);
+ void prepare(StockTransactionsStockCapGainsEntry* entry, StringVec& errors);
const char* get_memo();
};
@@ -1708,11 +1769,21 @@ PageCapGain::get_memo()
void
-PageCapGain::connect(Account **account, const char **memo, gnc_numeric *value)
+PageCapGain::connect(StockTransactionsStockCapGainsEntry*entry)
{
- m_account.connect(account);
- g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), memo);
- m_value.connect(value);
+ m_account.connect(&entry->m_account);
+ g_signal_connect(m_memo, "changed", G_CALLBACK(text_entry_changed_cb), &entry->m_memo);
+ m_value.connect(&entry->m_value);
+}
+
+void
+PageCapGain::prepare(StockTransactionsStockCapGainsEntry* entry, StringVec& errors)
+{
+ entry->m_memo = get_memo();
+ if (gnc_numeric_check(m_value.get()))
+ entry->set_value(m_value.get(), "capgains", errors);
+ entry->m_account = m_account.get();
+ m_value.set_focus();
}
/* The last page of the assistant shows what the resulting transaction will look
@@ -1899,13 +1970,14 @@ StockAssistantController::connect_signals (GtkBuilder *builder)
m_view.m_deets_page.connect(&m_model->m_transaction_date, &m_model->m_transaction_description);
m_view.m_stock_amount_page.connect(m_model.get());
m_view.m_stock_value_page.connect(m_model.get());
- m_view.m_cash_page.connect(&m_model->m_cash_entry->m_account, &m_model->m_cash_entry->m_memo,
- &m_model->m_cash_entry->m_value);
- m_view.m_fees_page.connect(m_model.get());
- m_view.m_dividend_page.connect(&m_model->m_dividend_entry->m_account, &m_model->m_dividend_entry->m_memo,
- &m_model->m_dividend_entry->m_value);
- m_view.m_capgain_page.connect(&m_model->m_capgains_entry->m_account, &m_model->m_capgains_entry->m_memo,
- &m_model->m_capgains_entry->m_value);
+ m_view.m_cash_page.connect(m_model->m_cash_entry.get());
+ auto fees_entry = dynamic_cast<StockTransactionFeesEntry *>(m_model->m_fees_entry.get());
+ if (fees_entry)
+ m_view.m_fees_page.connect(fees_entry);
+ m_view.m_dividend_page.connect(m_model->m_dividend_entry.get());
+ auto capgains_entry = dynamic_cast<StockTransactionsStockCapGainsEntry *>(m_model->m_capgains_entry.get());
+ if (capgains_entry)
+ m_view.m_capgain_page.connect(capgains_entry);
g_signal_connect (m_view.m_window, "destroy", G_CALLBACK (stock_assistant_window_destroy_cb), this);
@@ -1931,62 +2003,40 @@ StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
if (!m_model->maybe_reset_txn_types())
break;
m_view.m_type_page.prepare(m_model.get());
- m_view.m_type_page.set_focus();
- m_view.m_fees_page.set_capitalize_fees(m_model.get());
break;
case PAGE_TRANSACTION_DETAILS:
- m_model->m_transaction_date = m_view.m_deets_page.get_date_time();
- m_model->m_transaction_description = m_view.m_deets_page.get_description();
- m_view.m_deets_page.set_focus ();
+ m_view.m_deets_page.prepare(&m_model->m_transaction_date, &m_model->m_transaction_description);
break;
case PAGE_STOCK_AMOUNT:
- m_view.m_stock_amount_page.prepare (m_model->m_input_new_balance,
- m_model->get_stock_balance_str());
- if (!gnc_numeric_check(m_view.m_stock_amount_page.get_stock_amount()))
- m_model->m_stock_entry->set_amount(m_view.m_stock_amount_page.get_stock_amount(),
- m_model->m_errors);
- m_view.m_stock_amount_page.set_stock_amount(m_model->get_new_amount_str());
- m_view.m_stock_amount_page.m_amount.set_focus();
+ {
+ auto stock_entry = dynamic_cast<StockTransactionStockEntry*>(m_model->m_stock_entry.get());
+ if (stock_entry)
+ m_view.m_stock_amount_page.prepare(stock_entry, m_model.get(), m_model->m_errors);
break;
+ }
case PAGE_STOCK_VALUE:
- m_model->m_stock_entry->m_memo = m_view.m_stock_value_page.get_memo();
- if (!gnc_numeric_check(m_view.m_stock_value_page.m_value.get()))
- m_model->m_stock_entry->set_value(m_view.m_stock_value_page.m_value.get(),
- "stock", m_model->m_errors);
- m_view.m_stock_value_page.set_price(m_model->calculate_price());
- m_view.m_stock_value_page.m_value.set_focus();
+ m_view.m_stock_value_page.prepare(m_model->m_stock_entry.get(), m_model.get(), m_model->m_errors);
break;
case PAGE_CASH:
- m_model->m_cash_entry->m_memo = m_view.m_cash_page.get_memo();
- if (!gnc_numeric_check(m_view.m_cash_page.m_value.get()))
- m_model->m_cash_entry->set_value (m_view.m_cash_page.m_value.get(),
- "cash", m_model->m_errors);
- m_model->m_cash_entry->m_account = m_view.m_cash_page.m_account.get();
- m_view.m_cash_page.m_value.set_focus();
+ m_view.m_cash_page.prepare(m_model->m_cash_entry.get(), m_model->m_errors);
break;
case PAGE_FEES:
- m_view.m_fees_page.set_capitalize_fees (m_model.get());
- m_model->m_fees_entry->m_memo = m_view.m_fees_page.get_memo();
- if (!gnc_numeric_check(m_view.m_fees_page.m_value.get()))
- m_model->m_fees_entry->set_value (m_view.m_fees_page.m_value.get(), "fees",
- m_model->m_errors);
- m_model->m_fees_entry->m_account = m_view.m_fees_page.m_account.get();
- m_view.m_fees_page.m_value.set_focus();
+ {
+ auto fees_entry = dynamic_cast<StockTransactionFeesEntry*>(m_model->m_fees_entry.get());
+ if (fees_entry)
+ m_view.m_fees_page.prepare(fees_entry, m_model->m_errors);
break;
+ }
case PAGE_DIVIDEND:
- m_model->m_dividend_entry->m_memo = m_view.m_dividend_page.get_memo();
- if (!gnc_numeric_check(m_view.m_dividend_page.m_value.get()))
- m_model->m_dividend_entry->set_value (m_view.m_dividend_page.m_value.get(), "dividend", m_model->m_errors);
- m_model->m_dividend_entry->m_account = m_view.m_dividend_page.m_account.get();
- m_view.m_dividend_page.m_value.set_focus();
+ m_view.m_dividend_page.prepare(m_model->m_dividend_entry.get(), m_model->m_errors);
break;
case PAGE_CAPGAINS:
- m_model->m_capgains_entry->m_memo = m_view.m_capgain_page.get_memo();
- if (gnc_numeric_check(m_view.m_capgain_page.m_value.get()))
- m_model->m_capgains_entry->set_value(m_view.m_capgain_page.m_value.get(), "capgains", m_model->m_errors);
- m_model->m_capgains_entry->m_account = m_view.m_capgain_page.m_account.get();
- m_view.m_capgain_page.m_value.set_focus();
+ {
+ auto capgain_entry = dynamic_cast<StockTransactionsStockCapGainsEntry*>(m_model->m_capgains_entry.get());
+ if (capgain_entry)
+ m_view.m_capgain_page.prepare(capgain_entry, m_model->m_errors);
break;
+ }
case PAGE_FINISH:
{
m_view.m_finish_page.prepare (m_view.m_window, m_model.get());
commit 4c916ada2205b68e290dc0896ddfc665c120ab64
Author: John Ralls <jralls at ceridwen.us>
Date: Fri Aug 4 16:29:03 2023 -0700
Make connect_signals and prepare StockAssistantController members.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 7ccaa1dce4..da5545cfa0 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -1871,108 +1871,125 @@ StockAssistantView::~StockAssistantView()
/* The StockAssistantController manages the event handlers and user input. */
-static void connect_signals (gpointer, GtkBuilder*);
-
struct StockAssistantController
{
- std::unique_ptr<StockAssistantModel> model;
- StockAssistantView view;
+ std::unique_ptr<StockAssistantModel> m_model;
+ StockAssistantView m_view;
StockAssistantController (GtkWidget *parent, GtkBuilder* builder, Account* acct)
- : model{std::make_unique<StockAssistantModel>(acct)},
- view{builder, acct, parent}
+ : m_model{std::make_unique<StockAssistantModel>(acct)},
+ m_view{builder, acct, parent}
{
- connect_signals (this, builder);
+ connect_signals (builder);
DEBUG ("StockAssistantController constructor\n");
};
~StockAssistantController (){ DEBUG ("StockAssistantController destructor\n"); };
+ void connect_signals(GtkBuilder *builder);
+ void prepare(GtkAssistant* assistant, GtkWidget *page);
};
-// These callbacks must be registered with the GtkAssistant so they can't be member functions.
+static gint forward_page_func(int32_t, StockAssistantController*);
+static void stock_assistant_window_destroy_cb(GtkWidget *object, gpointer user_data);
+static void refresh_handler (GHashTable *changes, gpointer user_data);
+static void close_handler (gpointer user_data);
-static void
-stock_assistant_window_destroy_cb (GtkWidget *object, gpointer user_data)
-{
- auto info = static_cast<StockAssistantController*>(user_data);
- gnc_unregister_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, info);
- delete info;
+void
+StockAssistantController::connect_signals (GtkBuilder *builder)
+{
+ m_view.m_type_page.connect(m_model.get());
+ m_view.m_deets_page.connect(&m_model->m_transaction_date, &m_model->m_transaction_description);
+ m_view.m_stock_amount_page.connect(m_model.get());
+ m_view.m_stock_value_page.connect(m_model.get());
+ m_view.m_cash_page.connect(&m_model->m_cash_entry->m_account, &m_model->m_cash_entry->m_memo,
+ &m_model->m_cash_entry->m_value);
+ m_view.m_fees_page.connect(m_model.get());
+ m_view.m_dividend_page.connect(&m_model->m_dividend_entry->m_account, &m_model->m_dividend_entry->m_memo,
+ &m_model->m_dividend_entry->m_value);
+ m_view.m_capgain_page.connect(&m_model->m_capgains_entry->m_account, &m_model->m_capgains_entry->m_memo,
+ &m_model->m_capgains_entry->m_value);
+
+ g_signal_connect (m_view.m_window, "destroy", G_CALLBACK (stock_assistant_window_destroy_cb), this);
+
+ gtk_assistant_set_forward_page_func (GTK_ASSISTANT(m_view.m_window),
+ (GtkAssistantPageFunc)forward_page_func,
+ this, nullptr);
+ gtk_builder_connect_signals (builder, this); //Stock Assistant View: cancel, close, prepare
+
+ auto component_id = gnc_register_gui_component
+ (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, refresh_handler, close_handler, this);
+ gnc_gui_component_watch_entity_type (component_id, GNC_ID_ACCOUNT,
+ QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
}
void
-stock_assistant_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
- gpointer user_data)
+StockAssistantController::prepare(GtkAssistant* assistant, GtkWidget* page)
{
- auto info = static_cast<StockAssistantController*>(user_data);
- g_return_if_fail (info && info->model);
- auto model = info->model.get();
- auto& view = info->view;
-
auto currentpage = gtk_assistant_get_current_page(assistant);
switch (currentpage)
{
case PAGE_TRANSACTION_TYPE:
- if (!model->maybe_reset_txn_types())
+ if (!m_model->maybe_reset_txn_types())
break;
- view.m_type_page.prepare(model);
- view.m_type_page.set_focus();
- view.m_fees_page.set_capitalize_fees(model);
+ m_view.m_type_page.prepare(m_model.get());
+ m_view.m_type_page.set_focus();
+ m_view.m_fees_page.set_capitalize_fees(m_model.get());
break;
case PAGE_TRANSACTION_DETAILS:
- model->m_transaction_date = view.m_deets_page.get_date_time();
- model->m_transaction_description = view.m_deets_page.get_description();
- view.m_deets_page.set_focus ();
+ m_model->m_transaction_date = m_view.m_deets_page.get_date_time();
+ m_model->m_transaction_description = m_view.m_deets_page.get_description();
+ m_view.m_deets_page.set_focus ();
break;
case PAGE_STOCK_AMOUNT:
- view.m_stock_amount_page.prepare (model->m_input_new_balance,
- model->get_stock_balance_str());
- if (!gnc_numeric_check(view.m_stock_amount_page.get_stock_amount()))
- info->model->m_stock_entry->set_amount(view.m_stock_amount_page.get_stock_amount(),
- model->m_errors);
- view.m_stock_amount_page.set_stock_amount(info->model->get_new_amount_str());
- view.m_stock_amount_page.m_amount.set_focus();
+ m_view.m_stock_amount_page.prepare (m_model->m_input_new_balance,
+ m_model->get_stock_balance_str());
+ if (!gnc_numeric_check(m_view.m_stock_amount_page.get_stock_amount()))
+ m_model->m_stock_entry->set_amount(m_view.m_stock_amount_page.get_stock_amount(),
+ m_model->m_errors);
+ m_view.m_stock_amount_page.set_stock_amount(m_model->get_new_amount_str());
+ m_view.m_stock_amount_page.m_amount.set_focus();
break;
case PAGE_STOCK_VALUE:
- model->m_stock_entry->m_memo = view.m_stock_value_page.get_memo();
- if (!gnc_numeric_check(view.m_stock_value_page.m_value.get()))
- model->m_stock_entry->set_value(view.m_stock_value_page.m_value.get(),
- "stock", model->m_errors);
- view.m_stock_value_page.set_price(model->calculate_price());
- view.m_stock_value_page.m_value.set_focus();
+ m_model->m_stock_entry->m_memo = m_view.m_stock_value_page.get_memo();
+ if (!gnc_numeric_check(m_view.m_stock_value_page.m_value.get()))
+ m_model->m_stock_entry->set_value(m_view.m_stock_value_page.m_value.get(),
+ "stock", m_model->m_errors);
+ m_view.m_stock_value_page.set_price(m_model->calculate_price());
+ m_view.m_stock_value_page.m_value.set_focus();
break;
case PAGE_CASH:
- model->m_cash_entry->m_memo = view.m_cash_page.get_memo();
- if (!gnc_numeric_check(view.m_cash_page.m_value.get()))
- model->m_cash_entry->set_value (view.m_cash_page.m_value.get(),
- "cash", model->m_errors);
- model->m_cash_entry->m_account = view.m_cash_page.m_account.get();
- view.m_cash_page.m_value.set_focus();
+ m_model->m_cash_entry->m_memo = m_view.m_cash_page.get_memo();
+ if (!gnc_numeric_check(m_view.m_cash_page.m_value.get()))
+ m_model->m_cash_entry->set_value (m_view.m_cash_page.m_value.get(),
+ "cash", m_model->m_errors);
+ m_model->m_cash_entry->m_account = m_view.m_cash_page.m_account.get();
+ m_view.m_cash_page.m_value.set_focus();
break;
case PAGE_FEES:
- view.m_fees_page.set_capitalize_fees (info);
- model->m_fees_entry->m_memo = view.m_fees_page.get_memo();
- if (!gnc_numeric_check(view.m_fees_page.m_value.get()))
- model->m_fees_entry->set_value (view.m_fees_page.m_value.get(), "fees",
- model->m_errors);
- model->m_fees_entry->m_account = view.m_fees_page.m_account.get();
- view.m_fees_page.m_value.set_focus();
+ m_view.m_fees_page.set_capitalize_fees (m_model.get());
+ m_model->m_fees_entry->m_memo = m_view.m_fees_page.get_memo();
+ if (!gnc_numeric_check(m_view.m_fees_page.m_value.get()))
+ m_model->m_fees_entry->set_value (m_view.m_fees_page.m_value.get(), "fees",
+ m_model->m_errors);
+ m_model->m_fees_entry->m_account = m_view.m_fees_page.m_account.get();
+ m_view.m_fees_page.m_value.set_focus();
break;
case PAGE_DIVIDEND:
- model->m_dividend_entry->m_memo = view.m_dividend_page.get_memo();
- if (!gnc_numeric_check(view.m_dividend_page.m_value.get()))
- model->m_dividend_entry->set_value (view.m_dividend_page.m_value.get(), "dividend", model->m_errors);
- model->m_dividend_entry->m_account = view.m_dividend_page.m_account.get();
- view.m_dividend_page.m_value.set_focus();
+ m_model->m_dividend_entry->m_memo = m_view.m_dividend_page.get_memo();
+ if (!gnc_numeric_check(m_view.m_dividend_page.m_value.get()))
+ m_model->m_dividend_entry->set_value (m_view.m_dividend_page.m_value.get(), "dividend", m_model->m_errors);
+ m_model->m_dividend_entry->m_account = m_view.m_dividend_page.m_account.get();
+ m_view.m_dividend_page.m_value.set_focus();
break;
case PAGE_CAPGAINS:
- model->m_capgains_entry->m_memo = view.m_capgain_page.get_memo();
- if (gnc_numeric_check(view.m_capgain_page.m_value.get()))
- model->m_capgains_entry->set_value(view.m_capgain_page.m_value.get(), "capgains", model->m_errors);
- model->m_capgains_entry->m_account = view.m_capgain_page.m_account.get();
- view.m_capgain_page.m_value.set_focus();
+ m_model->m_capgains_entry->m_memo = m_view.m_capgain_page.get_memo();
+ if (gnc_numeric_check(m_view.m_capgain_page.m_value.get()))
+ m_model->m_capgains_entry->set_value(m_view.m_capgain_page.m_value.get(), "capgains", m_model->m_errors);
+ m_model->m_capgains_entry->m_account = m_view.m_capgain_page.m_account.get();
+ m_view.m_capgain_page.m_value.set_focus();
break;
case PAGE_FINISH:
{
- view.m_finish_page.prepare (view.m_window, model);
+ m_view.m_finish_page.prepare (m_view.m_window, m_model.get());
break;
}
default:
@@ -1980,10 +1997,29 @@ stock_assistant_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
}
}
+
+// These callbacks must be registered with the GtkAssistant so they can't be member functions.
+
+static void
+stock_assistant_window_destroy_cb (GtkWidget *object, gpointer user_data)
+{
+ auto info = static_cast<StockAssistantController*>(user_data);
+ gnc_unregister_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, info);
+ delete info;
+}
+
+void
+stock_assistant_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
+ gpointer user_data)
+{
+ auto info = static_cast<StockAssistantController*>(user_data);
+ info->prepare(assistant, page);
+}
+
static gint
forward_page_func (gint current_page, StockAssistantController* info)
{
- auto model = info->model.get();
+ auto model = info->m_model.get();
current_page++;
if (!model->m_txn_type)
@@ -2010,10 +2046,10 @@ void
stock_assistant_finish_cb (GtkAssistant *assistant, gpointer user_data)
{
auto info = static_cast<StockAssistantController*>(user_data);
- g_return_if_fail (info->model->m_txn_type);
+ g_return_if_fail (info->m_model->m_txn_type);
gnc_suspend_gui_refresh ();
- [[maybe_unused]] auto [success, trans] = info->model->create_transaction();
+ [[maybe_unused]] auto [success, trans] = info->m_model->create_transaction();
gnc_resume_gui_refresh ();
gnc_close_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, info);
@@ -2033,9 +2069,9 @@ refresh_handler (GHashTable *changes, gpointer user_data)
{
auto info = static_cast<StockAssistantController*>(user_data);
- if (!GNC_IS_ACCOUNT (info->model->m_acct))
+ if (!GNC_IS_ACCOUNT (info->m_model->m_acct))
{
- PWARN ("account %p does not exist anymore. abort", info->model->m_acct);
+ PWARN ("account %p does not exist anymore. abort", info->m_model->m_acct);
gnc_close_gui_component_by_data (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, info);
}
}
@@ -2044,35 +2080,7 @@ static void
close_handler (gpointer user_data)
{
auto info = static_cast<StockAssistantController*>(user_data);
- gtk_widget_destroy (info->view.m_window);
-}
-
-static void connect_signals (gpointer data, GtkBuilder *builder)
-{
- auto info = static_cast<StockAssistantController*>(data);
- auto model = info->model.get();
- auto& view = info->view;
-
- view.m_type_page.connect(model);
- view.m_deets_page.connect(&model->m_transaction_date, &model->m_transaction_description);
- view.m_stock_amount_page.connect(model);
- view.m_stock_value_page.connect(model);
- view.m_cash_page.connect(&model->m_cash_entry->m_account, &model->m_cash_entry->m_memo, &model->m_cash_entry->m_value);
- view.m_fees_page.connect(model);
- view.m_dividend_page.connect(&model->m_dividend_entry->m_account, &model->m_dividend_entry->m_memo, &model->m_dividend_entry->m_value);
- view.m_capgain_page.connect(&model->m_capgains_entry->m_account, &model->m_capgains_entry->m_memo, &model->m_capgains_entry->m_value);
-
- g_signal_connect (view.m_window, "destroy", G_CALLBACK (stock_assistant_window_destroy_cb), info);
-
- gtk_assistant_set_forward_page_func (GTK_ASSISTANT(view.m_window),
- (GtkAssistantPageFunc)forward_page_func,
- info, nullptr);
- gtk_builder_connect_signals (builder, info); //Stock Assistant View: cancel, close, prepare
-
- auto component_id = gnc_register_gui_component
- (ASSISTANT_STOCK_TRANSACTION_CM_CLASS, refresh_handler, close_handler, info);
- gnc_gui_component_watch_entity_type (component_id, GNC_ID_ACCOUNT,
- QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
+ gtk_widget_destroy (info->m_view.m_window);
}
/********************************************************************\
commit 30b41544ce0b406333b5cd01564f7b95b49937bf
Author: John Ralls <jralls at ceridwen.us>
Date: Fri Aug 4 14:12:03 2023 -0700
Make StockAssistantController's view member in-place instead of a unique_ptr.
Requires moving some parameters around so we can initialize it
correctly:
All of the view's pages need to take an Account* and get its commodity
or currency in their ctors, and creation of the builder has to move to
gnc_stock_transaction_assistant and get passed in.
diff --git a/gnucash/gnome/assistant-stock-transaction.cpp b/gnucash/gnome/assistant-stock-transaction.cpp
index 6b2d428581..7ccaa1dce4 100644
--- a/gnucash/gnome/assistant-stock-transaction.cpp
+++ b/gnucash/gnome/assistant-stock-transaction.cpp
@@ -1404,20 +1404,20 @@ struct PageStockAmount
GtkWidget * m_next_amount_label;
GncAmountEdit m_amount;
GtkWidget * m_amount_label;
- PageStockAmount (GtkBuilder *builder, gnc_commodity *commodity);
+ PageStockAmount (GtkBuilder *builder, Account* account);
void prepare (bool input_new_balance, const std::string prev_balance);
gnc_numeric get_stock_amount () { return m_amount.get(); }
void set_stock_amount (std::string new_amount_str);
void connect(StockAssistantModel *model);
};
-PageStockAmount::PageStockAmount (GtkBuilder *builder, gnc_commodity *stock_commodity) :
+PageStockAmount::PageStockAmount (GtkBuilder *builder, Account* account) :
m_page (get_widget (builder, "stock_amount_page")),
m_title (get_widget (builder, "stock_amount_title")),
m_prev_amount (get_widget (builder, "prev_balance_amount")),
m_next_amount (get_widget (builder, "next_balance_amount")),
m_next_amount_label (get_widget (builder, "next_balance_label")),
- m_amount (builder, stock_commodity),
+ m_amount (builder, xaccAccountGetCommodity(account)),
m_amount_label (get_widget (builder, "stock_amount_label"))
{
m_amount.attach (builder, "stock_amount_table", "stock_amount_label", 1);
@@ -1467,7 +1467,7 @@ struct PageStockValue
GncAmountEdit m_value;
GtkWidget * m_price;
GtkWidget * m_memo;
- PageStockValue (GtkBuilder *builder, gnc_commodity *currency);
+ PageStockValue (GtkBuilder *builder, Account* account);
const char* get_memo ();
void connect (StockAssistantModel *model);
void set_price(const gchar *val);
@@ -1483,9 +1483,9 @@ page_stock_value_changed_cb(GtkWidget *widget, StockAssistantModel *model)
me->set_price (model->calculate_price());
}
-PageStockValue::PageStockValue(GtkBuilder *builder, gnc_commodity *currency)
+PageStockValue::PageStockValue(GtkBuilder *builder, Account* account)
: m_page(get_widget(builder, "stock_value_page")),
- m_value(builder, currency),
+ m_value(builder, gnc_account_get_currency_or_parent(account)),
m_price(get_widget(builder, "stock_price_amount")),
m_memo(get_widget(builder, "stock_memo_entry"))
{
@@ -1527,17 +1527,17 @@ struct PageCash
GncAccountSelector m_account;
GtkWidget * m_memo;
GncAmountEdit m_value;
- PageCash (GtkBuilder *builder, gnc_commodity *currency);
+ PageCash (GtkBuilder *builder, Account* account);
void connect(Account **account, const char **memo, gnc_numeric *value);
const char* get_memo();
};
-PageCash::PageCash(GtkBuilder *builder, gnc_commodity *currency)
+PageCash::PageCash(GtkBuilder *builder, Account* account)
: m_page(get_widget(builder, "cash_details_page")),
m_account(builder, {ACCT_TYPE_ASSET, ACCT_TYPE_BANK},
- currency),
+ gnc_account_get_currency_or_parent(account)),
m_memo(get_widget(builder, "cash_memo_entry")),
- m_value(builder, currency)
+ m_value(builder, gnc_account_get_currency_or_parent(account))
{
m_account.attach (builder, "cash_table", "cash_account_label", 0);
m_value.attach (builder, "cash_table", "cash_label", 1);
@@ -1565,7 +1565,7 @@ struct PageFees
GncAccountSelector m_account;
GtkWidget * m_memo;
GncAmountEdit m_value;
- PageFees (GtkBuilder *builder, gnc_commodity *currency);
+ PageFees (GtkBuilder *builder, Account* account);
void connect(StockAssistantModel *model);
bool get_capitalize_fees ();
const char* get_memo();
@@ -1575,13 +1575,13 @@ struct PageFees
void update_fees_acct_sensitive (bool sensitive);
};
-PageFees::PageFees(GtkBuilder *builder, gnc_commodity *currency)
+PageFees::PageFees(GtkBuilder *builder, Account* account)
: m_page(get_widget(builder, "fees_details_page")),
m_capitalize(
get_widget(builder, "capitalize_fees_checkbutton")),
- m_account(builder, {ACCT_TYPE_EXPENSE}, currency),
+ m_account(builder, {ACCT_TYPE_EXPENSE}, gnc_account_get_currency_or_parent(account)),
m_memo(get_widget(builder, "fees_memo_entry")),
- m_value(builder, currency)
+ m_value(builder, gnc_account_get_currency_or_parent(account))
{
m_account.attach (builder, "fees_table", "fees_account_label", 1);
m_value.attach(builder, "fees_table", "fees_label", 2);
@@ -1648,16 +1648,16 @@ struct PageDividend
GncAccountSelector m_account;
GtkWidget *m_memo;
GncAmountEdit m_value;
- PageDividend (GtkBuilder *builder, gnc_commodity *currency);
+ PageDividend (GtkBuilder *builder, Account* account);
void connect(Account **account, const char **memo, gnc_numeric *value);
const char* get_memo();
};
-PageDividend::PageDividend(GtkBuilder *builder, gnc_commodity *currency)
+PageDividend::PageDividend(GtkBuilder *builder, Account* account)
: m_page(get_widget(builder, "dividend_details_page")),
- m_account(builder, {ACCT_TYPE_INCOME}, currency),
+ m_account(builder, {ACCT_TYPE_INCOME}, gnc_account_get_currency_or_parent(account)),
m_memo(get_widget(builder, "dividend_memo_entry")),
- m_value(builder, currency)
+ m_value(builder, gnc_account_get_currency_or_parent(account))
{
m_account.attach(builder, "dividend_table", "dividend_account_label", 0);
m_value.attach(builder, "dividend_table", "dividend_label", 1);
@@ -1685,16 +1685,16 @@ struct PageCapGain
GncAccountSelector m_account;
GtkWidget * m_memo;
GncAmountEdit m_value;
- PageCapGain (GtkBuilder *builder, gnc_commodity *currency);
+ PageCapGain (GtkBuilder *builder, Account* account);
void connect(Account **account, const char **memo, gnc_numeric *value);
const char* get_memo();
};
-PageCapGain::PageCapGain (GtkBuilder *builder, gnc_commodity *currency) :
+PageCapGain::PageCapGain (GtkBuilder *builder, Account* account) :
m_page (get_widget (builder, "capgains_details_page")),
- m_account (builder, { ACCT_TYPE_INCOME }, currency),
+ m_account (builder, { ACCT_TYPE_INCOME }, gnc_account_get_currency_or_parent(account)),
m_memo (get_widget (builder, "capgains_memo_entry")),
- m_value (builder, currency)
+ m_value (builder, gnc_account_get_currency_or_parent(account))
{
m_account.attach(builder, "capgains_table", "capgains_account_label", 0);
m_value.attach(builder, "capgains_table", "capgains_label", 1);
@@ -1839,19 +1839,17 @@ struct StockAssistantView {
PageCapGain m_capgain_page;
PageFinish m_finish_page;
- StockAssistantView(GtkBuilder *builder, gnc_commodity *stock_commodity,
- gnc_commodity *currency, GtkWidget *parent);
+ StockAssistantView(GtkBuilder *builder, Account* account, GtkWidget *parent);
~StockAssistantView();
void set_focus (GtkWidget *widget) { gtk_widget_grab_focus (widget); }
void set_focus_gae (GtkWidget *gae) { set_focus (GTK_WIDGET (gnc_amount_edit_gtk_entry (GNC_AMOUNT_EDIT (gae)))); }
};
-StockAssistantView::StockAssistantView (GtkBuilder *builder, gnc_commodity *stock_commodity,
- gnc_commodity *currency, GtkWidget *parent) :
+StockAssistantView::StockAssistantView (GtkBuilder *builder, Account* account, GtkWidget *parent) :
m_window (get_widget (builder, "stock_transaction_assistant")), m_type_page(builder), m_deets_page(builder),
- m_stock_amount_page (builder, currency), m_stock_value_page (builder, currency), m_cash_page (builder, currency),
- m_fees_page (builder, currency), m_dividend_page (builder, currency), m_capgain_page (builder, currency),
+ m_stock_amount_page (builder, account), m_stock_value_page (builder, account), m_cash_page (builder, account),
+ m_fees_page (builder, account), m_dividend_page (builder, account), m_capgain_page (builder, account),
m_finish_page (builder)
{
// Set the name for this assistant so it can be easily manipulated with css
@@ -1878,17 +1876,12 @@ static void connect_signals (gpointer, GtkBuilder*);
struct StockAssistantController
{
std::unique_ptr<StockAssistantModel> model;
- std::unique_ptr<StockAssistantView> view;
- StockAssistantController (GtkWidget *parent, Account* acct)
- : model (std::make_unique<StockAssistantModel>(acct))
+ StockAssistantView view;
+ StockAssistantController (GtkWidget *parent, GtkBuilder* builder, Account* acct)
+ : model{std::make_unique<StockAssistantModel>(acct)},
+ view{builder, acct, parent}
{
- auto builder = gtk_builder_new();
- gnc_builder_add_from_file (builder, "assistant-stock-transaction.glade",
- "stock_transaction_assistant");
- this->view = std::make_unique<StockAssistantView>
- (builder, xaccAccountGetCommodity (acct), this->model->m_currency, parent);
connect_signals (this, builder);
- g_object_unref (builder);
DEBUG ("StockAssistantController constructor\n");
};
~StockAssistantController (){ DEBUG ("StockAssistantController destructor\n"); };
@@ -1911,7 +1904,7 @@ stock_assistant_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
auto info = static_cast<StockAssistantController*>(user_data);
g_return_if_fail (info && info->model);
auto model = info->model.get();
- auto view = info->view.get();
+ auto& view = info->view;
auto currentpage = gtk_assistant_get_current_page(assistant);
@@ -1920,66 +1913,66 @@ stock_assistant_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
case PAGE_TRANSACTION_TYPE:
if (!model->maybe_reset_txn_types())
break;
- view->m_type_page.prepare(model);
- view->m_type_page.set_focus();
- view->m_fees_page.set_capitalize_fees(model);
+ view.m_type_page.prepare(model);
+ view.m_type_page.set_focus();
+ view.m_fees_page.set_capitalize_fees(model);
break;
case PAGE_TRANSACTION_DETAILS:
- model->m_transaction_date = view->m_deets_page.get_date_time();
- model->m_transaction_description = view->m_deets_page.get_description();
- view->m_deets_page.set_focus ();
+ model->m_transaction_date = view.m_deets_page.get_date_time();
+ model->m_transaction_description = view.m_deets_page.get_description();
+ view.m_deets_page.set_focus ();
break;
case PAGE_STOCK_AMOUNT:
- view->m_stock_amount_page.prepare (model->m_input_new_balance,
+ view.m_stock_amount_page.prepare (model->m_input_new_balance,
model->get_stock_balance_str());
- if (!gnc_numeric_check(view->m_stock_amount_page.get_stock_amount()))
- info->model->m_stock_entry->set_amount(view->m_stock_amount_page.get_stock_amount(),
+ if (!gnc_numeric_check(view.m_stock_amount_page.get_stock_amount()))
+ info->model->m_stock_entry->set_amount(view.m_stock_amount_page.get_stock_amount(),
model->m_errors);
- view->m_stock_amount_page.set_stock_amount(info->model->get_new_amount_str());
- view->m_stock_amount_page.m_amount.set_focus();
+ view.m_stock_amount_page.set_stock_amount(info->model->get_new_amount_str());
+ view.m_stock_amount_page.m_amount.set_focus();
break;
case PAGE_STOCK_VALUE:
- model->m_stock_entry->m_memo = view->m_stock_value_page.get_memo();
- if (!gnc_numeric_check(view->m_stock_value_page.m_value.get()))
- model->m_stock_entry->set_value(view->m_stock_value_page.m_value.get(),
+ model->m_stock_entry->m_memo = view.m_stock_value_page.get_memo();
+ if (!gnc_numeric_check(view.m_stock_value_page.m_value.get()))
+ model->m_stock_entry->set_value(view.m_stock_value_page.m_value.get(),
"stock", model->m_errors);
- view->m_stock_value_page.set_price(model->calculate_price());
- view->m_stock_value_page.m_value.set_focus();
+ view.m_stock_value_page.set_price(model->calculate_price());
+ view.m_stock_value_page.m_value.set_focus();
break;
case PAGE_CASH:
- model->m_cash_entry->m_memo = view->m_cash_page.get_memo();
- if (!gnc_numeric_check(view->m_cash_page.m_value.get()))
- model->m_cash_entry->set_value (view->m_cash_page.m_value.get(),
+ model->m_cash_entry->m_memo = view.m_cash_page.get_memo();
+ if (!gnc_numeric_check(view.m_cash_page.m_value.get()))
+ model->m_cash_entry->set_value (view.m_cash_page.m_value.get(),
"cash", model->m_errors);
- model->m_cash_entry->m_account = view->m_cash_page.m_account.get();
- view->m_cash_page.m_value.set_focus();
+ model->m_cash_entry->m_account = view.m_cash_page.m_account.get();
+ view.m_cash_page.m_value.set_focus();
break;
case PAGE_FEES:
- view->m_fees_page.set_capitalize_fees (info);
- model->m_fees_entry->m_memo = view->m_fees_page.get_memo();
- if (!gnc_numeric_check(view->m_fees_page.m_value.get()))
- model->m_fees_entry->set_value (view->m_fees_page.m_value.get(), "fees",
+ view.m_fees_page.set_capitalize_fees (info);
+ model->m_fees_entry->m_memo = view.m_fees_page.get_memo();
+ if (!gnc_numeric_check(view.m_fees_page.m_value.get()))
+ model->m_fees_entry->set_value (view.m_fees_page.m_value.get(), "fees",
model->m_errors);
- model->m_fees_entry->m_account = view->m_fees_page.m_account.get();
- view->m_fees_page.m_value.set_focus();
+ model->m_fees_entry->m_account = view.m_fees_page.m_account.get();
+ view.m_fees_page.m_value.set_focus();
break;
case PAGE_DIVIDEND:
- model->m_dividend_entry->m_memo = view->m_dividend_page.get_memo();
- if (!gnc_numeric_check(view->m_dividend_page.m_value.get()))
- model->m_dividend_entry->set_value (view->m_dividend_page.m_value.get(), "dividend", model->m_errors);
- model->m_dividend_entry->m_account = view->m_dividend_page.m_account.get();
- view->m_dividend_page.m_value.set_focus();
+ model->m_dividend_entry->m_memo = view.m_dividend_page.get_memo();
+ if (!gnc_numeric_check(view.m_dividend_page.m_value.get()))
+ model->m_dividend_entry->set_value (view.m_dividend_page.m_value.get(), "dividend", model->m_errors);
+ model->m_dividend_entry->m_account = view.m_dividend_page.m_account.get();
+ view.m_dividend_page.m_value.set_focus();
break;
case PAGE_CAPGAINS:
- model->m_capgains_entry->m_memo = view->m_capgain_page.get_memo();
- if (gnc_numeric_check(view->m_capgain_page.m_value.get()))
- model->m_capgains_entry->set_value(view->m_capgain_page.m_value.get(), "capgains", model->m_errors);
- model->m_capgains_entry->m_account = view->m_capgain_page.m_account.get();
- view->m_capgain_page.m_value.set_focus();
+ model->m_capgains_entry->m_memo = view.m_capgain_page.get_memo();
+ if (gnc_numeric_check(view.m_capgain_page.m_value.get()))
+ model->m_capgains_entry->set_value(view.m_capgain_page.m_value.get(), "capgains", model->m_errors);
+ model->m_capgains_entry->m_account = view.m_capgain_page.m_account.get();
+ view.m_capgain_page.m_value.set_focus();
break;
case PAGE_FINISH:
{
- view->m_finish_page.prepare (view->m_window, model);
+ view.m_finish_page.prepare (view.m_window, model);
break;
}
default:
@@ -2051,27 +2044,27 @@ static void
close_handler (gpointer user_data)
{
auto info = static_cast<StockAssistantController*>(user_data);
- gtk_widget_destroy (info->view->m_window);
+ gtk_widget_destroy (info->view.m_window);
}
static void connect_signals (gpointer data, GtkBuilder *builder)
{
auto info = static_cast<StockAssistantController*>(data);
auto model = info->model.get();
- auto view = info->view.get();
+ auto& view = info->view;
- view->m_type_page.connect(model);
- view->m_deets_page.connect(&model->m_transaction_date, &model->m_transaction_description);
- view->m_stock_amount_page.connect(model);
- view->m_stock_value_page.connect(model);
- view->m_cash_page.connect(&model->m_cash_entry->m_account, &model->m_cash_entry->m_memo, &model->m_cash_entry->m_value);
- view->m_fees_page.connect(model);
- view->m_dividend_page.connect(&model->m_dividend_entry->m_account, &model->m_dividend_entry->m_memo, &model->m_dividend_entry->m_value);
- view->m_capgain_page.connect(&model->m_capgains_entry->m_account, &model->m_capgains_entry->m_memo, &model->m_capgains_entry->m_value);
+ view.m_type_page.connect(model);
+ view.m_deets_page.connect(&model->m_transaction_date, &model->m_transaction_description);
+ view.m_stock_amount_page.connect(model);
+ view.m_stock_value_page.connect(model);
+ view.m_cash_page.connect(&model->m_cash_entry->m_account, &model->m_cash_entry->m_memo, &model->m_cash_entry->m_value);
+ view.m_fees_page.connect(model);
+ view.m_dividend_page.connect(&model->m_dividend_entry->m_account, &model->m_dividend_entry->m_memo, &model->m_dividend_entry->m_value);
+ view.m_capgain_page.connect(&model->m_capgains_entry->m_account, &model->m_capgains_entry->m_memo, &model->m_capgains_entry->m_value);
- g_signal_connect (view->m_window, "destroy", G_CALLBACK (stock_assistant_window_destroy_cb), info);
+ g_signal_connect (view.m_window, "destroy", G_CALLBACK (stock_assistant_window_destroy_cb), info);
- gtk_assistant_set_forward_page_func (GTK_ASSISTANT(view->m_window),
+ gtk_assistant_set_forward_page_func (GTK_ASSISTANT(view.m_window),
(GtkAssistantPageFunc)forward_page_func,
info, nullptr);
gtk_builder_connect_signals (builder, info); //Stock Assistant View: cancel, close, prepare
@@ -2093,5 +2086,10 @@ static void connect_signals (gpointer data, GtkBuilder *builder)
void
gnc_stock_transaction_assistant (GtkWidget *parent, Account *account)
{
- [[maybe_unused]]auto info = new StockAssistantController (parent, account);
+ auto builder = gtk_builder_new();
+ gnc_builder_add_from_file(builder, "assistant-stock-transaction.glade",
+ "stock_transaction_assistant");
+
+ [[maybe_unused]] auto info = new StockAssistantController(parent, builder, account);
+ g_object_unref(builder);
}
Summary of changes:
gnucash/gnome/assistant-stock-transaction.cpp | 2061 +++++++++++++-------
.../test/gtest-assistant-stock-transaction.cpp | 35 +-
.../gtkbuilder/assistant-stock-transaction.glade | 2 +-
3 files changed, 1345 insertions(+), 753 deletions(-)
More information about the gnucash-changes
mailing list