diff -r 64aabebb476b -r e7bed293aad5 finch/libgnt/gnttree.c --- a/finch/libgnt/gnttree.c Thu Nov 15 14:32:09 2018 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1991 +0,0 @@ -/* - * GNT - The GLib Ncurses Toolkit - * - * GNT is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This library 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "gntinternal.h" -#include "gntstyle.h" -#include "gnttree.h" -#include "gntutils.h" - -#include -#include - -#define SEARCH_TIMEOUT_S 4 /* 4 secs */ -#define SEARCHING(tree) (tree->priv->search && tree->priv->search->len > 0) - -#define COLUMN_INVISIBLE(tree, index) (tree->columns[index].flags & GNT_TREE_COLUMN_INVISIBLE) -#define BINARY_DATA(tree, index) (tree->columns[index].flags & GNT_TREE_COLUMN_BINARY_DATA) -#define RIGHT_ALIGNED(tree, index) (tree->columns[index].flags & GNT_TREE_COLUMN_RIGHT_ALIGNED) - -enum -{ - PROP_0, - PROP_COLUMNS, - PROP_EXPANDER, -}; - -enum -{ - SIG_SELECTION_CHANGED, - SIG_SCROLLED, - SIG_TOGGLED, - SIG_COLLAPSED, - SIGS, -}; - -struct _GntTreePriv -{ - GString *search; - int search_timeout; - int search_column; - gboolean (*search_func)(GntTree *tree, gpointer key, const char *search, const char *current); - - GCompareFunc compare; - int lastvisible; - int expander_level; -}; - -#define TAB_SIZE 3 - -/* XXX: Make this one into a GObject? - * ... Probably not */ -struct _GntTreeRow -{ - int box_count; - - void *key; - void *data; /* XXX: unused */ - - gboolean collapsed; - gboolean choice; /* Is this a choice-box? - If choice is true, then child will be NULL */ - gboolean isselected; - GntTextFormatFlags flags; - int color; - - GntTreeRow *parent; - GntTreeRow *child; - GntTreeRow *next; - GntTreeRow *prev; - - GList *columns; - GntTree *tree; -}; - -struct _GntTreeCol -{ - char *text; - gboolean isbinary; - int span; /* How many columns does it span? */ -}; - -static void tree_selection_changed(GntTree *, GntTreeRow *, GntTreeRow *); -static void _gnt_tree_init_internals(GntTree *tree, int col); - -static GntWidgetClass *parent_class = NULL; -static guint signals[SIGS] = { 0 }; - -static void -readjust_columns(GntTree *tree) -{ - int i, col, total; - int width; -#define WIDTH(i) (tree->columns[i].width_ratio ? tree->columns[i].width_ratio : tree->columns[i].width) - gnt_widget_get_size(GNT_WIDGET(tree), &width, NULL); - if (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER)) - width -= 2; - width -= 1; /* Exclude the scrollbar from the calculation */ - for (i = 0, total = 0; i < tree->ncol ; i++) { - if (tree->columns[i].flags & GNT_TREE_COLUMN_INVISIBLE) - continue; - if (tree->columns[i].flags & GNT_TREE_COLUMN_FIXED_SIZE) - width -= WIDTH(i) + (tree->priv->lastvisible != i); - else - total += WIDTH(i) + (tree->priv->lastvisible != i); - } - - if (total == 0) - return; - - for (i = 0; i < tree->ncol; i++) { - if (tree->columns[i].flags & GNT_TREE_COLUMN_INVISIBLE) - continue; - if (tree->columns[i].flags & GNT_TREE_COLUMN_FIXED_SIZE) - col = WIDTH(i); - else - col = (WIDTH(i) * width) / total; - gnt_tree_set_col_width(GNT_TREE(tree), i, col); - } -} - -/* Move the item at position old to position new */ -static GList * -g_list_reposition_child(GList *list, int old, int new) -{ - gpointer item = g_list_nth_data(list, old); - list = g_list_remove(list, item); - if (old < new) - new--; /* because the positions would have shifted after removing the item */ - list = g_list_insert(list, item, new); - return list; -} - -static GntTreeRow * -_get_next(GntTreeRow *row, gboolean godeep) -{ - if (row == NULL) - return NULL; - if (godeep && row->child) - return row->child; - if (row->next) - return row->next; - return _get_next(row->parent, FALSE); -} - -static gboolean -row_matches_search(GntTreeRow *row) -{ - GntTree *t = row->tree; - if (t->priv->search && t->priv->search->len > 0) { - GntTreeCol *col = (col = g_list_nth_data(row->columns, t->priv->search_column)) ? col : row->columns->data; - char *one, *two, *z; - if (t->priv->search_func) - return t->priv->search_func(t, row->key, t->priv->search->str, col->text); - one = g_utf8_casefold(col->text, -1); - two = g_utf8_casefold(t->priv->search->str, -1); - z = strstr(one, two); - g_free(one); - g_free(two); - if (z == NULL) - return FALSE; - } - return TRUE; -} - -static GntTreeRow * -get_next(GntTreeRow *row) -{ - if (row == NULL) - return NULL; - while ((row = _get_next(row, !row->collapsed)) != NULL) { - if (row_matches_search(row)) - break; - } - return row; -} - -/* Returns the n-th next row. If it doesn't exist, returns NULL */ -static GntTreeRow * -get_next_n(GntTreeRow *row, int n) -{ - while (row && n--) - row = get_next(row); - return row; -} - -/* Returns the n-th next row. If it doesn't exist, then the last non-NULL node */ -static GntTreeRow * -get_next_n_opt(GntTreeRow *row, int n, int *pos) -{ - GntTreeRow *next = row; - int r = 0; - - if (row == NULL) - return NULL; - - while (row && n--) - { - row = get_next(row); - if (row) - { - next = row; - r++; - } - } - - if (pos) - *pos = r; - - return next; -} - -static GntTreeRow * -get_last_child(GntTreeRow *row) -{ - if (row == NULL) - return NULL; - if (!row->collapsed && row->child) - row = row->child; - else - return row; - - while(row->next) - row = row->next; - return get_last_child(row); -} - -static GntTreeRow * -get_prev(GntTreeRow *row) -{ - if (row == NULL) - return NULL; - while (row) { - if (row->prev) - row = get_last_child(row->prev); - else - row = row->parent; - if (!row || row_matches_search(row)) - break; - } - return row; -} - -static GntTreeRow * -get_prev_n(GntTreeRow *row, int n) -{ - while (row && n--) - row = get_prev(row); - return row; -} - -/* Distance of row from the root */ -/* XXX: This is uber-inefficient */ -static int -get_root_distance(GntTreeRow *row) -{ - if (row == NULL) - return -1; - return get_root_distance(get_prev(row)) + 1; -} - -/* Returns the distance between a and b. - * If a is 'above' b, then the distance is positive */ -static int -get_distance(GntTreeRow *a, GntTreeRow *b) -{ - /* First get the distance from a to the root. - * Then the distance from b to the root. - * Subtract. - * It's not that good, but it works. */ - int ha = get_root_distance(a); - int hb = get_root_distance(b); - - return (hb - ha); -} - -static int -find_depth(GntTreeRow *row) -{ - int dep = -1; - - while (row) - { - dep++; - row = row->parent; - } - - return dep; -} - -static char * -update_row_text(GntTree *tree, GntTreeRow *row) -{ - GString *string = g_string_new(NULL); - GList *iter; - int i; - gboolean notfirst = FALSE; - - for (i = 0, iter = row->columns; i < tree->ncol && iter; i++, iter = iter->next) - { - GntTreeCol *col = iter->data; - const char *text; - int len; - int fl = 0; - gboolean cut = FALSE; - int width; - const char *display; - - if (COLUMN_INVISIBLE(tree, i)) - continue; - - if (BINARY_DATA(tree, i)) - display = ""; - else - display = col->text; - - len = gnt_util_onscreen_width(display, NULL); - - width = tree->columns[i].width; - - if (i == 0) - { - if (row->choice) - { - g_string_append_printf(string, "[%c] ", - row->isselected ? 'X' : ' '); - fl = 4; - } - else if (find_depth(row) < tree->priv->expander_level && row->child) - { - if (row->collapsed) - { - string = g_string_append(string, "+ "); - } - else - { - string = g_string_append(string, "- "); - } - fl = 2; - } - else - { - fl = TAB_SIZE * find_depth(row); - g_string_append_printf(string, "%*s", fl, ""); - } - len += fl; - } else if (notfirst && tree->show_separator) - g_string_append_c(string, '|'); - else - g_string_append_c(string, ' '); - - notfirst = TRUE; - - if (len > width) { - len = MAX(1, width - 1); - cut = TRUE; - } - - if (RIGHT_ALIGNED(tree, i) && len < tree->columns[i].width) { - g_string_append_printf(string, "%*s", width - len - cut, ""); - } - - text = gnt_util_onscreen_width_to_pointer(display, len - fl, NULL); - string = g_string_append_len(string, display, text - display); - if (cut && width > 1) { /* ellipsis */ - if (gnt_ascii_only()) - g_string_append_c(string, '~'); - else - string = g_string_append(string, "\342\200\246"); - len++; - } - - if (!RIGHT_ALIGNED(tree, i) && len < tree->columns[i].width && iter->next) - g_string_append_printf(string, "%*s", width - len, ""); - } - return g_string_free(string, FALSE); -} - -#define NEXT_X x += tree->columns[i].width + (i > 0 ? 1 : 0) - -static void -tree_mark_columns(GntTree *tree, int pos, int y, chtype type) -{ - GntWidget *widget = GNT_WIDGET(tree); - int i; - int x = pos; - gboolean notfirst = FALSE; - - for (i = 0; i < tree->ncol - 1; i++) - { - if (!COLUMN_INVISIBLE(tree, i)) { - notfirst = TRUE; - NEXT_X; - } - if (!COLUMN_INVISIBLE(tree, i+1) && notfirst) - mvwaddch(widget->window, y, x, type); - } -} - -static void -redraw_tree(GntTree *tree) -{ - int start, i; - GntWidget *widget = GNT_WIDGET(tree); - GntTreeRow *row; - int pos, up, down = 0; - int rows, scrcol; - int current = 0; - - if (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED)) - return; - - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - pos = 0; - else - pos = 1; - - if (tree->top == NULL) - tree->top = tree->root; - if (tree->current == NULL && tree->root != NULL) { - tree->current = tree->root; - tree_selection_changed(tree, NULL, tree->current); - } - - wbkgd(widget->window, gnt_color_pair(GNT_COLOR_NORMAL)); - - start = 0; - if (tree->show_title) - { - int i; - int x = pos; - - mvwhline(widget->window, pos + 1, pos, ACS_HLINE | gnt_color_pair(GNT_COLOR_NORMAL), - widget->priv.width - pos - 1); - mvwhline(widget->window, pos, pos, ' ' | gnt_color_pair(GNT_COLOR_NORMAL), - widget->priv.width - pos - 1); - - for (i = 0; i < tree->ncol; i++) - { - if (COLUMN_INVISIBLE(tree, i)) { - continue; - } - mvwaddnstr(widget->window, pos, x + (x != pos), tree->columns[i].title, tree->columns[i].width); - NEXT_X; - } - if (pos) - { - tree_mark_columns(tree, pos, 0, - (tree->show_separator ? ACS_TTEE : ACS_HLINE) | gnt_color_pair(GNT_COLOR_NORMAL)); - tree_mark_columns(tree, pos, widget->priv.height - pos, - (tree->show_separator ? ACS_BTEE : ACS_HLINE) | gnt_color_pair(GNT_COLOR_NORMAL)); - } - tree_mark_columns(tree, pos, pos + 1, - (tree->show_separator ? ACS_PLUS : ACS_HLINE) | gnt_color_pair(GNT_COLOR_NORMAL)); - tree_mark_columns(tree, pos, pos, - (tree->show_separator ? ACS_VLINE : ' ') | gnt_color_pair(GNT_COLOR_NORMAL)); - start = 2; - } - - rows = widget->priv.height - pos * 2 - start - 1; - tree->bottom = get_next_n_opt(tree->top, rows, &down); - if (down < rows) - { - tree->top = get_prev_n(tree->bottom, rows); - if (tree->top == NULL) - tree->top = tree->root; - } - - up = get_distance(tree->top, tree->current); - if (up < 0) - tree->top = tree->current; - else if (up >= widget->priv.height - pos) - tree->top = get_prev_n(tree->current, rows); - - if (tree->top && !row_matches_search(tree->top)) - tree->top = get_next(tree->top); - row = tree->top; - scrcol = widget->priv.width - 1 - 2 * pos; /* exclude the borders and the scrollbar */ - - if (tree->current && !row_matches_search(tree->current)) { - GntTreeRow *old = tree->current; - tree->current = tree->top; - tree_selection_changed(tree, old, tree->current); - } - - for (i = start + pos; row && i < widget->priv.height - pos; - i++, row = get_next(row)) - { - char *str; - int wr; - - GntTextFormatFlags flags = row->flags; - int attr = 0; - - if (!row_matches_search(row)) - continue; - str = update_row_text(tree, row); - - if ((wr = gnt_util_onscreen_width(str, NULL)) > scrcol) - { - char *s = (char*)gnt_util_onscreen_width_to_pointer(str, scrcol, &wr); - *s = '\0'; - } - - if (flags & GNT_TEXT_FLAG_BOLD) - attr |= A_BOLD; - if (flags & GNT_TEXT_FLAG_UNDERLINE) - attr |= A_UNDERLINE; - if (flags & GNT_TEXT_FLAG_BLINK) - attr |= A_BLINK; - - if (row == tree->current) - { - current = i; - attr |= A_BOLD; - if (gnt_widget_has_focus(widget)) - attr |= gnt_color_pair(GNT_COLOR_HIGHLIGHT); - else - attr |= gnt_color_pair(GNT_COLOR_HIGHLIGHT_D); - } - else - { - if (flags & GNT_TEXT_FLAG_DIM) - if (row->color) - attr |= (A_DIM | gnt_color_pair(row->color)); - else - attr |= (A_DIM | gnt_color_pair(GNT_COLOR_DISABLED)); - else if (flags & GNT_TEXT_FLAG_HIGHLIGHT) - attr |= (A_DIM | gnt_color_pair(GNT_COLOR_HIGHLIGHT)); - else if (row->color) - attr |= gnt_color_pair(row->color); - else - attr |= gnt_color_pair(GNT_COLOR_NORMAL); - } - - wbkgdset(widget->window, '\0' | attr); - mvwaddstr(widget->window, i, pos, C_(str)); - whline(widget->window, ' ', scrcol - wr); - tree->bottom = row; - g_free(str); - tree_mark_columns(tree, pos, i, - (tree->show_separator ? ACS_VLINE : ' ') | attr); - } - - wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_NORMAL)); - while (i < widget->priv.height - pos) - { - mvwhline(widget->window, i, pos, ' ', - widget->priv.width - pos * 2 - 1); - tree_mark_columns(tree, pos, i, - (tree->show_separator ? ACS_VLINE : ' ')); - i++; - } - - scrcol = widget->priv.width - pos - 1; /* position of the scrollbar */ - rows--; - if (rows > 0) - { - int total = 0; - int showing, position; - - get_next_n_opt(tree->root, g_list_length(tree->list), &total); - showing = rows * rows / MAX(total, 1) + 1; - showing = MIN(rows, showing); - - total -= rows; - up = get_distance(tree->root, tree->top); - down = total - up; - - position = (rows - showing) * up / MAX(1, up + down); - position = MAX((tree->top != tree->root), position); - - if (showing + position > rows) - position = rows - showing; - - if (showing + position == rows && row) - position = MAX(0, rows - 1 - showing); - else if (showing + position < rows && !row) - position = rows - showing; - - position += pos + start + 1; - - mvwvline(widget->window, pos + start + 1, scrcol, - ' ' | gnt_color_pair(GNT_COLOR_NORMAL), rows); - mvwvline(widget->window, position, scrcol, - ACS_CKBOARD | gnt_color_pair(GNT_COLOR_HIGHLIGHT_D), showing); - } - - mvwaddch(widget->window, start + pos, scrcol, - ((tree->top != tree->root) ? ACS_UARROW : ' ') | - gnt_color_pair(GNT_COLOR_HIGHLIGHT_D)); - - mvwaddch(widget->window, widget->priv.height - pos - 1, scrcol, - (row ? ACS_DARROW : ' ') | gnt_color_pair(GNT_COLOR_HIGHLIGHT_D)); - - /* If there's a search-text, show it in the bottom of the tree */ - if (tree->priv->search && tree->priv->search->len > 0) { - const char *str = gnt_util_onscreen_width_to_pointer(tree->priv->search->str, scrcol - 1, NULL); - wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_HIGHLIGHT_D)); - mvwaddnstr(widget->window, widget->priv.height - pos - 1, pos, - tree->priv->search->str, str - tree->priv->search->str); - } - wmove(widget->window, current, pos); - - gnt_widget_queue_update(widget); -} - -static void -gnt_tree_draw(GntWidget *widget) -{ - GntTree *tree = GNT_TREE(widget); - - redraw_tree(tree); - - GNTDEBUG; -} - -static void -gnt_tree_size_request(GntWidget *widget) -{ - if (widget->priv.height == 0) - widget->priv.height = 10; /* XXX: Why?! */ - if (widget->priv.width == 0) - { - GntTree *tree = GNT_TREE(widget); - int i, width = 0; - width = 1 + 2 * (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER)); - for (i = 0; i < tree->ncol; i++) - if (!COLUMN_INVISIBLE(tree, i)) { - width = width + tree->columns[i].width; - if (tree->priv->lastvisible != i) - width++; - } - widget->priv.width = width; - } -} - -static void -gnt_tree_map(GntWidget *widget) -{ - GntTree *tree = GNT_TREE(widget); - if (widget->priv.width == 0 || widget->priv.height == 0) - { - gnt_widget_size_request(widget); - } - tree->top = tree->root; - tree->current = tree->root; - GNTDEBUG; -} - -static void -tree_selection_changed(GntTree *tree, GntTreeRow *old, GntTreeRow *current) -{ - g_signal_emit(tree, signals[SIG_SELECTION_CHANGED], 0, old ? old->key : NULL, - current ? current->key : NULL); -} - -static gboolean -action_down(GntBindable *bind, GList *null) -{ - int dist; - GntTree *tree = GNT_TREE(bind); - GntTreeRow *old = tree->current; - GntTreeRow *row = get_next(tree->current); - if (row == NULL) - return FALSE; - tree->current = row; - if ((dist = get_distance(tree->current, tree->bottom)) < 0) - gnt_tree_scroll(tree, -dist); - else - redraw_tree(tree); - if (old != tree->current) - tree_selection_changed(tree, old, tree->current); - return TRUE; -} - -static gboolean -action_move_parent(GntBindable *bind, GList *null) -{ - GntTree *tree = GNT_TREE(bind); - GntTreeRow *row = tree->current; - int dist; - - if (!row || !row->parent || SEARCHING(tree)) - return FALSE; - - tree->current = row->parent; - if ((dist = get_distance(tree->current, tree->top)) > 0) - gnt_tree_scroll(tree, -dist); - else - redraw_tree(tree); - tree_selection_changed(tree, row, tree->current); - return TRUE; -} - -static gboolean -action_up(GntBindable *bind, GList *list) -{ - int dist; - GntTree *tree = GNT_TREE(bind); - GntTreeRow *old = tree->current; - GntTreeRow *row = get_prev(tree->current); - if (!row) - return FALSE; - tree->current = row; - if ((dist = get_distance(tree->current, tree->top)) > 0) - gnt_tree_scroll(tree, -dist); - else - redraw_tree(tree); - if (old != tree->current) - tree_selection_changed(tree, old, tree->current); - - return TRUE; -} - -static gboolean -action_page_down(GntBindable *bind, GList *null) -{ - GntTree *tree = GNT_TREE(bind); - GntTreeRow *old = tree->current; - GntTreeRow *row = get_next(tree->bottom); - if (row) - { - int dist = get_distance(tree->top, tree->current); - tree->top = tree->bottom; - tree->current = get_next_n_opt(tree->top, dist, NULL); - redraw_tree(tree); - } - else if (tree->current != tree->bottom) - { - tree->current = tree->bottom; - redraw_tree(tree); - } - - if (old != tree->current) - tree_selection_changed(tree, old, tree->current); - return TRUE; -} - -static gboolean -action_page_up(GntBindable *bind, GList *null) -{ - GntWidget *widget = GNT_WIDGET(bind); - GntTree *tree = GNT_TREE(bind); - GntTreeRow *row; - GntTreeRow *old = tree->current; - - if (tree->top != tree->root) - { - int dist = get_distance(tree->top, tree->current); - row = get_prev_n(tree->top, widget->priv.height - 1 - - tree->show_title * 2 - 2 * (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER) == 0)); - if (row == NULL) - row = tree->root; - tree->top = row; - tree->current = get_next_n_opt(tree->top, dist, NULL); - redraw_tree(tree); - } - else if (tree->current != tree->top) - { - tree->current = tree->top; - redraw_tree(tree); - } - if (old != tree->current) - tree_selection_changed(tree, old, tree->current); - return TRUE; -} - -static void -end_search(GntTree *tree) -{ - if (tree->priv->search) { - g_source_remove(tree->priv->search_timeout); - g_string_free(tree->priv->search, TRUE); - tree->priv->search = NULL; - tree->priv->search_timeout = 0; - GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(tree), GNT_WIDGET_DISABLE_ACTIONS); - } -} - -static gboolean -search_timeout(gpointer data) -{ - GntTree *tree = data; - - end_search(tree); - redraw_tree(tree); - - return FALSE; -} - -static gboolean -gnt_tree_key_pressed(GntWidget *widget, const char *text) -{ - GntTree *tree = GNT_TREE(widget); - GntTreeRow *old = tree->current; - - if (text[0] == '\r' || text[0] == '\n') { - end_search(tree); - gnt_widget_activate(widget); - } else if (tree->priv->search) { - gboolean changed = TRUE; - if (g_unichar_isprint(*text)) { - tree->priv->search = g_string_append_c(tree->priv->search, *text); - } else if (g_utf8_collate(text, GNT_KEY_BACKSPACE) == 0) { - if (tree->priv->search->len) - tree->priv->search->str[--tree->priv->search->len] = '\0'; - } else - changed = FALSE; - if (changed) { - redraw_tree(tree); - } else { - gnt_bindable_perform_action_key(GNT_BINDABLE(tree), text); - } - g_source_remove(tree->priv->search_timeout); - tree->priv->search_timeout = g_timeout_add_seconds(SEARCH_TIMEOUT_S, search_timeout, tree); - return TRUE; - } else if (text[0] == ' ' && text[1] == 0) { - /* Space pressed */ - GntTreeRow *row = tree->current; - if (row && row->child) - { - row->collapsed = !row->collapsed; - redraw_tree(tree); - g_signal_emit(tree, signals[SIG_COLLAPSED], 0, row->key, row->collapsed); - } - else if (row && row->choice) - { - row->isselected = !row->isselected; - g_signal_emit(tree, signals[SIG_TOGGLED], 0, row->key); - redraw_tree(tree); - } - } else { - return FALSE; - } - - if (old != tree->current) - { - tree_selection_changed(tree, old, tree->current); - } - - return TRUE; -} - -static void -gnt_tree_free_columns(GntTree *tree) -{ - int i; - for (i = 0; i < tree->ncol; i++) { - g_free(tree->columns[i].title); - } - g_free(tree->columns); -} - -static void -gnt_tree_destroy(GntWidget *widget) -{ - GntTree *tree = GNT_TREE(widget); - - end_search(tree); - if (tree->hash) - g_hash_table_destroy(tree->hash); - g_list_free(tree->list); - gnt_tree_free_columns(tree); - g_free(tree->priv); -} - -static gboolean -gnt_tree_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) -{ - GntTree *tree = GNT_TREE(widget); - GntTreeRow *old = tree->current; - if (event == GNT_MOUSE_SCROLL_UP) { - action_up(GNT_BINDABLE(widget), NULL); - } else if (event == GNT_MOUSE_SCROLL_DOWN) { - action_down(GNT_BINDABLE(widget), NULL); - } else if (event == GNT_LEFT_MOUSE_DOWN) { - GntTreeRow *row; - GntTree *tree = GNT_TREE(widget); - int pos = 1; - if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - pos = 0; - if (tree->show_title) - pos += 2; - pos = y - widget->priv.y - pos; - row = get_next_n(tree->top, pos); - if (row && tree->current != row) { - GntTreeRow *old = tree->current; - tree->current = row; - redraw_tree(tree); - tree_selection_changed(tree, old, tree->current); - } else if (row && row == tree->current) { - if (row->choice) { - row->isselected = !row->isselected; - g_signal_emit(tree, signals[SIG_TOGGLED], 0, row->key); - redraw_tree(tree); - } else { - gnt_widget_activate(widget); - } - } - } else { - return FALSE; - } - if (old != tree->current) { - tree_selection_changed(tree, old, tree->current); - } - return TRUE; -} - -static void -gnt_tree_size_changed(GntWidget *widget, int w, int h) -{ - GntTree *tree = GNT_TREE(widget); - if (widget->priv.width <= 0) - return; - - readjust_columns(tree); -} - -static gboolean -start_search(GntBindable *bindable, GList *list) -{ - GntTree *tree = GNT_TREE(bindable); - if (tree->priv->search) - return FALSE; - GNT_WIDGET_SET_FLAGS(GNT_WIDGET(tree), GNT_WIDGET_DISABLE_ACTIONS); - tree->priv->search = g_string_new(NULL); - tree->priv->search_timeout = g_timeout_add_seconds(SEARCH_TIMEOUT_S, search_timeout, tree); - return TRUE; -} - -static gboolean -end_search_action(GntBindable *bindable, GList *list) -{ - GntTree *tree = GNT_TREE(bindable); - if (tree->priv->search == NULL) - return FALSE; - GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(tree), GNT_WIDGET_DISABLE_ACTIONS); - end_search(tree); - redraw_tree(tree); - return TRUE; -} - -static gboolean -move_first_action(GntBindable *bind, GList *null) -{ - GntTree *tree = GNT_TREE(bind); - GntTreeRow *row = tree->root; - GntTreeRow *old = tree->current; - if (row && !row_matches_search(row)) - row = get_next(row); - if (row) { - tree->current = row; - redraw_tree(tree); - if (old != tree->current) - tree_selection_changed(tree, old, tree->current); - } - - return TRUE; -} - -static gboolean -move_last_action(GntBindable *bind, GList *null) -{ - GntTree *tree = GNT_TREE(bind); - GntTreeRow *old = tree->current; - GntTreeRow *row = tree->bottom; - GntTreeRow *next; - - while ((next = get_next(row))) - row = next; - - if (row) { - tree->current = row; - redraw_tree(tree); - if (old != tree->current) - tree_selection_changed(tree, old, tree->current); - } - - return TRUE; -} - -static void -gnt_tree_set_property(GObject *obj, guint prop_id, const GValue *value, - GParamSpec *spec) -{ - GntTree *tree = GNT_TREE(obj); - switch (prop_id) { - case PROP_COLUMNS: - _gnt_tree_init_internals(tree, g_value_get_int(value)); - break; - case PROP_EXPANDER: - if (tree->priv->expander_level == g_value_get_int(value)) - break; - tree->priv->expander_level = g_value_get_int(value); - default: - break; - } -} - -static void -gnt_tree_get_property(GObject *obj, guint prop_id, GValue *value, - GParamSpec *spec) -{ - GntTree *tree = GNT_TREE(obj); - switch (prop_id) { - case PROP_COLUMNS: - g_value_set_int(value, tree->ncol); - break; - case PROP_EXPANDER: - g_value_set_int(value, tree->priv->expander_level); - break; - default: - break; - } -} - -static void -gnt_tree_class_init(GntTreeClass *klass) -{ - GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass); - GObjectClass *gclass = G_OBJECT_CLASS(klass); - - parent_class = GNT_WIDGET_CLASS(klass); - parent_class->destroy = gnt_tree_destroy; - parent_class->draw = gnt_tree_draw; - parent_class->map = gnt_tree_map; - parent_class->size_request = gnt_tree_size_request; - parent_class->key_pressed = gnt_tree_key_pressed; - parent_class->clicked = gnt_tree_clicked; - parent_class->size_changed = gnt_tree_size_changed; - - gclass->set_property = gnt_tree_set_property; - gclass->get_property = gnt_tree_get_property; - g_object_class_install_property(gclass, - PROP_COLUMNS, - g_param_spec_int("columns", "Columns", - "Number of columns in the tree.", - 1, G_MAXINT, 1, - G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS - ) - ); - g_object_class_install_property(gclass, - PROP_EXPANDER, - g_param_spec_int("expander-level", "Expander level", - "Number of levels to show expander in the tree.", - 0, G_MAXINT, 1, - G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS - ) - ); - - signals[SIG_SELECTION_CHANGED] = - g_signal_new("selection-changed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntTreeClass, selection_changed), - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); - signals[SIG_SCROLLED] = - g_signal_new("scrolled", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_INT); - signals[SIG_TOGGLED] = - g_signal_new("toggled", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GntTreeClass, toggled), - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_POINTER); - signals[SIG_COLLAPSED] = - g_signal_new("collapse-toggled", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN); - - gnt_bindable_class_register_action(bindable, "move-up", action_up, - GNT_KEY_UP, NULL); - gnt_bindable_register_binding(bindable, "move-up", GNT_KEY_CTRL_P, NULL); - gnt_bindable_class_register_action(bindable, "move-down", action_down, - GNT_KEY_DOWN, NULL); - gnt_bindable_register_binding(bindable, "move-down", GNT_KEY_CTRL_N, NULL); - gnt_bindable_class_register_action(bindable, "move-parent", action_move_parent, - GNT_KEY_BACKSPACE, NULL); - gnt_bindable_class_register_action(bindable, "page-up", action_page_up, - GNT_KEY_PGUP, NULL); - gnt_bindable_class_register_action(bindable, "page-down", action_page_down, - GNT_KEY_PGDOWN, NULL); - gnt_bindable_class_register_action(bindable, "start-search", start_search, - "/", NULL); - gnt_bindable_class_register_action(bindable, "end-search", end_search_action, - "\033", NULL); - gnt_bindable_class_register_action(bindable, "move-first", move_first_action, - GNT_KEY_HOME, NULL); - gnt_bindable_class_register_action(bindable, "move-last", move_last_action, - GNT_KEY_END, NULL); - - gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), bindable); - GNTDEBUG; -} - -static void -gnt_tree_init(GTypeInstance *instance, gpointer class) -{ - GntWidget *widget = GNT_WIDGET(instance); - GntTree *tree = GNT_TREE(widget); - tree->show_separator = TRUE; - tree->priv = g_new0(GntTreePriv, 1); - GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X | GNT_WIDGET_GROW_Y | - GNT_WIDGET_CAN_TAKE_FOCUS | GNT_WIDGET_NO_SHADOW); - gnt_widget_set_take_focus(widget, TRUE); - widget->priv.minw = 4; - widget->priv.minh = 1; - GNTDEBUG; -} - -/****************************************************************************** - * GntTree API - *****************************************************************************/ -GType -gnt_tree_get_type(void) -{ - static GType type = 0; - - if(type == 0) - { - static const GTypeInfo info = { - sizeof(GntTreeClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)gnt_tree_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GntTree), - 0, /* n_preallocs */ - gnt_tree_init, /* instance_init */ - NULL /* value_table */ - }; - - type = g_type_register_static(GNT_TYPE_WIDGET, - "GntTree", - &info, 0); - } - - return type; -} - -static void -free_tree_col(gpointer data) -{ - GntTreeCol *col = data; - if (!col->isbinary) - g_free(col->text); - g_free(col); -} - -static void -free_tree_row(gpointer data) -{ - GntTreeRow *row = data; - - if (!row) - return; - - g_list_foreach(row->columns, (GFunc)free_tree_col, NULL); - g_list_free(row->columns); - g_free(row); -} - -GntWidget *gnt_tree_new() -{ - return gnt_tree_new_with_columns(1); -} - -void gnt_tree_set_visible_rows(GntTree *tree, int rows) -{ - GntWidget *widget = GNT_WIDGET(tree); - widget->priv.height = rows; - if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - widget->priv.height += 2; -} - -int gnt_tree_get_visible_rows(GntTree *tree) -{ - GntWidget *widget = GNT_WIDGET(tree); - int ret = widget->priv.height; - if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) - ret -= 2; - return ret; -} - -GList *gnt_tree_get_rows(GntTree *tree) -{ - return tree->list; -} - -void gnt_tree_scroll(GntTree *tree, int count) -{ - GntTreeRow *row; - - if (count < 0) - { - if (get_root_distance(tree->top) == 0) - return; - row = get_prev_n(tree->top, -count); - if (row == NULL) - row = tree->root; - tree->top = row; - } - else - { - get_next_n_opt(tree->bottom, count, &count); - tree->top = get_next_n(tree->top, count); - } - - redraw_tree(tree); - g_signal_emit(tree, signals[SIG_SCROLLED], 0, count); -} - -static gpointer -find_position(GntTree *tree, gpointer key, gpointer parent) -{ - GntTreeRow *row; - - if (tree->priv->compare == NULL) - return NULL; - - if (parent == NULL) - row = tree->root; - else - row = g_hash_table_lookup(tree->hash, parent); - - if (!row) - return NULL; - - if (parent) - row = row->child; - - while (row) - { - if (tree->priv->compare(key, row->key) < 0) - return (row->prev ? row->prev->key : NULL); - if (row->next) - row = row->next; - else - return row->key; - } - return NULL; -} - -void gnt_tree_sort_row(GntTree *tree, gpointer key) -{ - GntTreeRow *row, *q, *s; - int current, newp; - - if (!tree->priv->compare) - return; - - row = g_hash_table_lookup(tree->hash, key); - g_return_if_fail(row != NULL); - - current = g_list_index(tree->list, key); - - if (row->parent) - s = row->parent->child; - else - s = tree->root; - - q = NULL; - while (s) { - if (tree->priv->compare(row->key, s->key) < 0) - break; - q = s; - s = s->next; - } - - /* Move row between q and s */ - if (row == q || row == s) - return; - - if (q == NULL) { - /* row becomes the first child of its parent */ - row->prev->next = row->next; /* row->prev cannot be NULL at this point */ - if (row->next) - row->next->prev = row->prev; - if (row->parent) - row->parent->child = row; - else - tree->root = row; - row->next = s; - g_return_if_fail(s != NULL); /* s cannot be NULL */ - s->prev = row; - row->prev = NULL; - newp = g_list_index(tree->list, s) - 1; - } else { - if (row->prev) { - row->prev->next = row->next; - } else { - /* row was the first child of its parent */ - if (row->parent) - row->parent->child = row->next; - else - tree->top = row->next; - } - - if (row->next) - row->next->prev = row->prev; - - q->next = row; - row->prev = q; - if (s) - s->prev = row; - row->next = s; - newp = g_list_index(tree->list, q) + 1; - } - tree->list = g_list_reposition_child(tree->list, current, newp); - - redraw_tree(tree); -} - -GntTreeRow *gnt_tree_add_row_after(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro) -{ - GntTreeRow *pr = NULL; - - if (g_hash_table_lookup(tree->hash, key)) { - gnt_tree_remove(tree, key); - } - - row->tree = tree; - row->key = key; - row->data = NULL; - g_hash_table_replace(tree->hash, key, row); - - if (bigbro == NULL && tree->priv->compare) - { - bigbro = find_position(tree, key, parent); - } - - if (tree->root == NULL) - { - tree->root = row; - tree->list = g_list_prepend(tree->list, key); - } - else - { - int position = 0; - - if (bigbro) - { - pr = g_hash_table_lookup(tree->hash, bigbro); - if (pr) - { - if (pr->next) pr->next->prev = row; - row->next = pr->next; - row->prev = pr; - pr->next = row; - row->parent = pr->parent; - - position = g_list_index(tree->list, bigbro); - } - } - - if (pr == NULL && parent) - { - pr = g_hash_table_lookup(tree->hash, parent); - if (pr) - { - if (pr->child) pr->child->prev = row; - row->next = pr->child; - pr->child = row; - row->parent = pr; - - position = g_list_index(tree->list, parent); - } - } - - if (pr == NULL) - { - GntTreeRow *r = tree->root; - row->next = r; - if (r) r->prev = row; - if (tree->current == tree->root) - tree->current = row; - tree->root = row; - tree->list = g_list_prepend(tree->list, key); - } - else - { - tree->list = g_list_insert(tree->list, key, position + 1); - } - } - redraw_tree(tree); - - return row; -} - -GntTreeRow *gnt_tree_add_row_last(GntTree *tree, void *key, GntTreeRow *row, void *parent) -{ - GntTreeRow *pr = NULL, *br = NULL; - - if (parent) - pr = g_hash_table_lookup(tree->hash, parent); - - if (pr) - br = pr->child; - else - br = tree->root; - - if (br) - { - while (br->next) - br = br->next; - } - - return gnt_tree_add_row_after(tree, key, row, parent, br ? br->key : NULL); -} - -gpointer gnt_tree_get_selection_data(GntTree *tree) -{ - if (tree->current) - return tree->current->key; /* XXX: perhaps we should just get rid of 'data' */ - return NULL; -} - -char *gnt_tree_get_selection_text(GntTree *tree) -{ - if (tree->current) - return update_row_text(tree, tree->current); - return NULL; -} - -GList *gnt_tree_get_row_text_list(GntTree *tree, gpointer key) -{ - GList *list = NULL, *iter; - GntTreeRow *row = key ? g_hash_table_lookup(tree->hash, key) : tree->current; - int i; - - if (!row) - return NULL; - - for (i = 0, iter = row->columns; i < tree->ncol && iter; - i++, iter = iter->next) - { - GntTreeCol *col = iter->data; - list = g_list_append(list, BINARY_DATA(tree, i) ? col->text : g_strdup(col->text)); - } - - return list; -} - -GList *gnt_tree_get_selection_text_list(GntTree *tree) -{ - return gnt_tree_get_row_text_list(tree, NULL); -} - -void gnt_tree_remove(GntTree *tree, gpointer key) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - static int depth = 0; /* Only redraw after all child nodes are removed */ - if (row) - { - gboolean redraw = FALSE; - - if (row->child) { - depth++; - while (row->child) { - gnt_tree_remove(tree, row->child->key); - } - depth--; - } - - if (get_distance(tree->top, row) >= 0 && get_distance(row, tree->bottom) >= 0) - redraw = TRUE; - - /* Update root/top/current/bottom if necessary */ - if (tree->root == row) - tree->root = get_next(row); - if (tree->top == row) - { - if (tree->top != tree->root) - tree->top = get_prev(row); - else - tree->top = get_next(row); - } - if (tree->current == row) - { - if (tree->current != tree->root) - tree->current = get_prev(row); - else - tree->current = get_next(row); - tree_selection_changed(tree, row, tree->current); - } - if (tree->bottom == row) - { - tree->bottom = get_prev(row); - } - - /* Fix the links */ - if (row->next) - row->next->prev = row->prev; - if (row->parent && row->parent->child == row) - row->parent->child = row->next; - if (row->prev) - row->prev->next = row->next; - - g_hash_table_remove(tree->hash, key); - tree->list = g_list_remove(tree->list, key); - - if (redraw && depth == 0) - { - redraw_tree(tree); - } - } -} - -static gboolean -return_true(gpointer key, gpointer data, gpointer null) -{ - return TRUE; -} - -void gnt_tree_remove_all(GntTree *tree) -{ - tree->root = NULL; - g_hash_table_foreach_remove(tree->hash, (GHRFunc)return_true, tree); - g_list_free(tree->list); - tree->list = NULL; - tree->current = tree->top = tree->bottom = NULL; -} - -int gnt_tree_get_selection_visible_line(GntTree *tree) -{ - return get_distance(tree->top, tree->current) + - !!(GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER)); -} - -void gnt_tree_change_text(GntTree *tree, gpointer key, int colno, const char *text) -{ - GntTreeRow *row; - GntTreeCol *col; - - g_return_if_fail(colno < tree->ncol); - - row = g_hash_table_lookup(tree->hash, key); - if (row) - { - col = g_list_nth_data(row->columns, colno); - if (BINARY_DATA(tree, colno)) { - col->text = (gpointer)text; - } else { - g_free(col->text); - col->text = g_strdup(text ? text : ""); - } - - if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED) && - get_distance(tree->top, row) >= 0 && get_distance(row, tree->bottom) >= 0) - redraw_tree(tree); - } -} - -GntTreeRow *gnt_tree_add_choice(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro) -{ - GntTreeRow *r; - r = g_hash_table_lookup(tree->hash, key); - g_return_val_if_fail(!r || !r->choice, NULL); - - if (bigbro == NULL) { - if (tree->priv->compare) - bigbro = find_position(tree, key, parent); - else { - r = g_hash_table_lookup(tree->hash, parent); - if (!r) - r = tree->root; - else - r = r->child; - if (r) { - while (r->next) - r = r->next; - bigbro = r->key; - } - } - } - row = gnt_tree_add_row_after(tree, key, row, parent, bigbro); - row->choice = TRUE; - - return row; -} - -void gnt_tree_set_choice(GntTree *tree, void *key, gboolean set) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - - if (!row) - return; - g_return_if_fail(row->choice); - - row->isselected = set; - redraw_tree(tree); -} - -gboolean gnt_tree_get_choice(GntTree *tree, void *key) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - - if (!row) - return FALSE; - g_return_val_if_fail(row->choice, FALSE); - - return row->isselected; -} - -void gnt_tree_set_row_flags(GntTree *tree, void *key, GntTextFormatFlags flags) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - if (!row || row->flags == flags) - return; - - row->flags = flags; - redraw_tree(tree); /* XXX: It shouldn't be necessary to redraw the whole darned tree */ -} - -void gnt_tree_set_row_color(GntTree *tree, void *key, int color) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - if (!row || row->color == color) - return; - - row->color = color; - redraw_tree(tree); -} - -void gnt_tree_set_selected(GntTree *tree , void *key) -{ - int dist; - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - if (!row || row == tree->current) - return; - - if (tree->top == NULL) - tree->top = row; - if (tree->bottom == NULL) - tree->bottom = row; - - tree->current = row; - if ((dist = get_distance(tree->current, tree->bottom)) < 0) - gnt_tree_scroll(tree, -dist); - else if ((dist = get_distance(tree->current, tree->top)) > 0) - gnt_tree_scroll(tree, -dist); - else - redraw_tree(tree); - tree_selection_changed(tree, row, tree->current); -} - -static void _gnt_tree_init_internals(GntTree *tree, int col) -{ - gnt_tree_free_columns(tree); - - tree->ncol = col; - tree->hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_tree_row); - tree->columns = g_new0(struct _GntTreeColInfo, col); - tree->priv->lastvisible = col - 1; - while (col--) - { - tree->columns[col].width = 15; - } - tree->list = NULL; - tree->show_title = FALSE; - g_object_notify(G_OBJECT(tree), "columns"); -} - -GntWidget *gnt_tree_new_with_columns(int col) -{ - GntWidget *widget = g_object_new(GNT_TYPE_TREE, - "columns", col, - "expander-level", 1, - NULL); - - return widget; -} - -GntTreeRow *gnt_tree_create_row_from_list(GntTree *tree, GList *list) -{ - GList *iter; - int i; - GntTreeRow *row = g_new0(GntTreeRow, 1); - - for (i = 0, iter = list; i < tree->ncol && iter; iter = iter->next, i++) - { - GntTreeCol *col = g_new0(GntTreeCol, 1); - col->span = 1; - if (BINARY_DATA(tree, i)) { - col->text = iter->data; - col->isbinary = TRUE; - } else { - col->text = g_strdup(iter->data ? iter->data : ""); - col->isbinary = FALSE; - } - - row->columns = g_list_append(row->columns, col); - } - - return row; -} - -GntTreeRow *gnt_tree_create_row(GntTree *tree, ...) -{ - int i; - va_list args; - GList *list = NULL; - GntTreeRow *row; - - va_start(args, tree); - for (i = 0; i < tree->ncol; i++) - { - list = g_list_append(list, va_arg(args, char *)); - } - va_end(args); - - row = gnt_tree_create_row_from_list(tree, list); - g_list_free(list); - - return row; -} - -void gnt_tree_set_col_width(GntTree *tree, int col, int width) -{ - g_return_if_fail(col < tree->ncol); - - tree->columns[col].width = width; - if (tree->columns[col].width_ratio == 0) - tree->columns[col].width_ratio = width; -} - -void gnt_tree_set_column_title(GntTree *tree, int index, const char *title) -{ - g_free(tree->columns[index].title); - tree->columns[index].title = g_strdup(title); -} - -void gnt_tree_set_column_titles(GntTree *tree, ...) -{ - int i; - va_list args; - - va_start(args, tree); - for (i = 0; i < tree->ncol; i++) - { - const char *title = va_arg(args, const char *); - tree->columns[i].title = g_strdup(title); - } - va_end(args); -} - -void gnt_tree_set_show_title(GntTree *tree, gboolean set) -{ - tree->show_title = set; - GNT_WIDGET(tree)->priv.minh = (set ? 6 : 4); -} - -void gnt_tree_set_compare_func(GntTree *tree, GCompareFunc func) -{ - tree->priv->compare = func; -} - -void gnt_tree_set_expanded(GntTree *tree, void *key, gboolean expanded) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - if (row) { - row->collapsed = !expanded; - if (GNT_WIDGET(tree)->window) - gnt_widget_draw(GNT_WIDGET(tree)); - g_signal_emit(tree, signals[SIG_COLLAPSED], 0, key, row->collapsed); - } -} - -void gnt_tree_set_show_separator(GntTree *tree, gboolean set) -{ - tree->show_separator = set; -} - -void gnt_tree_adjust_columns(GntTree *tree) -{ - GntTreeRow *row = tree->root; - int *widths, i, twidth; - - widths = g_new0(int, tree->ncol); - while (row) { - GList *iter; - for (i = 0, iter = row->columns; iter; iter = iter->next, i++) { - GntTreeCol *col = iter->data; - int w = gnt_util_onscreen_width(col->text, NULL); - if (i == 0 && row->choice) - w += 4; - if (i == 0) { - w += find_depth(row) * TAB_SIZE; - } - if (widths[i] < w) - widths[i] = w; - } - row = get_next(row); - } - - twidth = 1 + 2 * (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER)); - for (i = 0; i < tree->ncol; i++) { - if (tree->columns[i].flags & GNT_TREE_COLUMN_FIXED_SIZE) - widths[i] = tree->columns[i].width; - gnt_tree_set_col_width(tree, i, widths[i]); - if (!COLUMN_INVISIBLE(tree, i)) { - twidth = twidth + widths[i]; - if (tree->priv->lastvisible != i) - twidth += 1; - } - } - g_free(widths); - - gnt_widget_set_size(GNT_WIDGET(tree), twidth, -1); -} - -void gnt_tree_set_hash_fns(GntTree *tree, gpointer hash, gpointer eq, gpointer kd) -{ - g_hash_table_foreach_remove(tree->hash, return_true, NULL); - g_hash_table_destroy(tree->hash); - tree->hash = g_hash_table_new_full(hash, eq, kd, free_tree_row); -} - -static void -set_column_flag(GntTree *tree, int col, GntTreeColumnFlag flag, gboolean set) -{ - if (set) - tree->columns[col].flags |= flag; - else - tree->columns[col].flags &= ~flag; -} - -void gnt_tree_set_column_visible(GntTree *tree, int col, gboolean vis) -{ - g_return_if_fail(col < tree->ncol); - set_column_flag(tree, col, GNT_TREE_COLUMN_INVISIBLE, !vis); - if (vis) { - /* the column is visible */ - if (tree->priv->lastvisible < col) - tree->priv->lastvisible = col; - } else { - if (tree->priv->lastvisible == col) - while (tree->priv->lastvisible) { - tree->priv->lastvisible--; - if (!COLUMN_INVISIBLE(tree, tree->priv->lastvisible)) - break; - } - } - if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED)) - readjust_columns(tree); -} - -void gnt_tree_set_column_resizable(GntTree *tree, int col, gboolean res) -{ - g_return_if_fail(col < tree->ncol); - set_column_flag(tree, col, GNT_TREE_COLUMN_FIXED_SIZE, !res); -} - -void gnt_tree_set_column_is_binary(GntTree *tree, int col, gboolean bin) -{ - g_return_if_fail(col < tree->ncol); - set_column_flag(tree, col, GNT_TREE_COLUMN_BINARY_DATA, bin); -} - -void gnt_tree_set_column_is_right_aligned(GntTree *tree, int col, gboolean right) -{ - g_return_if_fail(col < tree->ncol); - set_column_flag(tree, col, GNT_TREE_COLUMN_RIGHT_ALIGNED, right); -} - -void gnt_tree_set_column_width_ratio(GntTree *tree, int cols[]) -{ - int i; - for (i = 0; i < tree->ncol && cols[i]; i++) { - tree->columns[i].width_ratio = cols[i]; - } -} - -void gnt_tree_set_search_column(GntTree *tree, int col) -{ - g_return_if_fail(col < tree->ncol); - g_return_if_fail(!BINARY_DATA(tree, col)); - tree->priv->search_column = col; -} - -gboolean gnt_tree_is_searching(GntTree *tree) -{ - return (tree->priv->search != NULL); -} - -void gnt_tree_set_search_function(GntTree *tree, - gboolean (*func)(GntTree *tree, gpointer key, const char *search, const char *current)) -{ - tree->priv->search_func = func; -} - -gpointer gnt_tree_get_parent_key(GntTree *tree, gpointer key) -{ - GntTreeRow *row = g_hash_table_lookup(tree->hash, key); - return (row && row->parent) ? row->parent->key : NULL; -} - -gpointer gnt_tree_row_get_key(GntTree *tree, GntTreeRow *row) -{ - g_return_val_if_fail(row && row->tree == tree, NULL); - return row->key; -} - -GntTreeRow * gnt_tree_row_get_next(GntTree *tree, GntTreeRow *row) -{ - g_return_val_if_fail(row && row->tree == tree, NULL); - return row->next; -} - -GntTreeRow * gnt_tree_row_get_prev(GntTree *tree, GntTreeRow *row) -{ - g_return_val_if_fail(row && row->tree == tree, NULL); - return row->prev; -} - -GntTreeRow * gnt_tree_row_get_child(GntTree *tree, GntTreeRow *row) -{ - g_return_val_if_fail(row && row->tree == tree, NULL); - return row->child; -} - -GntTreeRow * gnt_tree_row_get_parent(GntTree *tree, GntTreeRow *row) -{ - g_return_val_if_fail(row && row->tree == tree, NULL); - return row->parent; -} - -/************************************************************************** - * GntTreeRow GBoxed API - **************************************************************************/ -static GntTreeRow * -gnt_tree_row_ref(GntTreeRow *row) -{ - g_return_val_if_fail(row != NULL, NULL); - - row->box_count++; - - return row; -} - -static void -gnt_tree_row_unref(GntTreeRow *row) -{ - g_return_if_fail(row != NULL); - g_return_if_fail(row->box_count >= 0); - - if (!row->box_count--) - free_tree_row(row); -} - -GType -gnt_tree_row_get_type(void) -{ - static GType type = 0; - - if (type == 0) { - type = g_boxed_type_register_static("GntTreeRow", - (GBoxedCopyFunc)gnt_tree_row_ref, - (GBoxedFreeFunc)gnt_tree_row_unref); - } - - return type; -}