mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Merge Bob Fewell's 'revised-reg-desc' into stable.
This commit is contained in:
commit
6d60c11252
@ -677,7 +677,7 @@ gnc_split_register_layout_add_cells (SplitRegister* reg,
|
||||
|
||||
gnc_register_add_cell (layout,
|
||||
DESC_CELL,
|
||||
COMBO_CELL_TYPE_NAME,
|
||||
COMPLETION_CELL_TYPE_NAME,
|
||||
C_ ("sample", "Description of a transaction"),
|
||||
CELL_ALIGN_LEFT,
|
||||
TRUE,
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "Transaction.h"
|
||||
#include "account-quickfill.h"
|
||||
#include "combocell.h"
|
||||
#include "completioncell.h"
|
||||
#include "gnc-component-manager.h"
|
||||
#include "qof.h"
|
||||
#include "gnc-ui-util.h"
|
||||
@ -54,7 +55,6 @@ static QofLogModule log_module = GNC_MOD_LEDGER;
|
||||
static void gnc_split_register_load_xfer_cells (SplitRegister* reg,
|
||||
Account* base_account);
|
||||
|
||||
static void gnc_split_register_load_desc_cells (SplitRegister* reg);
|
||||
static void
|
||||
gnc_split_register_load_recn_cells (SplitRegister* reg)
|
||||
{
|
||||
@ -113,6 +113,21 @@ gnc_split_register_load_type_cells (SplitRegister* reg)
|
||||
gnc_recn_cell_set_read_only (cell, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_split_register_load_desc_cells (SplitRegister* reg)
|
||||
{
|
||||
CompletionCell *cell;
|
||||
|
||||
if (!reg) return;
|
||||
|
||||
cell = (CompletionCell *)
|
||||
gnc_table_layout_get_cell (reg->table->layout, DESC_CELL);
|
||||
|
||||
if (!cell) return;
|
||||
|
||||
gnc_completion_cell_set_sort_enabled (cell, TRUE);
|
||||
}
|
||||
|
||||
/** Add a transaction to the register.
|
||||
*
|
||||
* Virtual cells are set up to hold the data, beginning at @a vcell_loc and
|
||||
@ -609,6 +624,13 @@ gnc_split_register_load (SplitRegister* reg, GList* slist,
|
||||
added_blank_trans = TRUE;
|
||||
}
|
||||
|
||||
gnc_completion_cell_clear_menu (
|
||||
(CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL));
|
||||
|
||||
gnc_completion_cell_reverse_sort (
|
||||
(CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL),
|
||||
table->model->reverse_sort);
|
||||
|
||||
/* populate the table */
|
||||
for (node = slist; node; node = node->next)
|
||||
{
|
||||
@ -729,10 +751,11 @@ gnc_split_register_load (SplitRegister* reg, GList* slist,
|
||||
if (info->first_pass)
|
||||
add_quickfill_completions (reg->table->layout, trans, split, has_last_num);
|
||||
|
||||
gnc_combo_cell_add_menu_item_unique (
|
||||
(ComboCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL),
|
||||
gnc_completion_cell_add_menu_item (
|
||||
(CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL),
|
||||
xaccTransGetDescription (trans));
|
||||
|
||||
|
||||
if (trans == find_trans)
|
||||
new_trans_row = vcell_loc.virt_row;
|
||||
|
||||
@ -936,17 +959,4 @@ gnc_split_register_load_xfer_cells (SplitRegister* reg, Account* base_account)
|
||||
gnc_combo_cell_use_list_store_cache (cell, store);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_split_register_load_desc_cells (SplitRegister* reg)
|
||||
{
|
||||
ComboCell* cell;
|
||||
GtkListStore* store = gtk_list_store_new (1, G_TYPE_STRING);
|
||||
|
||||
cell = (ComboCell*)
|
||||
gnc_table_layout_get_cell (reg->table->layout, DESC_CELL);
|
||||
|
||||
gnc_combo_cell_use_type_ahead_only (cell);
|
||||
|
||||
gnc_combo_cell_use_list_store_cache (cell, store);
|
||||
}
|
||||
/* ====================== END OF FILE ================================== */
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "combocell.h"
|
||||
#include "completioncell.h"
|
||||
#include "datecell.h"
|
||||
#include "dialog-utils.h"
|
||||
#include "gnc-component-manager.h"
|
||||
@ -2666,8 +2667,8 @@ gnc_split_register_config_cells (SplitRegister* reg)
|
||||
gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL), TRUE);
|
||||
|
||||
/* the description cell */
|
||||
gnc_combo_cell_set_autosize
|
||||
((ComboCell*)
|
||||
gnc_completion_cell_set_autosize
|
||||
((CompletionCell*)
|
||||
gnc_table_layout_get_cell (reg->table->layout, DESC_CELL), TRUE);
|
||||
|
||||
/* Use GNC_COMMODITY_MAX_FRACTION for prices and "exchange rates" */
|
||||
@ -2698,8 +2699,8 @@ gnc_split_register_config_cells (SplitRegister* reg)
|
||||
gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL), FALSE);
|
||||
|
||||
/* The description cell should accept strings not in the list */
|
||||
gnc_combo_cell_set_strict
|
||||
((ComboCell*)
|
||||
gnc_completion_cell_set_strict
|
||||
((CompletionCell*)
|
||||
gnc_table_layout_get_cell (reg->table->layout, DESC_CELL), FALSE);
|
||||
|
||||
/* number format for share quantities in stock ledgers */
|
||||
|
@ -24,6 +24,7 @@ set (register_core_HEADERS
|
||||
cell-factory.h
|
||||
cellblock.h
|
||||
combocell.h
|
||||
completioncell.h
|
||||
datecell.h
|
||||
formulacell.h
|
||||
gtable.h
|
||||
|
@ -63,10 +63,6 @@ void gnc_combo_cell_clear_menu (ComboCell* cell);
|
||||
void gnc_combo_cell_add_menu_item (ComboCell* cell,
|
||||
const char* menustr);
|
||||
|
||||
/** Add a unique menu item to the list. */
|
||||
void gnc_combo_cell_add_menu_item_unique (ComboCell* cell,
|
||||
const char* menustr);
|
||||
|
||||
/** Add a 'account name' menu item to the list. When testing for
|
||||
* equality with the currently selected item, this function will
|
||||
* ignore the characters normally used to separate account names. */
|
||||
@ -108,9 +104,5 @@ void gnc_combo_cell_use_quickfill_cache (ComboCell* cell,
|
||||
QuickFill* shared_qf);
|
||||
void gnc_combo_cell_use_list_store_cache (ComboCell* cell, gpointer data);
|
||||
|
||||
/** Set the combocell to use only type ahead search. This will make the
|
||||
* search to be more like a modified entry completion. */
|
||||
void gnc_combo_cell_use_type_ahead_only (ComboCell* cell);
|
||||
|
||||
/** @} */
|
||||
#endif
|
||||
|
79
gnucash/register/register-core/completioncell.h
Normal file
79
gnucash/register/register-core/completioncell.h
Normal file
@ -0,0 +1,79 @@
|
||||
/********************************************************************\
|
||||
* completion.h -- combo-box used for completion 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 completion.h
|
||||
* @struct CompletionCell
|
||||
* @brief The CompletionCell object implements a cell handler with a
|
||||
* "combination-box" pull-down menu in it.
|
||||
*
|
||||
* On output, the currently selected menu item is displayed.
|
||||
* On input, the user can select from a list in the pull-down menu,
|
||||
* or use the keyboard to select a menu entry by typing the first
|
||||
* few menu characters.
|
||||
*
|
||||
* @author Copyright (c) 2023 Robert Fewell
|
||||
*/
|
||||
|
||||
#ifndef COMPLETION_CELL_H
|
||||
#define COMPLETION_CELL_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "basiccell.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BasicCell cell;
|
||||
} CompletionCell;
|
||||
|
||||
|
||||
BasicCell * gnc_completion_cell_new (void);
|
||||
void gnc_completion_cell_init (CompletionCell* cell);
|
||||
|
||||
void gnc_completion_cell_set_value (CompletionCell* cell, const char* value);
|
||||
|
||||
void gnc_completion_cell_clear_menu (CompletionCell* cell);
|
||||
|
||||
/** Add a menu item to the hash table list. */
|
||||
void gnc_completion_cell_add_menu_item (CompletionCell* cell,
|
||||
const char* menustr);
|
||||
|
||||
/** Enable sorting of the menu item's contents. */
|
||||
void gnc_completion_cell_set_sort_enabled (CompletionCell* cell,
|
||||
gboolean enabled);
|
||||
|
||||
/** Determines whether the cell will accept strings not in the
|
||||
* menu. Defaults to strict, i.e., only menu items are accepted. */
|
||||
void gnc_completion_cell_set_strict (CompletionCell* cell, gboolean strict);
|
||||
|
||||
/** Determines whether the popup list autosizes itself or uses
|
||||
* all available space. FALSE by default. */
|
||||
void gnc_completion_cell_set_autosize (CompletionCell* cell, gboolean autosize);
|
||||
|
||||
/** Register the sort direction. Used to determine in what order the completion should
|
||||
* present the list. FALSE by default */
|
||||
void gnc_completion_cell_reverse_sort (CompletionCell* cell, gboolean is_reversed);
|
||||
|
||||
/** @} */
|
||||
#endif
|
@ -27,6 +27,7 @@
|
||||
#include "basiccell.h"
|
||||
#include "cell-factory.h"
|
||||
#include "combocell.h"
|
||||
#include "completioncell.h"
|
||||
#include "datecell.h"
|
||||
#include "formulacell.h"
|
||||
#include "numcell.h"
|
||||
|
@ -71,6 +71,7 @@
|
||||
#define QUICKFILL_CELL_TYPE_NAME "quickfill-cell"
|
||||
#define FORMULA_CELL_TYPE_NAME "formula-cell"
|
||||
#define CHECKBOX_CELL_TYPE_NAME "checkbox-cell"
|
||||
#define COMPLETION_CELL_TYPE_NAME "completion-cell"
|
||||
|
||||
void gnc_register_init (void);
|
||||
void gnc_register_shutdown (void);
|
||||
|
@ -2,6 +2,7 @@ include(CheckSymbolExists)
|
||||
|
||||
set (register_gnome_SOURCES
|
||||
combocell-gnome.c
|
||||
completioncell-gnome.c
|
||||
datecell-gnome.c
|
||||
formulacell-gnome.c
|
||||
gnucash-color.c
|
||||
|
@ -75,9 +75,6 @@ typedef struct _PopBox
|
||||
|
||||
GList* ignore_strings;
|
||||
|
||||
GHashTable *item_hash;
|
||||
|
||||
gboolean use_type_ahead_only;
|
||||
} PopBox;
|
||||
|
||||
|
||||
@ -168,10 +165,6 @@ gnc_combo_cell_init (ComboCell* cell)
|
||||
box->complete_char = '\0';
|
||||
|
||||
box->ignore_strings = NULL;
|
||||
|
||||
box->item_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
box->use_type_ahead_only = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -340,9 +333,6 @@ gnc_combo_cell_destroy (BasicCell* bcell)
|
||||
box->qf = NULL;
|
||||
}
|
||||
|
||||
if (box->item_hash)
|
||||
g_hash_table_destroy (box->item_hash);
|
||||
|
||||
g_list_free_full (box->ignore_strings, g_free);
|
||||
box->ignore_strings = NULL;
|
||||
|
||||
@ -367,7 +357,7 @@ gnc_combo_cell_set_sort_enabled (ComboCell* cell, gboolean enabled)
|
||||
return;
|
||||
|
||||
block_list_signals (cell);
|
||||
gnc_item_list_set_sort_enabled (box->item_list, enabled);
|
||||
gnc_item_list_set_sort_column (box->item_list, 0);
|
||||
unblock_list_signals (cell);
|
||||
}
|
||||
|
||||
@ -468,70 +458,6 @@ gnc_combo_cell_add_menu_item (ComboCell* cell, const char* menustr)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gnc_combo_cell_add_menu_item_unique (ComboCell* cell, const char* menustr)
|
||||
{
|
||||
PopBox* box;
|
||||
|
||||
if (cell == NULL)
|
||||
return;
|
||||
if (menustr == NULL)
|
||||
return;
|
||||
|
||||
box = cell->cell.gui_private;
|
||||
|
||||
if (box->item_list != NULL)
|
||||
{
|
||||
block_list_signals (cell);
|
||||
|
||||
/* check if menustr has already been added. */
|
||||
if (g_hash_table_lookup_extended (box->item_hash, menustr, NULL, NULL))
|
||||
return;
|
||||
|
||||
g_hash_table_insert (box->item_hash, g_strdup (menustr), NULL);
|
||||
|
||||
gchar *menustr_temp = g_strdup (menustr);
|
||||
gnc_utf8_strip_invalid_and_controls (menustr_temp);
|
||||
gnc_item_list_append (box->item_list, menustr_temp);
|
||||
if (cell->cell.value &&
|
||||
(strcmp (menustr_temp, cell->cell.value) == 0))
|
||||
gnc_item_list_select (box->item_list, menustr_temp);
|
||||
g_free (menustr_temp);
|
||||
unblock_list_signals (cell);
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
|
||||
// add a blank entry as the first entry in store
|
||||
if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL(cell->shared_store), NULL) == 0)
|
||||
{
|
||||
gtk_list_store_append (cell->shared_store, &iter);
|
||||
gtk_list_store_set (cell->shared_store, &iter, 0, "", -1);
|
||||
g_hash_table_insert (box->item_hash, g_strdup (""), NULL);
|
||||
}
|
||||
|
||||
/* check if menustr has already been added. */
|
||||
if (g_hash_table_lookup_extended (box->item_hash, menustr, NULL, NULL))
|
||||
return;
|
||||
|
||||
g_hash_table_insert (box->item_hash, g_strdup (menustr), NULL);
|
||||
|
||||
gchar *menustr_temp = g_strdup (menustr);
|
||||
gnc_utf8_strip_invalid_and_controls (menustr_temp);
|
||||
gtk_list_store_append (cell->shared_store, &iter);
|
||||
gtk_list_store_set (cell->shared_store, &iter, 0, menustr_temp, -1);
|
||||
g_free (menustr_temp);
|
||||
}
|
||||
|
||||
/* If we're going to be using a pre-fab quickfill,
|
||||
* then don't fill it in here */
|
||||
if (FALSE == box->use_quickfill_cache)
|
||||
{
|
||||
gnc_quickfill_insert (box->qf, menustr, QUICKFILL_ALPHA);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gnc_combo_cell_add_account_menu_item (ComboCell* cell, char* menustr)
|
||||
{
|
||||
@ -713,7 +639,6 @@ gnc_combo_cell_modify_verify (BasicCell* _cell,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!box->use_type_ahead_only) // Do we only want to use type-ahead
|
||||
match_str = quickfill_match (box->qf, newval);
|
||||
|
||||
if (match_str != NULL) // Do we have a quickfill match
|
||||
@ -937,19 +862,6 @@ gnc_combo_cell_direct_update (BasicCell* bcell,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_combo_cell_use_type_ahead_only (ComboCell* cell)
|
||||
{
|
||||
PopBox* box;
|
||||
|
||||
if (cell == NULL) return;
|
||||
|
||||
box = cell->cell.gui_private;
|
||||
|
||||
box->use_type_ahead_only = TRUE;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_combo_cell_gui_realize (BasicCell* bcell, gpointer data)
|
||||
{
|
||||
|
960
gnucash/register/register-gnome/completioncell-gnome.c
Normal file
960
gnucash/register/register-gnome/completioncell-gnome.c
Normal file
@ -0,0 +1,960 @@
|
||||
/********************************************************************\
|
||||
* completioncell-gnome.c -- completion combobox cell for gnome *
|
||||
* *
|
||||
* 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: completioncell-gnome.c
|
||||
*
|
||||
* FUNCTION: Implement gnome portion of a entry completion combo widget
|
||||
* embedded in a table cell.
|
||||
*
|
||||
* HISTORY:
|
||||
* @author Copyright (c) 2023 Robert Fewell
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include "completioncell.h"
|
||||
#include "gnc-prefs.h"
|
||||
#include "gnucash-item-edit.h"
|
||||
#include "gnucash-item-list.h"
|
||||
#include "gnucash-sheet.h"
|
||||
#include "gnucash-sheetP.h"
|
||||
#include "table-allgui.h"
|
||||
#include "gnc-glib-utils.h"
|
||||
|
||||
typedef struct _PopBox
|
||||
{
|
||||
GnucashSheet* sheet;
|
||||
GncItemEdit* item_edit;
|
||||
GncItemList* item_list;
|
||||
|
||||
GHashTable* item_hash; // the item hash table
|
||||
GtkListStore* item_store; // the item list store
|
||||
|
||||
gchar* newval; // string value to find
|
||||
|
||||
gboolean signals_connected; // list signals connected
|
||||
gboolean list_popped; // list is popped up
|
||||
|
||||
gboolean autosize; // autosize the popup width
|
||||
|
||||
gboolean sort_enabled; // sort of list store enabled
|
||||
gboolean register_is_reversed; // whether the register is reversed
|
||||
gboolean stop_searching; // set when there are no results
|
||||
|
||||
gboolean strict; // text entry must be in the list
|
||||
gboolean in_list_select; // item selected in the list
|
||||
|
||||
gint occurrence; // the position in the list
|
||||
|
||||
} PopBox;
|
||||
|
||||
#define DONT_TEXT N_("Don't autocomplete")
|
||||
|
||||
/** Enumeration for the list-store */
|
||||
enum GncCompletionColumn
|
||||
{
|
||||
TEXT_COL, //0
|
||||
TEXT_MARKUP_COL, //1
|
||||
WEIGHT_COL, //2
|
||||
};
|
||||
|
||||
static void gnc_completion_cell_gui_realize (BasicCell* bcell, gpointer w);
|
||||
static void gnc_completion_cell_gui_move (BasicCell* bcell);
|
||||
static void gnc_completion_cell_gui_destroy (BasicCell* bcell);
|
||||
static gboolean gnc_completion_cell_enter (BasicCell* bcell,
|
||||
int* cursor_position,
|
||||
int* start_selection,
|
||||
int* end_selection);
|
||||
static void gnc_completion_cell_leave (BasicCell* bcell);
|
||||
static void gnc_completion_cell_destroy (BasicCell* bcell);
|
||||
|
||||
BasicCell*
|
||||
gnc_completion_cell_new (void)
|
||||
{
|
||||
CompletionCell* cell = g_new0 (CompletionCell, 1);
|
||||
gnc_completion_cell_init (cell);
|
||||
return &cell->cell;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_completion_cell_init (CompletionCell* cell)
|
||||
{
|
||||
gnc_basic_cell_init (& (cell->cell));
|
||||
|
||||
cell->cell.is_popup = TRUE;
|
||||
|
||||
cell->cell.destroy = gnc_completion_cell_destroy;
|
||||
|
||||
cell->cell.gui_realize = gnc_completion_cell_gui_realize;
|
||||
cell->cell.gui_destroy = gnc_completion_cell_gui_destroy;
|
||||
|
||||
PopBox* box = g_new0 (PopBox, 1);
|
||||
|
||||
box->sheet = NULL;
|
||||
box->item_edit = NULL;
|
||||
box->item_list = NULL;
|
||||
box->item_store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING,
|
||||
G_TYPE_INT);
|
||||
box->signals_connected = FALSE;
|
||||
box->list_popped = FALSE;
|
||||
box->autosize = FALSE;
|
||||
box->register_is_reversed = FALSE;
|
||||
|
||||
box->sort_enabled = FALSE;
|
||||
|
||||
cell->cell.gui_private = box;
|
||||
|
||||
box->stop_searching = FALSE;
|
||||
|
||||
box->strict = FALSE;
|
||||
box->in_list_select = FALSE;
|
||||
box->occurrence = 0;
|
||||
|
||||
box->item_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
hide_popup (PopBox* box)
|
||||
{
|
||||
gnc_item_edit_hide_popup (box->item_edit);
|
||||
box->list_popped = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
select_item_cb (GncItemList* item_list, char* item_string, gpointer user_data)
|
||||
{
|
||||
CompletionCell* cell = user_data;
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
box->in_list_select = TRUE;
|
||||
gnucash_sheet_modify_current_cell (box->sheet, item_string);
|
||||
box->in_list_select = FALSE;
|
||||
|
||||
hide_popup (box);
|
||||
}
|
||||
|
||||
static void
|
||||
change_item_cb (GncItemList* item_list, char* item_string, gpointer user_data)
|
||||
{
|
||||
CompletionCell* cell = user_data;
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
box->in_list_select = TRUE;
|
||||
gnucash_sheet_modify_current_cell (box->sheet, item_string);
|
||||
box->in_list_select = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
activate_item_cb (GncItemList* item_list, char* item_string, gpointer user_data)
|
||||
{
|
||||
CompletionCell* cell = user_data;
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
hide_popup (box);
|
||||
}
|
||||
|
||||
static void
|
||||
block_list_signals (CompletionCell* cell)
|
||||
{
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
if (!box->signals_connected)
|
||||
return;
|
||||
|
||||
g_signal_handlers_block_matched (G_OBJECT(box->item_list),
|
||||
G_SIGNAL_MATCH_DATA,
|
||||
0, 0, NULL, NULL, cell);
|
||||
}
|
||||
|
||||
static void
|
||||
unblock_list_signals (CompletionCell* cell)
|
||||
{
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
if (!box->signals_connected)
|
||||
return;
|
||||
|
||||
g_signal_handlers_unblock_matched (G_OBJECT(box->item_list),
|
||||
G_SIGNAL_MATCH_DATA,
|
||||
0, 0, NULL, NULL, cell);
|
||||
}
|
||||
|
||||
static void
|
||||
key_press_item_cb (GncItemList* item_list, GdkEventKey* event, gpointer user_data)
|
||||
{
|
||||
CompletionCell* cell = user_data;
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
switch (event->keyval)
|
||||
{
|
||||
case GDK_KEY_Escape:
|
||||
block_list_signals (cell); // Prevent recursion, unselect all
|
||||
gnc_item_list_select (box->item_list, NULL);
|
||||
unblock_list_signals (cell);
|
||||
hide_popup (box);
|
||||
break;
|
||||
|
||||
default:
|
||||
gtk_widget_event (GTK_WIDGET (box->sheet),
|
||||
(GdkEvent*) event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
completion_disconnect_signals (CompletionCell* cell)
|
||||
{
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
if (!box->signals_connected)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_matched (G_OBJECT(box->item_list),
|
||||
G_SIGNAL_MATCH_DATA,
|
||||
0, 0, NULL, NULL, cell);
|
||||
|
||||
box->signals_connected = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
completion_connect_signals (CompletionCell* cell)
|
||||
{
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
if (box->signals_connected)
|
||||
return;
|
||||
|
||||
g_signal_connect (G_OBJECT(box->item_list), "select_item",
|
||||
G_CALLBACK(select_item_cb), cell);
|
||||
|
||||
g_signal_connect (G_OBJECT(box->item_list), "change_item",
|
||||
G_CALLBACK(change_item_cb), cell);
|
||||
|
||||
g_signal_connect (G_OBJECT(box->item_list), "activate_item",
|
||||
G_CALLBACK(activate_item_cb), cell);
|
||||
|
||||
g_signal_connect (G_OBJECT(box->item_list), "key_press_event",
|
||||
G_CALLBACK(key_press_item_cb), cell);
|
||||
|
||||
box->signals_connected = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_completion_cell_gui_destroy (BasicCell* bcell)
|
||||
{
|
||||
CompletionCell* cell = (CompletionCell*) bcell;
|
||||
|
||||
if (cell->cell.gui_realize)
|
||||
{
|
||||
PopBox* box = bcell->gui_private;
|
||||
if (box && box->item_list)
|
||||
{
|
||||
completion_disconnect_signals (cell);
|
||||
g_object_unref (box->item_list);
|
||||
box->item_list = NULL;
|
||||
}
|
||||
/* allow the widget to be shown again */
|
||||
cell->cell.gui_realize = gnc_completion_cell_gui_realize;
|
||||
cell->cell.gui_move = NULL;
|
||||
cell->cell.enter_cell = NULL;
|
||||
cell->cell.leave_cell = NULL;
|
||||
cell->cell.gui_destroy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_completion_cell_destroy (BasicCell* bcell)
|
||||
{
|
||||
CompletionCell* cell = (CompletionCell*) bcell;
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
gnc_completion_cell_gui_destroy (& (cell->cell));
|
||||
|
||||
if (box)
|
||||
{
|
||||
if (box->item_hash)
|
||||
g_hash_table_destroy (box->item_hash);
|
||||
|
||||
g_free (box);
|
||||
cell->cell.gui_private = NULL;
|
||||
}
|
||||
cell->cell.gui_private = NULL;
|
||||
cell->cell.gui_realize = NULL;
|
||||
}
|
||||
|
||||
static gint
|
||||
sort_func (GtkTreeModel* model, GtkTreeIter* iter_a, GtkTreeIter* iter_b, gpointer user_data)
|
||||
{
|
||||
gint a_weight, b_weight;
|
||||
gint ret = 0;
|
||||
|
||||
gtk_tree_model_get (model, iter_a, WEIGHT_COL, &a_weight, -1);
|
||||
gtk_tree_model_get (model, iter_b, WEIGHT_COL, &b_weight, -1);
|
||||
|
||||
if (a_weight < b_weight)
|
||||
ret = -1;
|
||||
else if (a_weight > b_weight)
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_completion_cell_set_sort_enabled (CompletionCell* cell,
|
||||
gboolean enabled)
|
||||
{
|
||||
if (!cell)
|
||||
return;
|
||||
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
box->sort_enabled = enabled;
|
||||
}
|
||||
|
||||
static void
|
||||
set_sort_column_enabled (PopBox* box, gboolean enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(box->item_list->list_store),
|
||||
WEIGHT_COL, sort_func, box->item_list, NULL);
|
||||
|
||||
gnc_item_list_set_sort_column (box->item_list, WEIGHT_COL);
|
||||
}
|
||||
else
|
||||
gnc_item_list_set_sort_column (box->item_list, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID);
|
||||
}
|
||||
|
||||
static void
|
||||
item_store_clear (CompletionCell* cell)
|
||||
{
|
||||
if (!cell)
|
||||
return;
|
||||
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
// disconnect list store from tree view
|
||||
GtkListStore *store = gnc_item_list_disconnect_store (box->item_list);
|
||||
|
||||
block_list_signals (cell);
|
||||
|
||||
if (box->sort_enabled) // if sorting, disable it
|
||||
set_sort_column_enabled (box, FALSE);
|
||||
|
||||
box->stop_searching = FALSE;
|
||||
gtk_list_store_clear (box->item_store);
|
||||
|
||||
if (box->sort_enabled) // if sorting, enable it
|
||||
set_sort_column_enabled (box, TRUE);
|
||||
|
||||
unblock_list_signals (cell);
|
||||
|
||||
// reconect list store to tree view
|
||||
gnc_item_list_connect_store (box->item_list, store);
|
||||
|
||||
hide_popup (box);
|
||||
}
|
||||
|
||||
void
|
||||
gnc_completion_cell_clear_menu (CompletionCell* cell)
|
||||
{
|
||||
if (!cell)
|
||||
return;
|
||||
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
if (!box)
|
||||
return;
|
||||
|
||||
if (box->item_list)
|
||||
{
|
||||
g_hash_table_remove_all (box->item_hash);
|
||||
item_store_clear (cell);
|
||||
box->occurrence = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gnc_completion_cell_add_menu_item (CompletionCell* cell,
|
||||
const char* menustr)
|
||||
{
|
||||
if (!cell || !menustr)
|
||||
return;
|
||||
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
if (box->item_hash)
|
||||
{
|
||||
gpointer value = g_hash_table_lookup (box->item_hash, menustr);
|
||||
gboolean update = FALSE;
|
||||
if (value)
|
||||
{
|
||||
if (!box->register_is_reversed)
|
||||
update = TRUE;
|
||||
}
|
||||
else
|
||||
update = TRUE;
|
||||
|
||||
if (update)
|
||||
{
|
||||
g_hash_table_insert (box->item_hash, g_strdup (menustr),
|
||||
GINT_TO_POINTER(box->occurrence));
|
||||
}
|
||||
box->occurrence++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gnc_completion_cell_set_value (CompletionCell* cell, const char* str)
|
||||
{
|
||||
if (!cell || !str)
|
||||
|
||||
gnc_basic_cell_set_value (&cell->cell, str);
|
||||
}
|
||||
|
||||
static inline void
|
||||
list_store_append (GtkListStore *store, char* string,
|
||||
char* markup, gint weight)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
|
||||
g_return_if_fail (store);
|
||||
g_return_if_fail (string);
|
||||
g_return_if_fail (markup);
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
|
||||
gtk_list_store_set (store, &iter, TEXT_COL, string,
|
||||
TEXT_MARKUP_COL, markup,
|
||||
WEIGHT_COL, weight, -1);
|
||||
}
|
||||
|
||||
static char*
|
||||
normalize_and_fold (char* utf8_string)
|
||||
{
|
||||
char *normalized = g_utf8_normalize (utf8_string, -1, G_NORMALIZE_NFC);
|
||||
if (!normalized)
|
||||
return NULL;
|
||||
|
||||
char *folded = g_utf8_casefold (normalized, -1);
|
||||
g_free (normalized);
|
||||
return folded;
|
||||
}
|
||||
|
||||
static gint
|
||||
test_and_add (PopBox* box, const gchar *text, gint start_pos,
|
||||
gpointer key, gint occurrence_difference)
|
||||
{
|
||||
gint ret_value = -1;
|
||||
gint text_length = g_utf8_strlen (text, -1);
|
||||
|
||||
if (start_pos > text_length)
|
||||
return ret_value;
|
||||
|
||||
gchar *sub_text = g_utf8_substring (text, start_pos, text_length);
|
||||
gchar *sub_text_norm_fold = normalize_and_fold (sub_text);
|
||||
gchar *found_text_ptr = g_strstr_len (sub_text_norm_fold, -1, box->newval);
|
||||
|
||||
if (found_text_ptr)
|
||||
{
|
||||
gchar *markup = NULL, *prefix = NULL, *match = NULL, *suffix = NULL;
|
||||
glong newval_length = g_utf8_strlen (box->newval, -1);
|
||||
gulong found_location = g_utf8_pointer_to_offset (sub_text_norm_fold,
|
||||
found_text_ptr) + start_pos;
|
||||
gboolean have_boundary = FALSE;
|
||||
gint prefix_length;
|
||||
gint weight;
|
||||
|
||||
if (found_location > 0)
|
||||
prefix = g_utf8_substring (text, 0, found_location);
|
||||
else
|
||||
prefix = g_strdup ("");
|
||||
|
||||
prefix_length = g_utf8_strlen (prefix, -1);
|
||||
|
||||
match = g_utf8_substring (text, found_location, found_location + newval_length);
|
||||
|
||||
if (found_location >= 1)
|
||||
{
|
||||
gunichar prev = g_utf8_get_char (g_utf8_offset_to_pointer (sub_text, found_location - start_pos - 1));
|
||||
if (prev && (g_unichar_isspace (prev) || g_unichar_ispunct (prev)))
|
||||
have_boundary = TRUE;
|
||||
else
|
||||
ret_value = found_location + 1;
|
||||
}
|
||||
|
||||
suffix = g_utf8_substring (text, found_location + newval_length, text_length);
|
||||
|
||||
markup = g_markup_printf_escaped ("%s<b>%s</b>%s%s", prefix, match, suffix, " ");
|
||||
|
||||
if ((prefix_length == 0 ) || have_boundary)
|
||||
{
|
||||
weight = occurrence_difference; // sorted by recent first
|
||||
|
||||
if (g_strcmp0 (sub_text_norm_fold, box->newval) == 0) // exact match
|
||||
weight = 1;
|
||||
|
||||
list_store_append (box->item_store, key, markup, weight);
|
||||
}
|
||||
g_free (markup);
|
||||
g_free (prefix);
|
||||
g_free (match);
|
||||
g_free (suffix);
|
||||
}
|
||||
g_free (sub_text_norm_fold);
|
||||
g_free (sub_text);
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
static void
|
||||
add_item (gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
PopBox* box = user_data;
|
||||
gchar *hash_entry = g_strdup (key);
|
||||
|
||||
if (hash_entry && *hash_entry)
|
||||
{
|
||||
gint start_pos = 0;
|
||||
gint occurrence_difference;
|
||||
gnc_utf8_strip_invalid_and_controls (hash_entry);
|
||||
|
||||
if (box->register_is_reversed)
|
||||
occurrence_difference = GPOINTER_TO_INT(value) + 1;
|
||||
else
|
||||
occurrence_difference = box->occurrence - GPOINTER_TO_INT(value);
|
||||
|
||||
do
|
||||
{
|
||||
start_pos = test_and_add (box, hash_entry, start_pos, key, occurrence_difference);
|
||||
}
|
||||
while (start_pos != -1);
|
||||
}
|
||||
g_free (hash_entry);
|
||||
}
|
||||
|
||||
static void
|
||||
select_first_entry_in_list (PopBox* box)
|
||||
{
|
||||
GtkTreeModel *model = gtk_tree_view_get_model (box->item_list->tree_view);
|
||||
GtkTreeIter iter;
|
||||
gchar* string;
|
||||
|
||||
if (!gtk_tree_model_get_iter_first (model, &iter))
|
||||
return;
|
||||
|
||||
if (!gtk_tree_model_iter_next (model, &iter))
|
||||
return;
|
||||
|
||||
gtk_tree_model_get (model, &iter, TEXT_COL, &string, -1);
|
||||
|
||||
gnc_item_list_select (box->item_list, string);
|
||||
|
||||
GtkTreePath* path = gtk_tree_path_new_first ();
|
||||
gtk_tree_view_scroll_to_cell (box->item_list->tree_view,
|
||||
path, NULL, TRUE, 0.5, 0.0);
|
||||
gtk_tree_path_free (path);
|
||||
g_free (string);
|
||||
}
|
||||
|
||||
static void
|
||||
populate_list_store (CompletionCell* cell, const gchar* str)
|
||||
{
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
box->in_list_select = FALSE;
|
||||
|
||||
if (box->stop_searching)
|
||||
return;
|
||||
|
||||
if (str && *str)
|
||||
box->newval = normalize_and_fold ((gchar*)str);
|
||||
else
|
||||
return;
|
||||
|
||||
// disconnect list store from tree view
|
||||
box->item_store = gnc_item_list_disconnect_store (box->item_list);
|
||||
|
||||
block_list_signals (cell);
|
||||
|
||||
if (box->sort_enabled) // if sorting, disable it
|
||||
set_sort_column_enabled (box, FALSE);
|
||||
|
||||
gtk_list_store_clear (box->item_store);
|
||||
|
||||
// add the don't first entry
|
||||
gchar *markup = g_markup_printf_escaped ("<i>%s</i>", DONT_TEXT);
|
||||
list_store_append (box->item_store, DONT_TEXT, markup, 0);
|
||||
g_free (markup);
|
||||
|
||||
// add to the list store
|
||||
g_hash_table_foreach (box->item_hash, add_item, box);
|
||||
|
||||
if (box->sort_enabled) // if sorting, enable it
|
||||
set_sort_column_enabled (box, TRUE);
|
||||
|
||||
unblock_list_signals (cell);
|
||||
|
||||
// reconnect list store to tree view
|
||||
gnc_item_list_connect_store (box->item_list, box->item_store);
|
||||
|
||||
// if no entries, do not show popup
|
||||
if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL(box->item_store), NULL) == 1)
|
||||
{
|
||||
box->stop_searching = TRUE;
|
||||
hide_popup (box);
|
||||
}
|
||||
else
|
||||
gnc_item_edit_show_popup (box->item_edit);
|
||||
|
||||
block_list_signals (cell); // Prevent recursion, select first entry
|
||||
select_first_entry_in_list (box);
|
||||
unblock_list_signals (cell);
|
||||
|
||||
g_free (box->newval);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_completion_cell_modify_verify (BasicCell* bcell,
|
||||
const char* change,
|
||||
int change_len,
|
||||
const char* newval,
|
||||
int newval_len,
|
||||
int* cursor_position,
|
||||
int* start_selection,
|
||||
int* end_selection)
|
||||
{
|
||||
CompletionCell* cell = (CompletionCell*) bcell;
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
glong newval_chars = g_utf8_strlen (newval, newval_len);
|
||||
|
||||
if (box->in_list_select)
|
||||
{
|
||||
if (g_strcmp0 (newval, DONT_TEXT) == 0)
|
||||
return;
|
||||
gnc_basic_cell_set_value_internal (bcell, newval);
|
||||
*cursor_position = -1;
|
||||
*start_selection = 0;
|
||||
*end_selection = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// check to enable searching
|
||||
if (((*cursor_position < newval_chars) &&
|
||||
(g_utf8_strlen (bcell->value, -1) < newval_chars)) ||
|
||||
(g_utf8_strlen (bcell->value, -1) > newval_chars))
|
||||
{
|
||||
box->stop_searching = FALSE;
|
||||
}
|
||||
|
||||
populate_list_store (cell, newval);
|
||||
|
||||
if (g_strcmp0 (newval, "") == 0)
|
||||
{
|
||||
block_list_signals (cell); // Prevent recursion, unselect all
|
||||
gnc_item_list_select (box->item_list, NULL);
|
||||
unblock_list_signals (cell);
|
||||
hide_popup (box);
|
||||
}
|
||||
gnc_basic_cell_set_value_internal (bcell, newval);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gnc_completion_cell_direct_update (BasicCell* bcell,
|
||||
int* cursor_position,
|
||||
int* start_selection,
|
||||
int* end_selection,
|
||||
void* gui_data)
|
||||
{
|
||||
CompletionCell* cell = (CompletionCell*) bcell;
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
GdkEventKey* event = gui_data;
|
||||
|
||||
if (event->type != GDK_KEY_PRESS)
|
||||
return FALSE;
|
||||
|
||||
switch (event->keyval)
|
||||
{
|
||||
case GDK_KEY_Tab:
|
||||
case GDK_KEY_ISO_Left_Tab:
|
||||
{
|
||||
char* string = gnc_item_list_get_selection (box->item_list);
|
||||
|
||||
if (!string)
|
||||
break;
|
||||
|
||||
g_signal_emit_by_name (G_OBJECT(box->item_list), "change_item",
|
||||
string, (gpointer)bcell);
|
||||
|
||||
g_free (string);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (box->strict)
|
||||
box->in_list_select = gnc_item_in_list (box->item_list, bcell->value);
|
||||
|
||||
if (!bcell->value)
|
||||
item_store_clear (cell);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_completion_cell_reverse_sort (CompletionCell* cell, gboolean is_reversed)
|
||||
{
|
||||
if (!cell)
|
||||
return;
|
||||
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
if (is_reversed != box->register_is_reversed)
|
||||
{
|
||||
gnc_completion_cell_clear_menu (cell);
|
||||
box->register_is_reversed = is_reversed;
|
||||
box->occurrence = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_completion_cell_gui_realize (BasicCell* bcell, gpointer data)
|
||||
{
|
||||
GnucashSheet* sheet = data;
|
||||
GncItemEdit* item_edit = gnucash_sheet_get_item_edit (sheet);
|
||||
CompletionCell* cell = (CompletionCell*) bcell;
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
|
||||
/* initialize gui-specific, private data */
|
||||
box->sheet = sheet;
|
||||
box->item_edit = item_edit;
|
||||
box->item_list = GNC_ITEM_LIST(gnc_item_list_new (box->item_store));
|
||||
|
||||
block_list_signals (cell);
|
||||
set_sort_column_enabled (box, FALSE);
|
||||
unblock_list_signals (cell);
|
||||
|
||||
gtk_widget_show_all (GTK_WIDGET(box->item_list));
|
||||
g_object_ref_sink (box->item_list);
|
||||
|
||||
/* to mark cell as realized, remove the realize method */
|
||||
cell->cell.gui_realize = NULL;
|
||||
cell->cell.gui_move = gnc_completion_cell_gui_move;
|
||||
cell->cell.enter_cell = gnc_completion_cell_enter;
|
||||
cell->cell.leave_cell = gnc_completion_cell_leave;
|
||||
cell->cell.gui_destroy = gnc_completion_cell_gui_destroy;
|
||||
cell->cell.modify_verify = gnc_completion_cell_modify_verify;
|
||||
cell->cell.direct_update = gnc_completion_cell_direct_update;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_item_list_to_default_setup (BasicCell* bcell)
|
||||
{
|
||||
PopBox* box = bcell->gui_private;
|
||||
PopupToggle popup_toggle;
|
||||
|
||||
item_store_clear ((CompletionCell*) bcell);
|
||||
|
||||
popup_toggle = box->item_edit->popup_toggle;
|
||||
gtk_widget_set_sensitive (GTK_WIDGET(popup_toggle.tbutton), TRUE);
|
||||
gtk_widget_set_visible (GTK_WIDGET(popup_toggle.tbutton), TRUE);
|
||||
|
||||
GtkTreeViewColumn *column = gtk_tree_view_get_column (
|
||||
GTK_TREE_VIEW(box->item_list->tree_view), TEXT_COL);
|
||||
gtk_tree_view_column_clear_attributes (column,box->item_list->renderer);
|
||||
gtk_tree_view_column_add_attribute (column, box->item_list->renderer,
|
||||
"text", TEXT_COL);
|
||||
box->list_popped = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_completion_cell_gui_move (BasicCell* bcell)
|
||||
{
|
||||
PopBox* box = bcell->gui_private;
|
||||
|
||||
completion_disconnect_signals ((CompletionCell*) bcell);
|
||||
|
||||
gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
reset_item_list_to_default_setup (bcell);
|
||||
}
|
||||
|
||||
static int
|
||||
popup_get_height (G_GNUC_UNUSED GtkWidget* widget,
|
||||
int space_available,
|
||||
int row_height,
|
||||
gpointer user_data)
|
||||
{
|
||||
PopBox* box = user_data;
|
||||
GtkScrolledWindow* scrollwin = GNC_ITEM_LIST(widget)->scrollwin;
|
||||
GtkWidget *hsbar = gtk_scrolled_window_get_hscrollbar (scrollwin);
|
||||
GtkStyleContext *context = gtk_widget_get_style_context (hsbar);
|
||||
/* Note: gtk_scrolled_window_get_overlay_scrolling (scrollwin) always returns
|
||||
TRUE so look for style class "overlay-indicator" on the scrollbar. */
|
||||
gboolean overlay = gtk_style_context_has_class (context, "overlay-indicator");
|
||||
int count = gnc_item_list_num_entries (box->item_list);
|
||||
int height = count * (gnc_item_list_get_cell_height (box->item_list) + 2);
|
||||
|
||||
if (!overlay)
|
||||
{
|
||||
gint minh, nath;
|
||||
gtk_widget_get_preferred_height (hsbar, &minh, &nath);
|
||||
height = height + minh;
|
||||
}
|
||||
|
||||
if (height < space_available)
|
||||
{
|
||||
// if the list is empty height would be 0 so return 1 instead to
|
||||
// satisfy the check_popup_height_is_true function
|
||||
gint ret_height = height ? height : 1;
|
||||
|
||||
gtk_widget_set_size_request (GTK_WIDGET(scrollwin), -1, ret_height);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrollwin),
|
||||
GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
|
||||
return ret_height;
|
||||
}
|
||||
else
|
||||
gtk_widget_set_size_request (GTK_WIDGET(scrollwin), -1, -1);
|
||||
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrollwin),
|
||||
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
return space_available;
|
||||
}
|
||||
|
||||
static int
|
||||
popup_autosize (GtkWidget* widget,
|
||||
int max_width,
|
||||
gpointer user_data)
|
||||
{
|
||||
PopBox* box = user_data;
|
||||
|
||||
if (!box || !box->autosize)
|
||||
return max_width;
|
||||
|
||||
return gnc_item_list_autosize (GNC_ITEM_LIST(widget)) + 20;
|
||||
}
|
||||
|
||||
static void
|
||||
popup_set_focus (GtkWidget* widget,
|
||||
G_GNUC_UNUSED gpointer user_data)
|
||||
{
|
||||
/* An empty GtkTreeView grabbing focus causes the key_press events to be
|
||||
* lost because there's no entry cell to handle them.
|
||||
*/
|
||||
if (gnc_item_list_num_entries (GNC_ITEM_LIST(widget)))
|
||||
gtk_widget_grab_focus (GTK_WIDGET (GNC_ITEM_LIST(widget)->tree_view));
|
||||
}
|
||||
|
||||
static void
|
||||
popup_post_show (GtkWidget* widget,
|
||||
G_GNUC_UNUSED gpointer user_data)
|
||||
{
|
||||
gnc_item_list_autosize (GNC_ITEM_LIST(widget));
|
||||
gnc_item_list_show_selected (GNC_ITEM_LIST(widget));
|
||||
}
|
||||
|
||||
static int
|
||||
popup_get_width (GtkWidget* widget,
|
||||
G_GNUC_UNUSED gpointer user_data)
|
||||
{
|
||||
GtkAllocation alloc;
|
||||
gtk_widget_get_allocation (GTK_WIDGET (GNC_ITEM_LIST(widget)->tree_view),
|
||||
&alloc);
|
||||
return alloc.width;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gnc_completion_cell_enter (BasicCell* bcell,
|
||||
int* cursor_position,
|
||||
int* start_selection,
|
||||
int* end_selection)
|
||||
{
|
||||
CompletionCell* cell = (CompletionCell*) bcell;
|
||||
PopBox* box = bcell->gui_private;
|
||||
PopupToggle popup_toggle;
|
||||
|
||||
gnc_item_edit_set_popup (box->item_edit,
|
||||
GTK_WIDGET(box->item_list),
|
||||
popup_get_height, popup_autosize,
|
||||
popup_set_focus, popup_post_show,
|
||||
popup_get_width, box);
|
||||
|
||||
popup_toggle = box->item_edit->popup_toggle;
|
||||
gtk_widget_set_sensitive (GTK_WIDGET(popup_toggle.tbutton), FALSE);
|
||||
gtk_widget_set_visible (GTK_WIDGET(popup_toggle.tbutton), FALSE);
|
||||
|
||||
GtkTreeViewColumn *column = gtk_tree_view_get_column (
|
||||
GTK_TREE_VIEW(box->item_list->tree_view), TEXT_COL);
|
||||
gtk_tree_view_column_clear_attributes (column, box->item_list->renderer);
|
||||
gtk_tree_view_column_add_attribute (column, box->item_list->renderer,
|
||||
"markup", TEXT_MARKUP_COL);
|
||||
|
||||
completion_connect_signals (cell);
|
||||
|
||||
*cursor_position = -1;
|
||||
*start_selection = 0;
|
||||
*end_selection = -1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_completion_cell_leave (BasicCell* bcell)
|
||||
{
|
||||
PopBox* box = bcell->gui_private;
|
||||
|
||||
completion_disconnect_signals ((CompletionCell*) bcell);
|
||||
|
||||
gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
reset_item_list_to_default_setup (bcell);
|
||||
|
||||
if (box->strict && !box->in_list_select)
|
||||
gnc_basic_cell_set_value_internal (bcell, "");
|
||||
}
|
||||
|
||||
void
|
||||
gnc_completion_cell_set_strict (CompletionCell* cell, gboolean strict)
|
||||
{
|
||||
if (!cell)
|
||||
return;
|
||||
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
if (!box)
|
||||
return;
|
||||
|
||||
box->strict = strict;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_completion_cell_set_autosize (CompletionCell* cell, gboolean autosize)
|
||||
{
|
||||
if (!cell)
|
||||
return;
|
||||
|
||||
PopBox* box = cell->cell.gui_private;
|
||||
if (!box)
|
||||
return;
|
||||
|
||||
box->autosize = autosize;
|
||||
}
|
@ -98,22 +98,14 @@ gnc_item_list_append (GncItemList* item_list, const char* string)
|
||||
|
||||
|
||||
void
|
||||
gnc_item_list_set_sort_enabled (GncItemList* item_list, gboolean enabled)
|
||||
gnc_item_list_set_sort_column (GncItemList* item_list, gint column_id)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
g_return_if_fail (IS_GNC_ITEM_LIST (item_list));
|
||||
|
||||
gtk_tree_sortable_set_sort_column_id
|
||||
(GTK_TREE_SORTABLE (item_list->list_store),
|
||||
0,
|
||||
column_id,
|
||||
GTK_SORT_ASCENDING);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_tree_sortable_set_sort_column_id
|
||||
(GTK_TREE_SORTABLE (item_list->list_store),
|
||||
GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
|
||||
GTK_SORT_ASCENDING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -203,6 +195,7 @@ gnc_item_list_select (GncItemList* item_list, const char* string)
|
||||
g_free (to_find_data);
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
gnc_item_list_get_selection (GncItemList *item_list)
|
||||
{
|
||||
@ -277,6 +270,29 @@ gnc_item_list_using_temp (GncItemList *item_list)
|
||||
return item_list && item_list->temp_store;
|
||||
}
|
||||
|
||||
GtkListStore *
|
||||
gnc_item_list_disconnect_store (GncItemList *item_list)
|
||||
{
|
||||
GtkListStore *store;
|
||||
|
||||
g_return_val_if_fail (item_list != NULL, NULL);
|
||||
|
||||
store = GTK_LIST_STORE(gtk_tree_view_get_model (item_list->tree_view));
|
||||
|
||||
gtk_tree_view_set_model (item_list->tree_view, NULL);
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_item_list_connect_store (GncItemList *item_list, GtkListStore *list_store)
|
||||
{
|
||||
g_return_if_fail (item_list != 0);
|
||||
|
||||
gtk_tree_view_set_model (item_list->tree_view,
|
||||
GTK_TREE_MODEL (list_store));
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_item_list_init (GncItemList* item_list)
|
||||
{
|
||||
@ -493,8 +509,8 @@ gnc_item_list_new (GtkListStore* list_store)
|
||||
g_object_unref (list_store);
|
||||
|
||||
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
|
||||
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (
|
||||
tree_view)),
|
||||
gtk_tree_selection_set_mode (
|
||||
gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)),
|
||||
GTK_SELECTION_BROWSE);
|
||||
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
|
||||
0, GTK_SORT_ASCENDING);
|
||||
|
@ -77,7 +77,7 @@ void gnc_item_list_clear (GncItemList *item_list);
|
||||
|
||||
void gnc_item_list_append (GncItemList *item_list, const char *string);
|
||||
|
||||
void gnc_item_list_set_sort_enabled(GncItemList *item_list, gboolean enabled);
|
||||
void gnc_item_list_set_sort_column (GncItemList *item_list, gint column_id);
|
||||
|
||||
gboolean gnc_item_in_list (GncItemList *item_list, const char *string);
|
||||
|
||||
@ -98,5 +98,9 @@ void gnc_item_list_set_temp_store (GncItemList *item_list, GtkListStore *store);
|
||||
|
||||
gboolean gnc_item_list_using_temp (GncItemList *item_list);
|
||||
|
||||
GtkListStore * gnc_item_list_disconnect_store (GncItemList *item_list);
|
||||
|
||||
void gnc_item_list_connect_store (GncItemList *item_list, GtkListStore *store);
|
||||
|
||||
/** @} */
|
||||
#endif /* GNUCASH_ITEM_LIST_H */
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "gnc-state.h"
|
||||
|
||||
#include "combocell.h"
|
||||
#include "completioncell.h"
|
||||
#include "datecell.h"
|
||||
#include "formulacell-gnome.h"
|
||||
#include "pricecell-gnome.h"
|
||||
@ -100,6 +101,7 @@ void
|
||||
gnucash_register_add_cell_types (void)
|
||||
{
|
||||
gnc_register_add_cell_type (COMBO_CELL_TYPE_NAME, gnc_combo_cell_new);
|
||||
gnc_register_add_cell_type (COMPLETION_CELL_TYPE_NAME, gnc_completion_cell_new);
|
||||
gnc_register_add_cell_type (DATE_CELL_TYPE_NAME, gnc_date_cell_new);
|
||||
gnc_register_add_cell_type (PRICE_CELL_TYPE_NAME,
|
||||
gnc_price_cell_gnome_new);
|
||||
|
Loading…
Reference in New Issue
Block a user