gambas-source-code/gb.gtk/src/gtree.cpp
Benoît Minisini 2fbf67cb29 [CONFIGURATION]
* NEW: Update FSF address in every source file.


git-svn-id: svn://localhost/gambas/trunk@3870 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2011-06-03 00:51:09 +00:00

1357 lines
28 KiB
C++

/***************************************************************************
gtree.cpp
(c) 2004-2006 - Daniel Campos Fernández <dcamposf@gmail.com>
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, 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 02110-1301, USA.
***************************************************************************/
#include <gtk/gtk.h>
#include <string.h>
#include <stdlib.h>
#include "gmemory.h"
#include "gtree.h"
#include "gtreeview.h"
#if GTK_MAJOR_VERSION >= 2 && GTK_MINOR_VERSION >= 12
#define HIDDEN_COL 0
#else
#define HIDDEN_COL 1
#endif
static GtkTreeViewColumn* gt_tree_view_find_column(GtkTreeView *tree, int ind)
{
GtkTreeViewColumn *col=NULL;
GList *cols;
GList *iter;
if (!tree) return NULL;
cols=gtk_tree_view_get_columns(GTK_TREE_VIEW(tree));
if (!cols) return NULL;
iter=g_list_nth(cols,(guint)ind + HIDDEN_COL);
if (iter) {
col=(GtkTreeViewColumn*)iter->data;
}
g_list_free(cols);
return col;
}
static int gt_tree_view_find_index(GtkTreeView *tree, GtkTreeViewColumn *column)
{
int index;
GList *cols;
GList *iter;
if (!tree) return -1;
cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(tree));
if (!cols) return -1;
iter = cols;
index = 0;
if (HIDDEN_COL)
iter = g_list_next(iter);
while (iter)
{
if (iter->data == (gpointer)column)
break;
iter = g_list_next(iter);
index++;
}
g_list_free(cols);
if (!iter)
index = -1;
return index;
}
/************************************************************
gTreeCell
*************************************************************/
gTreeCell::gTreeCell()
{
_text = NULL;
_picture = NULL;
}
gTreeCell::~gTreeCell()
{
setText(NULL);
setPicture(NULL);
}
void gTreeCell::setText(const char *vl)
{
if (_text)
g_free(_text);
_text = vl ? g_strdup(vl) : NULL;
}
void gTreeCell::setPicture(gPicture *vl)
{
gPicture::assign(&_picture, vl);
}
/************************************************************
gTreeRow
*************************************************************/
gTreeRow::gTreeRow(gTree *tr, char *key, GtkTreeIter *iter)
{
int count;
data = NULL;
dataiter = iter;
tree = tr;
_key = key;
_expanded = false;
_editable = tr->isEditable();
count = tree->columnCount();
while (count > 0)
{
count--;
data = g_list_prepend(data, (gpointer)new gTreeCell());
}
if (data)
data = g_list_reverse(data);
//fprintf(stderr, "new key: (%p) %s\n", _key, _key);
}
gTreeRow::~gTreeRow()
{
GList *iter=NULL;
if (tree->onRemove)
(*tree->onRemove)(tree, _key);
if (dataiter) gtk_tree_iter_free(dataiter);
if (data) iter=g_list_first(data);
while (iter)
{
delete (gTreeCell*)iter->data;
iter=g_list_next(iter);
}
if (data) g_list_free(data);
//fprintf(stderr, "free key: (%p) %s\n", _key, _key);
g_free(_key);
}
void gTreeRow::add()
{
data = g_list_append(data, (gpointer)new gTreeCell());
}
void gTreeRow::remove()
{
GList *iter=NULL;
gTreeCell *cell;
if (!data) return;
iter = g_list_last(data);
cell = (gTreeCell *)iter->data;
data = g_list_remove(data, cell);
delete cell;
}
int gTreeRow::children()
{
GtkTreeIter iter;
int ct=1;
if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(tree->store),&iter,dataiter)) return 0;
while ( gtk_tree_model_iter_next(GTK_TREE_MODEL(tree->store),&iter) ) ct++;
return ct;
}
void gTreeRow::update()
{
GtkTreePath *path;
path=gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store),dataiter);
if (path)
{
gtk_tree_model_row_changed (GTK_TREE_MODEL(tree->store),path,dataiter);
gtk_tree_path_free(path);
}
}
/*char* gTreeRow::parentKey()
{
GtkTreeIter it;
char *key;
if (!gtk_tree_model_iter_parent(GTK_TREE_MODEL(parent->store),&it,dataiter)) return NULL;
gtk_tree_model_get(GTK_TREE_MODEL(parent->store),&it,0,&key,-1);
return key;
}*/
void gTreeRow::setExpanded(bool ex)
{
GtkTreePath *path;
//char *current;
//fprintf(stderr, "setExpanded: %s = %d\n", _key, ex);
if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL(tree->store),dataiter))
{
_expanded = ex;
return;
}
path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store),dataiter);
if (!path)
return;
if (ex)
gtk_tree_view_expand_row(GTK_TREE_VIEW(tree->widget), path, false);
else
gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree->widget), path);
gtk_tree_path_free(path);
}
void gTreeRow::setExpanded()
{
tree->view->lock();
//_expanded = !_expanded;
setExpanded(_expanded);
tree->view->unlock();
}
bool gTreeRow::isExpanded()
{
// GtkTreePath *path;
// bool real = false;
//
// path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store),dataiter);
// if (path)
// {
// real = gtk_tree_view_row_expanded(GTK_TREE_VIEW(tree->widget),path);
// gtk_tree_path_free(path);
// }
//fprintf(stderr, "isExpanded: %s: %d (%d)\n", _key, _expanded, real);
return _expanded;
}
void gTreeRow::updateExpanded(bool ex)
{
//GtkTreePath *path;
/*path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store),dataiter);
if (!path)
return;
_expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(tree->widget),path);
gtk_tree_path_free(path);*/
_expanded = ex;
//fprintf(stderr, "updateExpanded: %s = %d\n", _key, _expanded);
}
gTreeCell* gTreeRow::get(int ind)
{
GList *iter;
if (!data)
return NULL;
iter = g_list_nth(data, ind);
if (!iter)
return NULL;
return (gTreeCell*)iter->data;
}
void gTreeRow::ensureVisible()
{
GtkTreePath *path;
char *parentKey = parent();
if (parentKey)
{
path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store), (*tree)[parentKey]->dataiter);
if (path)
{
gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tree->widget), path);
gtk_tree_path_free(path);
}
}
path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store),dataiter);
if (path)
{
gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tree->widget), path, NULL, false, 0.0, 0.0);
gtk_tree_path_free(path);
}
}
char *gTreeRow::next()
{
GtkTreePath* path;
path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store), dataiter);
if (!path)
return NULL;
gtk_tree_path_next(path);
return tree->pathToKey(path);
}
char *gTreeRow::prev()
{
GtkTreePath* path;
path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store), dataiter);
if (!path)
return NULL;
gtk_tree_path_prev(path);
return tree->pathToKey(path);
}
char *gTreeRow::child()
{
GtkTreePath* path;
path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store), dataiter);
if (!path)
return NULL;
gtk_tree_path_down(path);
return tree->pathToKey(path);
}
char *gTreeRow::last()
{
GtkTreePath* path;
GtkTreeIter iter;
int count;
path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store), dataiter);
if (!path)
return NULL;
if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(tree->store), &iter, path))
return NULL;
gtk_tree_path_free(path);
count = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(tree->store), NULL);
if (!count) return NULL;
while (--count)
gtk_tree_model_iter_next(GTK_TREE_MODEL(tree->store), &iter);
return tree->iterToKey(&iter);
}
char *gTreeRow::parent()
{
GtkTreeIter *iter = gtk_tree_iter_copy(dataiter);
char *key;
//GtkTreePath* path;
if (!gtk_tree_model_iter_parent(GTK_TREE_MODEL(tree->store), iter, dataiter))
key = NULL;
else
key = tree->iterToKey(iter);
gtk_tree_iter_free(iter);
return key;
/*path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store), dataiter);
if (!path)
return NULL;
if (!gtk_tree_path_up(path))
return NULL;
return tree->pathToKey(path);*/
}
char *gTreeRow::above()
{
char *key, *key2;
key = prev();
if (!key)
return parent();
for(;;)
{
key2 = (*tree)[key]->child();
if (!key2)
break;
key = key2;
for(;;)
{
key2 = (*tree)[key]->next();
if (!key2)
break;
key = key2;
}
}
return key;
}
char *gTreeRow::below()
{
char *key, *key2;
key = child();
if (key)
return key;
key = next();
if (key)
return key;
key = parent();
for(;;)
{
if (!key)
return NULL;
key2 = (*tree)[key]->next();
if (key2)
return key2;
key = (*tree)[key]->parent();
}
}
void gTreeRow::rect(int *x, int *y, int *w, int *h)
{
GtkTreePath* path;
GdkRectangle rect;
GtkTreeViewColumn *column;
gint depth;
gint size;
gint margin;
path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store), dataiter);
if (!path)
return;
column = gt_tree_view_find_column(GTK_TREE_VIEW(tree->widget), tree->columnCount() - 1);
gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tree->widget), path, column, &rect);
depth = gtk_tree_path_get_depth(path);
gtk_tree_path_free(path);
gtk_widget_style_get (tree->widget,
"expander-size", &size,
"vertical-separator", &margin,
(void *)NULL);
size += 4; // Constant that is hard-coded into GTK+ source code
if (!tree->hasExpanders())
depth--;
*x = depth * size;
*w = rect.x + rect.width - *x;
*h = rect.height + margin;
*y = rect.y;
}
void gTreeRow::moveFirst()
{
gtk_tree_store_move_after(tree->store, dataiter, NULL);
}
void gTreeRow::moveAfter(char *key)
{
gTreeRow *row;
if (!key || !*key)
{
moveFirst();
return;
}
row = tree->getRow(key);
if (!row)
return;
if (strcmp(row->parent(), parent()))
return;
gtk_tree_store_move_after(tree->store, dataiter, row->dataiter);
}
void gTreeRow::moveLast()
{
gtk_tree_store_move_before(tree->store, dataiter, NULL);
}
void gTreeRow::moveBefore(char *key)
{
gTreeRow *row;
if (!key || !*key)
{
moveLast();
return;
}
row = tree->getRow(key);
if (!row)
return;
if (strcmp(row->parent(), parent()))
return;
gtk_tree_store_move_before(tree->store, dataiter, row->dataiter);
}
void gTreeRow::startRename()
{
GtkTreePath* path;
path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree->store), dataiter);
if (!path)
return;
//tree->view->setFocus();
gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree->widget), path, gt_tree_view_find_column(GTK_TREE_VIEW(tree->widget), 0), true);
gtk_tree_path_free(path);
}
/************************************************************
gTree
*************************************************************/
static gboolean gTree_equal(char *a,char *b)
{
return !strcasecmp(a,b);
}
static void cb_tree_edited(GtkCellRendererText *renderer, gchar *spath, gchar *new_text, gTree *tree)
{
gTreeView *view = tree->view;
if (!tree->_edited_row)
return;
view->setItemText(tree->_edited_row, new_text);
view->emit(SIGNAL(view->onRename), tree->_edited_row);
tree->_edited_row = NULL;
}
static void cb_tree_started(GtkCellRenderer *renderer, GtkCellEditable *editable, gchar *spath, gTree *tree)
{
GtkTreePath *path = gtk_tree_path_new_from_string(spath);
if (path)
tree->_edited_row = tree->pathToKey(path);
else
tree->_edited_row = NULL;
}
static void cb_tree_canceled(GtkCellRendererText *renderer, gTree *tree)
{
gTreeView *view = tree->view;
view->emit(SIGNAL(view->onCancel), tree->_edited_row);
tree->_edited_row = NULL;
}
static void cb_column_clicked(GtkTreeViewColumn *col, gTree *tree)
{
int index = gt_tree_view_find_index(GTK_TREE_VIEW(tree->widget), col);
if (index == tree->getSortColumn())
tree->setSortAscending(!tree->isSortAscending());
else
tree->setSortColumn(index);
}
static gint tree_compare(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gTree *tree)
{
bool def = true;
int comp;
char *ka = tree->iterToKey(a);
char *kb = tree->iterToKey(b);
const char *ta, *tb;
//fprintf(stderr, "ka = '%s' kb = '%s'\n", ka, kb);
if (tree->view && tree->view->onCompare)
def = tree->view->onCompare(tree->view, ka, kb, &comp);
if (def)
{
ta = tree->getRow(ka)->get(tree->getSortColumn())->text();
if (!ta) ta = "";
tb = tree->getRow(kb)->get(tree->getSortColumn())->text();
if (!tb) tb = "";
//fprintf(stderr, "ta = '%s' tb = '%s'\n", ta, tb);
comp = g_utf8_collate(ta, tb);
}
if (!tree->isSortAscending())
comp = (-comp);
return comp;
}
void gTree::showExpanders()
{
#if GTK_MAJOR_VERSION >= 2 && GTK_MINOR_VERSION >= 12
gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(widget), true);
#else
gtk_tree_view_set_expander_column(GTK_TREE_VIEW(widget), gt_tree_view_find_column(GTK_TREE_VIEW(widget), 0));
#endif
_expander = true;
}
void gTree::lock()
{
if (view) view->lock();
}
void gTree::unlock()
{
if (view) view->unlock();
}
gTree::gTree(gTreeView *v)
{
onRemove = NULL;
datakey = g_hash_table_new((GHashFunc)g_str_hash,(GEqualFunc)gTree_equal);
if (v)
{
store = gtk_tree_store_new(1, G_TYPE_POINTER);
widget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
g_object_unref(G_OBJECT(store));
view = v;
}
else // combo-box !
{
store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
view = NULL;
widget = NULL;
}
_editable = false;
_resizable = false;
_auto_resize = false;
_edited_row = NULL;
_sorted = false;
_ascending = true;
_sort_column = 0;
_init_sort = false;
_sort_dirty = false;
_expander = false;
if (view)
{
#if GTK_MAJOR_VERSION >= 2 && GTK_MINOR_VERSION >= 12
gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(widget), false);
#else
GtkTreeViewColumn *column = gtk_tree_view_column_new();
//gtk_tree_view_column_pack_start(column,rgraph,false);
//gtk_tree_view_column_pack_start(column,rtext,true);
//gtk_tree_view_column_set_cell_data_func(column,rgraph,(GtkTreeCellDataFunc)tree_cell_graph,(gpointer)this,NULL);
//gtk_tree_view_column_set_cell_data_func(column,rtext,(GtkTreeCellDataFunc)tree_cell_text,(gpointer)this,NULL);
gtk_tree_view_column_set_visible(column, false);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column);
gtk_tree_view_set_expander_column(GTK_TREE_VIEW(widget), column);
#endif
rgraph = gtk_cell_renderer_pixbuf_new();
g_object_ref_sink(rgraph);
rtext = gtk_cell_renderer_text_new();
g_object_ref_sink(rtext);
g_signal_connect(G_OBJECT(rtext), "edited", G_CALLBACK(cb_tree_edited), (gpointer)this);
g_signal_connect(G_OBJECT(rtext), "editing-started", G_CALLBACK(cb_tree_started), (gpointer)this);
g_signal_connect(G_OBJECT(rtext), "editing-canceled", G_CALLBACK(cb_tree_canceled), (gpointer)this);
//addColumn();
setAutoResize(true);
}
}
gTree::~gTree()
{
clear();
g_hash_table_destroy(datakey);
if (view)
{
g_object_unref(rgraph);
g_object_unref(rtext);
}
}
void gTree::clear()
{
char *key;
lock();
while ((key = firstRow()))
removeRow(key);
for (int i = 0; i < columnCount(); i++)
{
setColumnWidth(i, 16);
setColumnWidth(i, -1);
}
unlock();
}
void gTree::clear(char *parent)
{
gTreeRow *row;
char *child;
row = (*this)[parent];
if (!row)
return;
lock();
while((child = row->child()))
removeRow(child);
unlock();
}
int gTree::visibleWidth()
{
GdkRectangle rect;
gint w,h;
gtk_tree_view_get_visible_rect (GTK_TREE_VIEW(widget),&rect);
gtk_tree_view_convert_bin_window_to_widget_coords(GTK_TREE_VIEW(widget),rect.width,rect.height,&w,&h);
return w;
}
int gTree::visibleHeight()
{
GdkRectangle rect;
gint w,h;
gtk_tree_view_get_visible_rect (GTK_TREE_VIEW(widget),&rect);
gtk_tree_view_convert_bin_window_to_widget_coords(GTK_TREE_VIEW(widget),rect.width,rect.height,&w,&h);
return h;
}
char *gTree::iterToKey(GtkTreeIter *iter)
{
char *key;
gtk_tree_model_get(GTK_TREE_MODEL(store), iter, view ? 0 : 1, &key, -1);
return key;
}
char *gTree::pathToKey(GtkTreePath *path, bool free)
{
GtkTreeIter iter;
char *key;
if (!path) return NULL;
if (gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
key = iterToKey(&iter);
else
key = NULL;
if (free) gtk_tree_path_free(path);
return key;
}
char* gTree::cursor()
{
GtkTreePath *path;
gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, NULL);
return pathToKey(path);
}
void gTree::setCursor(char *vl)
{
GtkTreePath *path;
gTreeRow *row = getRow(vl);
if (!row) return;
path = gtk_tree_model_get_path(GTK_TREE_MODEL(store),row->dataiter);
if (path)
{
gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget),path,NULL,false);
gtk_tree_path_free(path);
}
}
char *gTree::firstRow()
{
GtkTreeIter iter;
if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store),&iter)) return NULL;
return iterToKey(&iter);
}
char *gTree::lastRow()
{
GtkTreeIter iter;
gint count;
if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
return NULL;
count = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
if (!count) return NULL;
while (--count)
gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
return iterToKey(&iter);
}
bool gTree::rowExists(char *key)
{
return (bool)(key && *key && g_hash_table_lookup(datakey,(gconstpointer)key));
}
bool gTree::rowSelected(char *key)
{
GtkTreeSelection *sel;
gTreeRow *row=(gTreeRow*)g_hash_table_lookup(datakey,(gconstpointer)key);
if (!row) return false;
sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
if (!sel) return false;
return gtk_tree_selection_iter_is_selected(sel,row->dataiter);
}
void gTree::setRowSelected(char *key,bool vl)
{
GtkTreeSelection *sel;
gTreeRow *row=(gTreeRow*)g_hash_table_lookup(datakey,(gconstpointer)key);
if (!row) return;
sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
if (!sel) return;
if (vl)
gtk_tree_selection_select_iter(sel,row->dataiter);
else
gtk_tree_selection_unselect_iter(sel,row->dataiter);
}
bool gTree::isRowEditable(char *key)
{
gTreeRow *row = getRow(key);
if (!row)
return false;
else
return row->isEditable();
}
void gTree::setRowEditable(char *key, bool vl)
{
gTreeRow *row = getRow(key);
if (!row)
return;
row->setEditable(vl);
}
int gTree::rowCount()
{
return g_hash_table_size(datakey);
}
bool gTree::removeRow(char *key)
{
gTreeRow *row;
char *child;
if (!key || !*key) return false;
row=(gTreeRow*)g_hash_table_lookup(datakey, (gconstpointer)key);
if (!row) return false;
//fprintf(stderr, "gTree::removeRow: '%s'\n", key);
while((child = row->child()))
removeRow(child);
//fprintf(stderr, "gTree::removeRow: '%s' removed\n", key);
g_hash_table_remove (datakey, (gconstpointer)key);
gtk_tree_store_remove(store, row->dataiter);
delete row;
return true;
}
gTreeRow* gTree::getRow(char *key) const
{
if (!key)
return NULL;
else
return (gTreeRow*)g_hash_table_lookup (datakey,(gconstpointer)key);
}
gTreeRow* gTree::addRow(char *key, char *parent, char *after, bool before)
{
GtkTreeIter iter;
GtkTreeIter *piter;
gTreeRow *row,*par,*aft=NULL;
char *buf;
if (!key) return NULL;
if (g_hash_table_lookup (datakey,(gconstpointer)key)) return NULL;
if (after)
{
aft=(gTreeRow*)g_hash_table_lookup (datakey,(gconstpointer)after);
if (!aft) return NULL;
}
if (parent)
{
par = (gTreeRow*)g_hash_table_lookup (datakey,(gconstpointer)parent);
if (!par)
return NULL;
piter = par->dataiter;
}
else
piter = NULL;
if (aft)
{
if (before)
gtk_tree_store_insert_before(store, &iter, piter, aft->dataiter);
else
gtk_tree_store_insert_after(store, &iter, piter, aft->dataiter);
}
else
gtk_tree_store_append (store, &iter, piter);
buf = g_strdup(key); // Will be freed by ~gTreeRow()
row = new gTreeRow(this, buf, gtk_tree_iter_copy(&iter));
g_hash_table_insert(datakey, (gpointer)buf, (gpointer)row);
gtk_tree_store_set(store, &iter, view ? 0 : 1, buf, -1);
if (parent)
{
getRow(parent)->setExpanded();
showExpanders();
}
return row;
}
static void tree_cell_text(GtkTreeViewColumn *col,GtkCellRenderer *cell,GtkTreeModel *md,GtkTreeIter *iter,gTree *Tr)
{
gTreeRow *row=NULL;
gTreeCell *data;
const char *buf = "";
char *key;
int index = -1;
double align;
key = Tr->iterToKey(iter);
if (key)
row=(gTreeRow*)g_hash_table_lookup(Tr->datakey,(gpointer)key);
if (row)
{
index = gt_tree_view_find_index(GTK_TREE_VIEW(Tr->widget), col);
data = row->get(index);
if (data)
{
if (data->text())
buf = data->text();
}
}
align = gtk_tree_view_column_get_alignment(col);
g_object_set(G_OBJECT(cell),
"text", buf,
"editable", index == 0 && row->isEditable(),
"xalign", align,
(void *)NULL);
}
static void tree_cell_graph(GtkTreeViewColumn *col,GtkCellRenderer *cell,GtkTreeModel *md,GtkTreeIter *iter,gTree *Tr)
{
gTreeRow *row=NULL;
gTreeCell *data;
GdkPixbuf *buf=NULL;
char *key;
key = Tr->iterToKey(iter);
if (key)
row=(gTreeRow*)g_hash_table_lookup(Tr->datakey,(gpointer)key);
if (row)
{
data = row->get(gt_tree_view_find_index(GTK_TREE_VIEW(Tr->widget), col));
if (data)
{
buf = data->picture() ? data->picture()->getPixbuf() : NULL;
}
}
g_object_set(G_OBJECT(cell),"pixbuf",buf,(void *)NULL);
}
static void gTree_addColumn(char *key,gTreeRow *value,gpointer data)
{
value->add();
}
void gTree::addColumn()
{
GtkTreeViewColumn *column;
g_hash_table_foreach(datakey,(GHFunc)gTree_addColumn,NULL);
if (view)
{
column = gtk_tree_view_column_new();
gtk_tree_view_column_pack_start(column,rgraph,false);
gtk_tree_view_column_pack_start(column,rtext,true);
gtk_tree_view_column_set_cell_data_func(column,rgraph,(GtkTreeCellDataFunc)tree_cell_graph,(gpointer)this,NULL);
gtk_tree_view_column_set_cell_data_func(column,rtext,(GtkTreeCellDataFunc)tree_cell_text,(gpointer)this,NULL);
gtk_tree_view_column_set_resizable(column, isResizable());
gtk_tree_view_column_set_sizing(column, isAutoResize() ? GTK_TREE_VIEW_COLUMN_AUTOSIZE : GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget),column);
g_signal_connect(G_OBJECT(column), "clicked", G_CALLBACK(cb_column_clicked), (gpointer)this);
updateSort();
}
}
static void gTree_removeColumn(char *key,gTreeRow *value,gpointer data)
{
value->remove();
}
void gTree::removeColumn()
{
GtkTreeViewColumn *column;
int vl;
if (!(vl=columnCount()) ) return;
g_hash_table_foreach(datakey,(GHFunc)gTree_removeColumn,NULL);
if (view)
{
//column=gtk_tree_view_get_column(GTK_TREE_VIEW(widget),vl-1);
column = gt_tree_view_find_column(GTK_TREE_VIEW(widget), vl-1);
gtk_tree_view_remove_column(GTK_TREE_VIEW(widget),column);
updateSort();
}
}
int gTree::columnCount()
{
GList *cols;
int ret;
if (!view) return 1;
if (!widget) return 0;
cols=gtk_tree_view_get_columns(GTK_TREE_VIEW(widget));
if (!cols) return 0;
ret=g_list_length(cols) - HIDDEN_COL;
g_list_free(cols);
return ret;
}
char* gTree::columnName(int ind)
{
GtkTreeViewColumn *col=gt_tree_view_find_column(GTK_TREE_VIEW(widget),ind);
if (!col) return NULL;
return (char *)gtk_tree_view_column_get_title(col);
}
void gTree::setColumnName(int ind,char *vl)
{
GtkTreeViewColumn *col=gt_tree_view_find_column(GTK_TREE_VIEW(widget),ind);
if (!col) return;
gtk_tree_view_column_set_title(col,(const gchar*)vl);
}
bool gTree::columnVisible(int ind)
{
GtkTreeViewColumn *col=gt_tree_view_find_column(GTK_TREE_VIEW(widget),ind);
if (!col) return false;
return gtk_tree_view_column_get_visible(col);
}
void gTree::setColumnVisible(int ind,bool vl)
{
GtkTreeViewColumn *col=gt_tree_view_find_column(GTK_TREE_VIEW(widget),ind);
if (!col) return;
gtk_tree_view_column_set_visible(col,vl);
}
bool gTree::columnResizable(int ind)
{
GtkTreeViewColumn *col=gt_tree_view_find_column(GTK_TREE_VIEW(widget),ind);
if (!col) return false;
return gtk_tree_view_column_get_resizable(col);
}
void gTree::setColumnResizable(int ind, bool vl)
{
GtkTreeViewColumn *col=gt_tree_view_find_column(GTK_TREE_VIEW(widget),ind);
if (!col) return;
gtk_tree_view_column_set_resizable(col,vl);
}
int gTree::columnAlignment(int ind)
{
GtkTreeViewColumn *col = gt_tree_view_find_column(GTK_TREE_VIEW(widget), ind);
if (!col)
return ALIGN_LEFT;
else
return gt_to_alignment(gtk_tree_view_column_get_alignment(col));
}
void gTree::setColumnAlignment(int ind, int align)
{
GtkTreeViewColumn *col = gt_tree_view_find_column(GTK_TREE_VIEW(widget), ind);
if (!col)
return;
gtk_tree_view_column_set_alignment(col, gt_from_alignment(align));
}
int gTree::columnWidth(int ind)
{
GtkTreeViewColumn *col = gt_tree_view_find_column(GTK_TREE_VIEW(widget), ind);
if (!col)
return 0;
else
return gtk_tree_view_column_get_fixed_width(col);
}
void gTree::setColumnWidth(int ind, int w)
{
GtkTreeViewColumn *col = gt_tree_view_find_column(GTK_TREE_VIEW(widget), ind);
if (!col)
return;
if (w > 0)
{
gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_fixed_width(col, w);
}
else
gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
}
bool gTree::headers()
{
if (!widget) return false;
return gtk_tree_view_get_headers_visible(GTK_TREE_VIEW(widget));
}
void gTree::setHeaders(bool vl)
{
if (!widget) return;
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(widget),vl);
}
void gTree::setResizable(bool vl)
{
int i;
for (i = 0; i < columnCount(); i++)
gtk_tree_view_column_set_resizable(gt_tree_view_find_column(GTK_TREE_VIEW(widget), i), vl);
_resizable = vl;
}
void gTree::setAutoResize(bool vl)
{
int i;
for (i = 0; i < columnCount(); i++)
gtk_tree_view_column_set_sizing(gt_tree_view_find_column(GTK_TREE_VIEW(widget), i), vl ? GTK_TREE_VIEW_COLUMN_AUTOSIZE : GTK_TREE_VIEW_COLUMN_FIXED);
_auto_resize = vl;
}
void gTree::selectAll()
{
GtkTreeSelection *sel;
sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
if (!sel)
return;
gtk_tree_selection_select_all(sel);
}
void gTree::unselectAll()
{
GtkTreeSelection *sel;
sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
if (!sel)
return;
gtk_tree_selection_unselect_all(sel);
}
void gTree::setSorted(bool v)
{
if (v == _sorted)
return;
_sorted = v;
_sort_column = v ? 0 : -1;
if (!_sorted)
{
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), NULL, NULL, NULL);
}
updateSort();
}
void gTree::setSortColumn(int v)
{
if (_sort_column < 0)
setSorted(false);
else
{
_sort_column = v;
_ascending = true;
updateSort();
}
}
void gTree::setSortAscending(bool v)
{
_ascending = v;
updateSort();
}
void gTree::sort()
{
if (!_sorted)
return;
// BM: force the store to be sorted
gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), (GtkTreeIterCompareFunc)tree_compare, this, NULL);
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
_sort_dirty = false;
}
void gTree::updateSort()
{
int i;
bool s;
if (view)
{
if (_sort_column >= columnCount())
_sort_column = 0;
for (i = 0; i < columnCount(); i++)
{
GtkTreeViewColumn *col = gt_tree_view_find_column(GTK_TREE_VIEW(widget), i);
if (!_sorted)
{
gtk_tree_view_column_set_sort_indicator(col, false);
gtk_tree_view_column_set_clickable(col, false);
continue;
}
gtk_tree_view_column_set_clickable(col, true);
s = i == _sort_column;
gtk_tree_view_column_set_sort_indicator(col, s);
if (s)
gtk_tree_view_column_set_sort_order(col, _ascending ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING);
}
}
sortLater();
}
static gboolean tree_sort_later(gTree *tree)
{
tree->sort();
return FALSE;
}
void gTree::sortLater()
{
if (!isSorted() || _sort_dirty)
return;
_sort_dirty = true;
g_timeout_add(0, (GSourceFunc)tree_sort_later, this);
}