diff --git a/gnucash/register/register-core/CMakeLists.txt b/gnucash/register/register-core/CMakeLists.txt index 51fa9110ce..c593b84d82 100644 --- a/gnucash/register/register-core/CMakeLists.txt +++ b/gnucash/register/register-core/CMakeLists.txt @@ -1,4 +1,5 @@ set (register_core_SOURCES + assoccell.c basiccell.c cell-factory.c cellblock.c @@ -18,6 +19,7 @@ set (register_core_SOURCES set (register_core_HEADERS + assoccell.h basiccell.h cell-factory.h cellblock.h diff --git a/gnucash/register/register-core/assoccell.c b/gnucash/register/register-core/assoccell.c new file mode 100644 index 0000000000..c91a5d640b --- /dev/null +++ b/gnucash/register/register-core/assoccell.c @@ -0,0 +1,289 @@ +/********************************************************************\ + * assoccell.c -- association checkbox cell * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * + * * +\********************************************************************/ + +/* + * FILE: + * assoccell.c + * + * FUNCTION: + * Implements a mouse-click cell that allows a series + * of values to be clicked through and return a glyth if + * font allows it. + * + * HISTORY: + * Copyright (c) 1998 Linas Vepstas + * Copyright (c) 2000 Dave Peticolas + * Copyright (c) 2001 Derek Atkins + * Copyright (c) 2020 Robert Fewell + */ + +#include + +#include +#include +#include + +#include "basiccell.h" +#include "gnc-engine.h" +#include "assoccell.h" +#include "gnc-ui-util.h" + +static void gnc_assoc_cell_set_value (BasicCell *_cell, const char *value); + +const char * +gnc_assoc_get_glyph_from_flag (char association_flag) +{ + switch (association_flag) + { + case WASSOC: + return GLYPH_LINK; + case FASSOC: + return GLYPH_PAPERCLIP; + default: + return " "; + } +} + +static const char +gnc_assoc_get_flag_from_glyph (const char *glyph) +{ + if (strcmp (glyph, GLYPH_LINK) == 0) + return WASSOC; + else if (strcmp (glyph, GLYPH_PAPERCLIP) == 0) + return FASSOC; + else + return ' '; +} + +gboolean +gnc_assoc_get_use_glyphs (AssocCell *cell) +{ + return cell->use_glyphs; +} + +static const char * +gnc_assoc_cell_get_string (AssocCell *cell, char flag) +{ + static char str[2] = { 0, 0 }; + + if (cell->use_glyphs) + return gnc_assoc_get_glyph_from_flag (flag); + + if (cell->get_string != NULL) + return (cell->get_string)(flag); + + str[0] = flag; + + return str; +} + +static gboolean +gnc_assoc_cell_enter (BasicCell *_cell, + int *cursor_position, + int *start_selection, + int *end_selection) +{ + AssocCell *cell = (AssocCell *) _cell; + char * this_flag; + + if (cell->confirm_cb && + ! (cell->confirm_cb (cell->flag, cell->confirm_data))) + return FALSE; + + if (cell->read_only == TRUE) + return FALSE; + + /* Find the current flag in the list of flags */ + this_flag = strchr (cell->flag_order, cell->flag); + + if (this_flag == NULL || *this_flag == '\0') + { + /* If it's not there (or the list is empty) use default_flag */ + cell->flag = cell->default_flag; + } + else + { + /* It is in the list -- choose the -next- item in the list (wrapping + * around as necessary). + */ + this_flag++; + if (*this_flag != '\0') + cell->flag = *this_flag; + else + cell->flag = *(cell->flag_order); + } + + /* And set the display */ + gnc_assoc_cell_set_flag (cell, cell->flag); + + return FALSE; +} + +static void +gnc_assoc_cell_init (AssocCell *cell) +{ + gnc_basic_cell_init (&cell->cell); + + gnc_assoc_cell_set_flag (cell, '\0'); + cell->confirm_cb = NULL; + cell->get_string = NULL; + cell->valid_flags = ""; + cell->flag_order = ""; + cell->read_only = FALSE; + cell->use_glyphs = FALSE; + + cell->cell.enter_cell = gnc_assoc_cell_enter; + cell->cell.set_value = gnc_assoc_cell_set_value; +} + +BasicCell * +gnc_assoc_cell_new (void) +{ + AssocCell * cell; + + cell = g_new0 (AssocCell, 1); + + gnc_assoc_cell_init (cell); + + return &cell->cell; +} + +/* assumes we are given the untranslated form */ +static void +gnc_assoc_cell_set_value (BasicCell *_cell, const char *value) +{ + AssocCell *cell = (AssocCell *) _cell; + char flag; + + if (!value || *value == '\0') + { + cell->flag = cell->default_flag; + gnc_basic_cell_set_value_internal (_cell, ""); + return; + } + + if (cell->use_glyphs) + flag = gnc_assoc_get_flag_from_glyph (value); + else + { + flag = cell->default_flag; + if (strchr (cell->valid_flags, *value) != NULL) + flag = *value; + } + gnc_assoc_cell_set_flag (cell, flag); +} + +void +gnc_assoc_cell_set_flag (AssocCell *cell, char flag) +{ + const char *string; + + g_return_if_fail (cell != NULL); + + cell->flag = flag; + string = gnc_assoc_cell_get_string (cell, flag); + + gnc_basic_cell_set_value_internal (&cell->cell, string); +} + +char +gnc_assoc_cell_get_flag (AssocCell *cell) +{ + g_return_val_if_fail (cell != NULL, '\0'); + + return cell->flag; +} + +void +gnc_assoc_cell_set_string_getter (AssocCell *cell, + AssocCellStringGetter get_string) +{ + g_return_if_fail (cell != NULL); + + cell->get_string = get_string; +} + +void +gnc_assoc_cell_set_confirm_cb (AssocCell *cell, AssocCellConfirm confirm_cb, + gpointer data) +{ + g_return_if_fail (cell != NULL); + + cell->confirm_cb = confirm_cb; + cell->confirm_data = data; +} + +void +gnc_assoc_cell_set_valid_flags (AssocCell *cell, const char *flags, + char default_flag) +{ + g_return_if_fail (cell != NULL); + g_return_if_fail (flags != NULL); + + cell->valid_flags = (char *)flags; + cell->default_flag = default_flag; +} + +void +gnc_assoc_cell_set_flag_order (AssocCell *cell, const char *flags) +{ + g_return_if_fail (cell != NULL); + g_return_if_fail (flags != NULL); + + cell->flag_order = (char *)flags; +} + +void +gnc_assoc_cell_set_read_only (AssocCell *cell, gboolean read_only) +{ + g_return_if_fail (cell != NULL); + + cell->read_only = read_only; +} + +void +gnc_assoc_cell_set_use_glyphs (AssocCell *cell) +{ + gboolean use_glyphs = TRUE; + gchar *test_text; + GtkWidget *label; + PangoLayout *test_layout; + gint count; + + g_return_if_fail (cell != NULL); + + label = gtk_label_new (NULL); + test_text = g_strconcat (GLYPH_LINK, ",", GLYPH_PAPERCLIP, NULL); + test_layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), test_text); + + pango_layout_set_text (test_layout, test_text, strlen (test_text)); + + count = pango_layout_get_unknown_glyphs_count (test_layout); + + if (count != 0) + use_glyphs = FALSE; + + g_object_unref (test_layout); + g_free (test_text); + + cell->use_glyphs = use_glyphs; +} diff --git a/gnucash/register/register-core/assoccell.h b/gnucash/register/register-core/assoccell.h new file mode 100644 index 0000000000..519d27c635 --- /dev/null +++ b/gnucash/register/register-core/assoccell.h @@ -0,0 +1,100 @@ +/********************************************************************\ + * assoccell.h -- association checkbox cell * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * + * * +\********************************************************************/ + +/** @addtogroup Cell Cell + * @{ + * @file assoccell.h + * @struct AssocCell + * @brief The AssocCell object implements a cell handler + * that will cycle through a series of single-character + * values when clicked upon by the mouse and will return a glyph + * if font can show it. + */ +/* HISTORY: + * Copyright (c) 1998 Linas Vepstas + * Copyright (c) 2000 Dave Peticolas + * Copyright (c) 2001 Derek Atkins + * Copyright (c) 2020 Robert Fewell + */ + +#ifndef ASSOC_CELL_H +#define ASSOC_CELL_H + +#include + +#include "basiccell.h" + +#define GLYPH_PAPERCLIP "\360\237\223\216" // Codepoint U+1F4CE +#define GLYPH_LINK "\360\237\224\227" // Codepoint U+1F517 + +typedef const char * (*AssocCellStringGetter) (char flag); +typedef gboolean (*AssocCellConfirm) (char old_flag, gpointer data); + +typedef struct +{ + BasicCell cell; + + char flag; /** The actual flag value */ + + char * valid_flags; /** The list of valid flags */ + char * flag_order; /** Automatic flag selection order */ + char default_flag; /** Default flag for unknown user input */ + + AssocCellStringGetter get_string; + AssocCellConfirm confirm_cb; + gpointer confirm_data; + gboolean read_only; + gboolean use_glyphs; +} AssocCell; + +BasicCell * gnc_assoc_cell_new (void); + +void gnc_assoc_cell_set_flag (AssocCell *cell, char flag); +char gnc_assoc_cell_get_flag (AssocCell *cell); + +void gnc_assoc_cell_set_confirm_cb (AssocCell *cell, + AssocCellConfirm confirm_cb, + gpointer data); + +void gnc_assoc_cell_set_string_getter (AssocCell *cell, + AssocCellStringGetter getter); + +/** note that @param flags is copied into the RecnCell directly, but + * remains the "property" of the caller. The caller must maintain the + * chars pointer, and the caller must setup a mechanism to 'free' the + * chars pointer. The rationale is that you may have many AssocCell + * objects that use the same set of flags. + */ +void gnc_assoc_cell_set_valid_flags (AssocCell *cell, const char *flags, + char default_flag); +void gnc_assoc_cell_set_flag_order (AssocCell *cell, const char *flags); + +void gnc_assoc_cell_set_read_only (AssocCell *cell, gboolean read_only); + +void gnc_assoc_cell_set_use_glyphs (AssocCell *cell); + +gboolean gnc_assoc_get_use_glyphs (AssocCell *cell); + +const char * gnc_assoc_get_glyph_from_flag (char association_flag); + +/** @} */ +#endif diff --git a/gnucash/register/register-core/register-common.c b/gnucash/register/register-core/register-common.c index c350a7650d..47818881e4 100644 --- a/gnucash/register/register-core/register-common.c +++ b/gnucash/register/register-core/register-common.c @@ -23,6 +23,7 @@ #include +#include "assoccell.h" #include "basiccell.h" #include "cell-factory.h" #include "combocell.h" @@ -57,6 +58,8 @@ gnc_register_init (void) gnc_register_add_cell_type (RECN_CELL_TYPE_NAME, gnc_recn_cell_new); + gnc_register_add_cell_type (ASSOC_CELL_TYPE_NAME, gnc_assoc_cell_new); + gnc_register_add_cell_type (QUICKFILL_CELL_TYPE_NAME, gnc_quickfill_cell_new); diff --git a/gnucash/register/register-core/register-common.h b/gnucash/register/register-core/register-common.h index 6d1990a18c..0d6ca83e5f 100644 --- a/gnucash/register/register-core/register-common.h +++ b/gnucash/register/register-core/register-common.h @@ -67,6 +67,7 @@ #define NUM_CELL_TYPE_NAME "num-cell" #define PRICE_CELL_TYPE_NAME "price-cell" #define RECN_CELL_TYPE_NAME "recn-cell" +#define ASSOC_CELL_TYPE_NAME "assoc-cell" #define QUICKFILL_CELL_TYPE_NAME "quickfill-cell" #define FORMULA_CELL_TYPE_NAME "formula-cell" #define CHECKBOX_CELL_TYPE_NAME "checkbox-cell" diff --git a/libgnucash/app-utils/gnc-ui-util.c b/libgnucash/app-utils/gnc-ui-util.c index 1091478d53..5b66feb024 100644 --- a/libgnucash/app-utils/gnc-ui-util.c +++ b/libgnucash/app-utils/gnc-ui-util.c @@ -902,6 +902,36 @@ gnc_get_reconcile_flag_order (void) return flags; } +const char * +gnc_get_association_str (char association_flag) +{ + switch (association_flag) + { + case WASSOC: + return C_("Association flag for 'web'", "w"); + case FASSOC: + return C_("Association flag for 'file'", "f"); + case ' ': + return " "; + default: + PERR("Bad association flag"); + return NULL; + } +} + +const char * +gnc_get_association_valid_flags (void) +{ + static const char flags[] = { FASSOC, WASSOC, ' ', 0 }; + return flags; +} + +const char * +gnc_get_association_flag_order (void) +{ + static const char flags[] = { FASSOC, WASSOC, ' ', 0 }; + return flags; +} static const char * equity_base_name (GNCEquityType equity_type) @@ -1522,7 +1552,7 @@ PrintAmountInternal(char *buf, gnc_numeric val, const GNCPrintAmountInfo *info) } min_dp = info->min_decimal_places; max_dp = info->max_decimal_places; - + /* Don to limit the number of decimal places _UNLESS_ force_fit is * true. */ if (!info->force_fit) diff --git a/libgnucash/app-utils/gnc-ui-util.h b/libgnucash/app-utils/gnc-ui-util.h index 48ca85b521..ccc0e3a014 100644 --- a/libgnucash/app-utils/gnc-ui-util.h +++ b/libgnucash/app-utils/gnc-ui-util.h @@ -189,6 +189,29 @@ const char * gnc_get_reconcile_str (char reconciled_flag); const char * gnc_get_reconcile_valid_flags (void); const char * gnc_get_reconcile_flag_order (void); +#define WASSOC 'w' +#define FASSOC 'f' + +/** Get a string containing association valid flags + * + * @return a string containing the list of associated flags + */ +const char *gnc_get_association_valid_flags (void); + +/** Get a string containing association flag order + * + * @return a string containing the association flag change order + */ +const char *gnc_get_association_flag_order (void); + +/** Get a string representing the association type + * + * @param association_flag The flag to convert into a string + * + * @return the i18n'd association string + */ +const char *gnc_get_association_str (char association_flag); + typedef enum { EQUITY_OPENING_BALANCE, diff --git a/po/POTFILES.in b/po/POTFILES.in index 881c4f03af..62acd2cc83 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -396,6 +396,7 @@ gnucash/register/ledger-core/split-register-load.c gnucash/register/ledger-core/split-register-model.c gnucash/register/ledger-core/split-register-model-save.c gnucash/register/ledger-core/split-register-util.c +gnucash/register/register-core/assoccell.c gnucash/register/register-core/basiccell.c gnucash/register/register-core/cellblock.c gnucash/register/register-core/cell-factory.c