Get rid off GtkTreeModelFilter because the time to sort becomes unbearable when combined with GtkTreeSortable. This means that we now track which frames are visible in the our own packet list store. To do so, we now distinguish between physical and visible rows. All frames are added as physical rows. Only those that passes the display filter are marked as visible.

svn path=/trunk/; revision=29705
This commit is contained in:
Kovarththanan Rajaratnam 2009-09-05 10:36:29 +00:00
parent b7bdf3efc1
commit 95ddec4d07
5 changed files with 188 additions and 114 deletions

2
file.c
View File

@ -1898,6 +1898,8 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
/* Unfreeze the packet list. */
#ifdef NEW_PACKET_LIST
if (!add_to_packet_list)
new_packet_list_recreate_visible_rows();
new_packet_list_thaw();
#else
packet_list_thaw();

View File

@ -74,9 +74,6 @@ static void show_cell_data_func(GtkTreeViewColumn *col,
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data);
static void filter_function (GtkTreeView *treeview);
static gboolean filter_visible_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data _U_);
GtkWidget *
new_packet_list_create(void)
@ -114,10 +111,8 @@ new_packet_list_append(column_info *cinfo _U_, frame_data *fdata, packet_info *p
row_data.fdata = fdata;
packet_list_append_record(packetlist, &row_data);
/* XXX - Check that this is the right # */
return PACKET_LIST_RECORD_COUNT(packetlist->rows);
/* Return the _visible_ position */
return packet_list_append_record(packetlist, &row_data);
}
static gboolean
@ -262,7 +257,8 @@ new_packet_list_freeze(void)
void
new_packet_list_thaw(void)
{
filter_function(GTK_TREE_VIEW(packetlist->view));
/* Apply model */
gtk_tree_view_set_model( GTK_TREE_VIEW(packetlist->view), GTK_TREE_MODEL(packetlist));
/* Remove extra reference added by new_packet_list_freeze() */
g_object_unref(packetlist);
@ -270,6 +266,12 @@ new_packet_list_thaw(void)
packets_bar_update();
}
void
new_packet_list_recreate_visible_rows(void)
{
packet_list_recreate_visible_rows(packetlist);
}
void
new_packet_list_resize_columns_cb(GtkWidget *widget _U_, gpointer data _U_)
{
@ -568,7 +570,7 @@ new_packet_list_get_row_data(gint row)
{
PacketListRecord *record;
record = PACKET_LIST_RECORD_GET(packetlist->rows, row-1);
record = PACKET_LIST_RECORD_GET(packetlist->physical_rows, row-1);
return record->fdata;
}
@ -650,7 +652,7 @@ show_cell_data_func(GtkTreeViewColumn *col _U_, GtkCellRenderer *renderer,
record = new_packet_list_get_record(model, iter);
fdata = record->fdata;
row = record->pos;
row = record->physical_pos;
if (record->dissected)
color_filter = fdata->color_filter;
@ -772,28 +774,6 @@ void new_packet_list_mark_frame_cb(GtkWidget *w _U_, gpointer data _U_)
mark_frames_ready();
}
static void filter_function (GtkTreeView *treeview)
{
GtkTreeModel *filter_model;
filter_model = gtk_tree_model_filter_new(GTK_TREE_MODEL(packetlist), NULL );
gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER ( filter_model ),(GtkTreeModelFilterVisibleFunc) filter_visible_func, NULL , NULL);
/* Apply model */
gtk_tree_view_set_model( GTK_TREE_VIEW( treeview ),filter_model);
g_object_unref( filter_model );
}
/* This function is called on every model row. We check whether the packet
* should be visible or not.
*/
static gboolean
filter_visible_func (GtkTreeModel *model _U_, GtkTreeIter *iter, gpointer data _U_)
{
return packet_list_visible_record(packetlist, iter);
}
static gboolean
get_col_text_from_record( PacketListRecord *record, gint col_num, gchar** cell_text){

View File

@ -98,9 +98,6 @@ static gboolean packet_list_sortable_has_default_sort_func(GtkTreeSortable
static void packet_list_sortable_init(GtkTreeSortableIface *iface);
static gint packet_list_compare_records(gint sort_id _U_, PacketListRecord *a,
PacketListRecord *b);
static gint packet_list_qsort_compare_func(PacketListRecord **a,
PacketListRecord **b,
PacketList *packet_list);
static void packet_list_resort(PacketList *packet_list);
static GObjectClass *parent_class = NULL;
@ -221,16 +218,17 @@ packet_list_init(PacketList *packet_list)
packet_list->column_types[i] = G_TYPE_STRING;
}
/* To check whether an iter belongs to our model. */
packet_list->stamp = g_random_int();
/* Note: We need one extra column to store the entire PacketListRecord */
packet_list->column_types[i] = G_TYPE_POINTER;
packet_list->n_columns = (guint)cfile.cinfo.num_cols+1;
packet_list->rows = g_ptr_array_new();
packet_list->physical_rows = g_ptr_array_new();
packet_list->visible_rows = g_ptr_array_new();
packet_list->sort_id = 0; /* defaults to first column for now */
packet_list->sort_order = GTK_SORT_ASCENDING;
packet_list->stamp = g_random_int(); /* To check whether an iter belongs
* to our model. */
}
/* This function is called just before a packet list is destroyed. Free
@ -297,13 +295,15 @@ packet_list_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter,
n = indices[0]; /* the n-th top level row */
packet_list = PACKET_LIST(tree_model);
if(n >= PACKET_LIST_RECORD_COUNT(packet_list->rows))
if(PACKET_LIST_RECORD_COUNT(packet_list->visible_rows) == 0)
return FALSE;
record = PACKET_LIST_RECORD_GET(packet_list->rows, n);
if(!PACKET_LIST_RECORD_INDEX_VALID(packet_list->visible_rows, n))
return FALSE;
g_assert(record != NULL);
g_assert(record->pos == n);
record = PACKET_LIST_RECORD_GET(packet_list->visible_rows, n);
g_assert(record->visible_pos == n);
/* We simply store a pointer to our custom record in the iter */
iter->stamp = packet_list->stamp;
@ -330,7 +330,7 @@ packet_list_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter)
record = (PacketListRecord*) iter->user_data;
path = gtk_tree_path_new();
gtk_tree_path_append_index(path, record->pos);
gtk_tree_path_append_index(path, record->visible_pos);
return path;
}
@ -345,16 +345,18 @@ packet_list_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column,
g_return_if_fail(PACKETLIST_IS_LIST(tree_model));
g_return_if_fail(iter != NULL);
packet_list = PACKET_LIST(tree_model);
/* Note: We use one extra column to store the entire PacketListRecord */
g_return_if_fail(column < packet_list->n_columns);
type = packet_list->column_types[column];
g_value_init(value, type);
record = (PacketListRecord*) iter->user_data;
g_return_if_fail(record->pos < PACKET_LIST_RECORD_COUNT(packet_list->rows));
g_return_if_fail(PACKET_LIST_RECORD_INDEX_VALID(packet_list->physical_rows, record->physical_pos));
g_return_if_fail(PACKET_LIST_RECORD_INDEX_VALID(packet_list->visible_rows, record->visible_pos));
type = packet_list->column_types[column];
g_value_init(value, type);
/* XXX Probably the switch should be on column or
* should we allways return the pointer and read the data as required??
@ -374,6 +376,27 @@ packet_list_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column,
}
}
static PacketListRecord *
packet_list_iter_next_visible(PacketList *packet_list, PacketListRecord *record)
{
PacketListRecord *nextrecord;
gint next_visible_pos;
g_assert(record->visible_pos >= 0);
next_visible_pos = record->visible_pos + 1;
/* Is this the last record in the list? */
if(!PACKET_LIST_RECORD_INDEX_VALID(packet_list->visible_rows, next_visible_pos))
return NULL;
nextrecord = PACKET_LIST_RECORD_GET(packet_list->visible_rows, next_visible_pos);
g_assert(nextrecord->visible_pos == (record->visible_pos + 1));
g_assert(nextrecord->physical_pos >= (record->physical_pos + 1));
return nextrecord;
}
/* Takes an iter structure and sets it to point to the next row. */
static gboolean
packet_list_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter)
@ -383,22 +406,19 @@ packet_list_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter)
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), FALSE);
if(iter == NULL || iter->user_data == NULL)
if(iter == NULL)
return FALSE;
g_return_val_if_fail(iter->user_data, FALSE);
packet_list = PACKET_LIST(tree_model);
record = (PacketListRecord*) iter->user_data;
nextrecord = packet_list_iter_next_visible(packet_list, record);
/* Is this the last record in the list? */
if((record->pos + 1) >= PACKET_LIST_RECORD_COUNT(packet_list->rows))
if (!nextrecord)
return FALSE;
nextrecord = PACKET_LIST_RECORD_GET(packet_list->rows, (record->pos + 1));
g_assert(nextrecord != NULL);
g_assert(nextrecord->pos == (record->pos + 1));
iter->stamp = packet_list->stamp;
iter->user_data = nextrecord;
@ -411,27 +431,23 @@ packet_list_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter,
{
PacketList *packet_list;
g_return_val_if_fail(parent == NULL || parent->user_data != NULL,
FALSE);
g_return_val_if_fail(parent == NULL || parent->user_data != NULL, FALSE);
/* This is a list, nodes have no children. */
if(parent)
return FALSE;
/* parent == NULL is a special case; we need to return the first top-
* level row */
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), FALSE);
packet_list = PACKET_LIST(tree_model);
/* No rows => no first row */
if(PACKET_LIST_RECORD_COUNT(packet_list->rows) == 0)
if(PACKET_LIST_RECORD_COUNT(packet_list->visible_rows) == 0)
return FALSE;
/* Set iter to first item in list */
iter->stamp = packet_list->stamp;
iter->user_data = PACKET_LIST_RECORD_GET(packet_list->rows, 0);
iter->user_data = PACKET_LIST_RECORD_GET(packet_list->visible_rows, 0);
return TRUE;
}
@ -447,16 +463,20 @@ packet_list_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter)
{
PacketList *packet_list;
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), -1);
g_return_val_if_fail(iter == NULL || iter->user_data != NULL, FALSE);
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), 0);
g_return_val_if_fail(iter, 0);
g_return_val_if_fail(iter->user_data, 0);
packet_list = PACKET_LIST(tree_model);
/* special case: if iter == NULL, return number of top-level rows */
if(!iter)
return PACKET_LIST_RECORD_COUNT(packet_list->rows);
return 0; /* Lists have zero children */
if(!iter) {
/* special case: if iter == NULL, return number of top-level rows */
return PACKET_LIST_RECORD_COUNT(packet_list->visible_rows);
}
else {
/* Lists have zero children */
return 0;
}
}
static gboolean
@ -474,15 +494,13 @@ packet_list_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter,
if(parent)
return FALSE;
/* Special case: if parent == NULL, set iter to n-th
* top-level row. */
if((guint)n >= PACKET_LIST_RECORD_COUNT(packet_list->rows))
return FALSE;
/* Special case: if parent == NULL, set iter to n-th top-level row. */
if(!PACKET_LIST_RECORD_INDEX_VALID(packet_list->visible_rows, n))
return NULL;
record = PACKET_LIST_RECORD_GET(packet_list->rows, n);
record = PACKET_LIST_RECORD_GET(packet_list->visible_rows, n);
g_assert(record != NULL);
g_assert(record->pos == (guint)n);
g_assert(record->visible_pos == n);
iter->stamp = packet_list->stamp;
iter->user_data = record;
@ -532,9 +550,6 @@ new_packet_list_store_clear(PacketList *packet_list)
g_return_if_fail(packet_list != NULL);
g_return_if_fail(PACKETLIST_IS_LIST(packet_list));
if(PACKET_LIST_RECORD_COUNT(packet_list->rows) == 0)
return;
/* Don't issue a row_deleted signal. We rely on our caller to have disconnected
* the model from the view.
for( ; packet_list->num_rows > 0; --packet_list->num_rows)
@ -542,8 +557,12 @@ new_packet_list_store_clear(PacketList *packet_list)
*/
/* XXX - hold on to these rows and reuse them instead */
g_ptr_array_free(packet_list->rows, TRUE);
packet_list->rows = g_ptr_array_new();
if(packet_list->physical_rows)
g_ptr_array_free(packet_list->physical_rows, TRUE);
if(packet_list->visible_rows)
g_ptr_array_free(packet_list->visible_rows, TRUE);
packet_list->physical_rows = g_ptr_array_new();
packet_list->visible_rows = g_ptr_array_new();
}
#if 0
@ -585,22 +604,26 @@ packet_list_visible_record(PacketList *packet_list, GtkTreeIter *iter)
return record->fdata->flags.passed_dfilter;
}
void
gint
packet_list_append_record(PacketList *packet_list, row_data_t *row_data)
{
PacketListRecord *newrecord;
guint pos;
g_return_if_fail(PACKETLIST_IS_LIST(packet_list));
pos = PACKET_LIST_RECORD_COUNT(packet_list->rows);
g_return_val_if_fail(PACKETLIST_IS_LIST(packet_list), -1);
newrecord = se_alloc(sizeof(PacketListRecord));
newrecord->dissected = FALSE;
newrecord->fdata = row_data->fdata;
newrecord->pos = pos;
newrecord->physical_pos = PACKET_LIST_RECORD_COUNT(packet_list->physical_rows);
PACKET_LIST_RECORD_APPEND(packet_list->rows, newrecord);
if (newrecord->fdata->flags.passed_dfilter) {
newrecord->visible_pos = PACKET_LIST_RECORD_COUNT(packet_list->visible_rows);
PACKET_LIST_RECORD_APPEND(packet_list->visible_rows, newrecord);
}
else
newrecord->visible_pos = -1;
PACKET_LIST_RECORD_APPEND(packet_list->physical_rows, newrecord);
/* Don't issue a row_inserted signal. We rely on our caller to have disconnected
* the model from the view.
@ -610,6 +633,8 @@ packet_list_append_record(PacketList *packet_list, row_data_t *row_data)
/* Don't resort the list for every row, the list will be in packet order any way.
* packet_list_resort(packet_list);
*/
return newrecord->visible_pos;
}
void
@ -619,10 +644,13 @@ packet_list_change_record(PacketList *packet_list, guint row, gint col, column_i
g_return_if_fail(PACKETLIST_IS_LIST(packet_list));
g_assert(row < PACKET_LIST_RECORD_COUNT(packet_list->rows));
record = PACKET_LIST_RECORD_GET(packet_list->rows, row);
g_assert(record->pos == row);
g_assert(row < PACKET_LIST_RECORD_COUNT(packet_list->physical_rows));
record = PACKET_LIST_RECORD_GET(packet_list->physical_rows, row);
g_assert(record->physical_pos == row);
g_assert(!record->fdata->col_text || (record->fdata->col_text[col] == NULL));
if (!record->fdata->col_text)
record->fdata->col_text = se_alloc0(sizeof(record->fdata->col_text) *
(packet_list->n_columns-1));
@ -728,8 +756,9 @@ packet_list_compare_records(gint sort_id, PacketListRecord *a,
g_return_val_if_reached(0);
}
static gint
packet_list_qsort_compare_func(PacketListRecord **a, PacketListRecord **b,
packet_list_qsort_physical_compare_func(PacketListRecord **a, PacketListRecord **b,
PacketList *packet_list)
{
gint ret;
@ -745,34 +774,64 @@ packet_list_qsort_compare_func(PacketListRecord **a, PacketListRecord **b,
return ret;
}
static gint
packet_list_qsort_visible_compare_func(PacketListRecord **a, PacketListRecord **b,
PacketList *packet_list)
{
gint ret;
g_assert((a) && (b) && (packet_list));
ret = ((*a)->visible_pos) < ((*b)->visible_pos) ? -1 :
((*a)->visible_pos) > ((*b)->visible_pos) ? 1 : 0;
return ret;
}
static void
packet_list_resort(PacketList *packet_list)
{
PacketListRecord *record;
GtkTreePath *path;
gint *neworder;
guint i;
guint phy_idx;
guint vis_idx;
g_return_if_fail(packet_list != NULL);
g_return_if_fail(PACKETLIST_IS_LIST(packet_list));
if(PACKET_LIST_RECORD_COUNT(packet_list->rows) == 0)
if(PACKET_LIST_RECORD_COUNT(packet_list->visible_rows) == 0)
return;
/* resort */
g_qsort_with_data(packet_list->rows->pdata,
PACKET_LIST_RECORD_COUNT(packet_list->rows),
/* resort physical rows according to sorting column */
g_qsort_with_data(packet_list->physical_rows->pdata,
PACKET_LIST_RECORD_COUNT(packet_list->physical_rows),
sizeof(PacketListRecord*),
(GCompareDataFunc) packet_list_qsort_compare_func,
(GCompareDataFunc) packet_list_qsort_physical_compare_func,
packet_list);
/* let other objects know about the new order */
neworder = g_new0(gint, PACKET_LIST_RECORD_COUNT(packet_list->rows));
neworder = g_new0(gint, PACKET_LIST_RECORD_COUNT(packet_list->visible_rows));
for(i = 0; i < PACKET_LIST_RECORD_COUNT(packet_list->rows); ++i) {
neworder[i] = PACKET_LIST_RECORD_GET(packet_list->rows, i)->pos;
PACKET_LIST_RECORD_GET(packet_list->rows, i)->pos = i;
for(phy_idx = 0, vis_idx = 0; phy_idx < PACKET_LIST_RECORD_COUNT(packet_list->physical_rows); ++phy_idx) {
record = PACKET_LIST_RECORD_GET(packet_list->physical_rows, phy_idx);
record->physical_pos = phy_idx;
if (record->visible_pos >= 0) {
neworder[vis_idx] = record->visible_pos;
record->visible_pos = vis_idx;
++vis_idx;
}
}
g_assert(vis_idx == PACKET_LIST_RECORD_COUNT(packet_list->visible_rows));
/* resort visible rows according to new physical order */
g_qsort_with_data(packet_list->visible_rows->pdata,
PACKET_LIST_RECORD_COUNT(packet_list->visible_rows),
sizeof(PacketListRecord*),
(GCompareDataFunc) packet_list_qsort_visible_compare_func,
packet_list);
path = gtk_tree_path_new();
gtk_tree_model_rows_reordered(GTK_TREE_MODEL(packet_list), path, NULL,
@ -782,14 +841,41 @@ packet_list_resort(PacketList *packet_list)
g_free(neworder);
}
void
packet_list_recreate_visible_rows(PacketList *packet_list)
{
guint phy_idx;
guint vis_idx;
PacketListRecord *record;
g_return_if_fail(packet_list != NULL);
g_return_if_fail(PACKETLIST_IS_LIST(packet_list));
if(PACKET_LIST_RECORD_COUNT(packet_list->physical_rows) == 0)
return;
if(packet_list->visible_rows)
g_ptr_array_free(packet_list->visible_rows, TRUE);
packet_list->visible_rows = g_ptr_array_new();
for(phy_idx = 0, vis_idx = 0; phy_idx < PACKET_LIST_RECORD_COUNT(packet_list->physical_rows); ++phy_idx) {
record = PACKET_LIST_RECORD_GET(packet_list->physical_rows, phy_idx);
if (record->fdata->flags.passed_dfilter) {
record->visible_pos = vis_idx++;
PACKET_LIST_RECORD_APPEND(packet_list->visible_rows, record);
}
}
}
void
packet_list_reset_dissected(PacketList *packet_list)
{
PacketListRecord *record;
guint i;
for(i = 0; i < PACKET_LIST_RECORD_COUNT(packet_list->rows); ++i) {
record = PACKET_LIST_RECORD_GET(packet_list->rows, i);
for(i = 0; i < PACKET_LIST_RECORD_COUNT(packet_list->physical_rows); ++i) {
record = PACKET_LIST_RECORD_GET(packet_list->physical_rows, i);
record->dissected = FALSE;
}
}

View File

@ -45,10 +45,11 @@ typedef struct _PacketListRecord PacketListRecord;
typedef struct _PacketList PacketList;
typedef struct _PacketListClass PacketListClass;
#define PACKET_LIST_RECORD_GET(rows, pos) ((PacketListRecord*) g_ptr_array_index((rows), (pos)))
#define PACKET_LIST_RECORD_GET(rows, pos) ((PacketListRecord*) g_ptr_array_index((rows), (pos)))
#define PACKET_LIST_RECORD_SET(rows, pos, item) PACKET_LIST_RECORD_GET((rows), (pos)) = (item)
#define PACKET_LIST_RECORD_APPEND(rows, item) g_ptr_array_add((rows), (item))
#define PACKET_LIST_RECORD_COUNT(rows) ((rows)->len)
#define PACKET_LIST_RECORD_COUNT(rows) ((rows) ? (rows)->len : 0)
#define PACKET_LIST_RECORD_INDEX_VALID(rows, idx) ((rows) ? (((guint) (idx)) < (rows)->len) : FALSE)
/* PacketListRecord: represents a row */
struct _PacketListRecord
@ -57,7 +58,10 @@ struct _PacketListRecord
frame_data *fdata;
/* admin stuff used by the custom list model */
guint pos; /* position within the array */
/* position within the physical array */
guint physical_pos;
/* position within the visible array */
gint visible_pos;
};
/* PacketListRecord: Everything for our model implementation. */
@ -65,9 +69,9 @@ struct _PacketList
{
GObject parent; /* MUST be first */
GPtrArray *rows; /* Dynamically allocated array of pointers to
* the PacketListRecord structure for each
* row. */
GPtrArray *visible_rows;
/* Array of pointers to the PacketListRecord structure for each row. */
GPtrArray *physical_rows;
gint n_columns;
/* Note: We need one extra column to store the entire PacketListRecord */
@ -77,8 +81,8 @@ struct _PacketList
gint sort_id;
GtkSortType sort_order;
gint stamp; /* Random integer to check whether an iter belongs to our
* model. */
/* Random integer to check whether an iter belongs to our model. */
gint stamp;
};
/* PacketListClass: more boilerplate GObject stuff */
@ -90,8 +94,9 @@ struct _PacketListClass
GType packet_list_list_get_type(void);
PacketList *new_packet_list_new(void);
void new_packet_list_store_clear(PacketList *packet_list);
void packet_list_recreate_visible_rows(PacketList *packet_list);
gboolean packet_list_visible_record(PacketList *packet_list, GtkTreeIter *iter);
void packet_list_append_record(PacketList *packet_list, row_data_t *row_data);
gint packet_list_append_record(PacketList *packet_list, row_data_t *row_data);
void packet_list_change_record(PacketList *packet_list, guint row, gint col, column_info *cinfo);
void packet_list_reset_dissected(PacketList *packet_list);
#endif /* NEW_PACKET_LIST */

View File

@ -63,6 +63,7 @@ extern void pipe_input_set_handler(gint source, gpointer user_data, int *child_p
#ifdef NEW_PACKET_LIST
void new_packet_list_clear(void);
void new_packet_list_freeze(void);
void new_packet_list_recreate_visible_rows(void);
void new_packet_list_thaw(void);
void new_packet_list_next(void);
void new_packet_list_prev(void);