diff options
author | Steven Rostedt <srostedt@redhat.com> | 2010-01-07 23:02:50 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2010-01-07 23:02:50 -0500 |
commit | 3c6228066478232d696fc7da7db2e1c7a3e29329 (patch) | |
tree | 1d16951cb1774dab2d4ace773b509595723162e0 | |
parent | 7b0139ebb1cfd673189c82ed565619480c1c3cf2 (diff) |
trace-view: Add search feature
Add a search feature to search for matches in the list rows.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | kernel-shark.c | 16 | ||||
-rw-r--r-- | trace-view-main.c | 13 | ||||
-rw-r--r-- | trace-view.c | 301 | ||||
-rw-r--r-- | trace-view.h | 2 |
4 files changed, 319 insertions, 13 deletions
diff --git a/kernel-shark.c b/kernel-shark.c index 720833b..b0d2a19 100644 --- a/kernel-shark.c +++ b/kernel-shark.c | |||
@@ -718,6 +718,18 @@ void kernel_shark(int argc, char **argv) | |||
718 | gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0); | 718 | gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0); |
719 | gtk_widget_show(spin); | 719 | gtk_widget_show(spin); |
720 | 720 | ||
721 | /* --- Search --- */ | ||
722 | |||
723 | /* The tree needs its columns loaded now */ | ||
724 | info->treeview = gtk_tree_view_new(); | ||
725 | trace_view_load(info->treeview, handle, spin); | ||
726 | |||
727 | label = gtk_label_new(" Search: "); | ||
728 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | ||
729 | gtk_widget_show(label); | ||
730 | |||
731 | trace_view_search_setup(GTK_BOX(hbox), GTK_TREE_VIEW(info->treeview)); | ||
732 | |||
721 | /* --- Top Level Trace View Paging Hbox --- */ | 733 | /* --- Top Level Trace View Paging Hbox --- */ |
722 | 734 | ||
723 | hbox = gtk_hbox_new(FALSE, 0); | 735 | hbox = gtk_hbox_new(FALSE, 0); |
@@ -734,13 +746,9 @@ void kernel_shark(int argc, char **argv) | |||
734 | 746 | ||
735 | /* --- Set up Trace Tree --- */ | 747 | /* --- Set up Trace Tree --- */ |
736 | 748 | ||
737 | info->treeview = gtk_tree_view_new(); | ||
738 | |||
739 | g_signal_connect(info->treeview, "row-activated", | 749 | g_signal_connect(info->treeview, "row-activated", |
740 | (GCallback)row_double_clicked, info); | 750 | (GCallback)row_double_clicked, info); |
741 | 751 | ||
742 | trace_view_load(info->treeview, handle, spin); | ||
743 | |||
744 | gtk_container_add(GTK_CONTAINER(scrollwin), info->treeview); | 752 | gtk_container_add(GTK_CONTAINER(scrollwin), info->treeview); |
745 | 753 | ||
746 | gtk_signal_connect(GTK_OBJECT(info->treeview), "button_press_event", | 754 | gtk_signal_connect(GTK_OBJECT(info->treeview), "button_press_event", |
diff --git a/trace-view-main.c b/trace-view-main.c index 122cda8..c728646 100644 --- a/trace-view-main.c +++ b/trace-view-main.c | |||
@@ -257,6 +257,17 @@ void trace_view(int argc, char **argv) | |||
257 | gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0); | 257 | gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0); |
258 | gtk_widget_show(spin); | 258 | gtk_widget_show(spin); |
259 | 259 | ||
260 | /* --- Search --- */ | ||
261 | |||
262 | /* The tree needs its columns loaded now */ | ||
263 | trace_view_load(trace_tree, handle, spin); | ||
264 | |||
265 | label = gtk_label_new(" Search: "); | ||
266 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | ||
267 | gtk_widget_show(label); | ||
268 | |||
269 | trace_view_search_setup(GTK_BOX(hbox), GTK_TREE_VIEW(trace_tree)); | ||
270 | |||
260 | /* --- Top Level Hbox --- */ | 271 | /* --- Top Level Hbox --- */ |
261 | 272 | ||
262 | hbox = gtk_hbox_new(FALSE, 0); | 273 | hbox = gtk_hbox_new(FALSE, 0); |
@@ -273,8 +284,6 @@ void trace_view(int argc, char **argv) | |||
273 | 284 | ||
274 | /* --- Set up Trace Tree --- */ | 285 | /* --- Set up Trace Tree --- */ |
275 | 286 | ||
276 | trace_view_load(trace_tree, handle, spin); | ||
277 | |||
278 | gtk_container_add(GTK_CONTAINER(scrollwin), trace_tree); | 287 | gtk_container_add(GTK_CONTAINER(scrollwin), trace_tree); |
279 | gtk_widget_show(trace_tree); | 288 | gtk_widget_show(trace_tree); |
280 | 289 | ||
diff --git a/trace-view.c b/trace-view.c index 8b98e48..90c01c7 100644 --- a/trace-view.c +++ b/trace-view.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * | 18 | * |
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
20 | */ | 20 | */ |
21 | #define _GNU_SOURCE | ||
21 | #include <stdio.h> | 22 | #include <stdio.h> |
22 | #include <string.h> | 23 | #include <string.h> |
23 | #include <stdarg.h> | 24 | #include <stdarg.h> |
@@ -306,10 +307,20 @@ void trace_view_update_filters(GtkWidget *treeview, | |||
306 | trace_view_select(treeview, time); | 307 | trace_view_select(treeview, time); |
307 | } | 308 | } |
308 | 309 | ||
310 | static void select_row_from_path(GtkTreeView *tree, GtkTreePath *path) | ||
311 | { | ||
312 | GtkTreeSelection *selection; | ||
313 | |||
314 | selection = gtk_tree_view_get_selection(tree); | ||
315 | gtk_tree_selection_select_path(selection, path); | ||
316 | |||
317 | /* finally, make it visible */ | ||
318 | gtk_tree_view_scroll_to_cell(tree, path, NULL, TRUE, 0.5, 0.0); | ||
319 | } | ||
320 | |||
309 | void trace_view_select(GtkWidget *treeview, guint64 time) | 321 | void trace_view_select(GtkWidget *treeview, guint64 time) |
310 | { | 322 | { |
311 | GtkTreeView *tree = GTK_TREE_VIEW(treeview); | 323 | GtkTreeView *tree = GTK_TREE_VIEW(treeview); |
312 | GtkTreeSelection *selection; | ||
313 | GtkTreeModel *model; | 324 | GtkTreeModel *model; |
314 | GtkTreePath *path; | 325 | GtkTreePath *path; |
315 | gint select_page, page; | 326 | gint select_page, page; |
@@ -351,12 +362,7 @@ void trace_view_select(GtkWidget *treeview, guint64 time) | |||
351 | snprintf(buf, 100, "%d", row); | 362 | snprintf(buf, 100, "%d", row); |
352 | printf("row = %s\n", buf); | 363 | printf("row = %s\n", buf); |
353 | path = gtk_tree_path_new_from_string(buf); | 364 | path = gtk_tree_path_new_from_string(buf); |
354 | 365 | select_row_from_path(tree, path); | |
355 | selection = gtk_tree_view_get_selection(tree); | ||
356 | gtk_tree_selection_select_path(selection, path); | ||
357 | |||
358 | /* finally, make it visible */ | ||
359 | gtk_tree_view_scroll_to_cell(tree, path, NULL, TRUE, 0.5, 0.0); | ||
360 | gtk_tree_path_free(path); | 366 | gtk_tree_path_free(path); |
361 | } | 367 | } |
362 | 368 | ||
@@ -461,3 +467,284 @@ void trace_view_cpu_filter_callback(gboolean accept, | |||
461 | gtk_tree_view_set_model(trace_tree, GTK_TREE_MODEL(store)); | 467 | gtk_tree_view_set_model(trace_tree, GTK_TREE_MODEL(store)); |
462 | g_object_unref(store); | 468 | g_object_unref(store); |
463 | } | 469 | } |
470 | |||
471 | static GtkTreeModel *create_col_model(GtkTreeView *treeview) | ||
472 | { | ||
473 | GtkListStore *store; | ||
474 | GtkTreeViewColumn *col; | ||
475 | GtkTreeIter iter; | ||
476 | const gchar *title; | ||
477 | int i; | ||
478 | |||
479 | store = gtk_list_store_new(1, G_TYPE_STRING); | ||
480 | |||
481 | i = 0; | ||
482 | col = gtk_tree_view_get_column(treeview, i++); | ||
483 | while (col) { | ||
484 | title = gtk_tree_view_column_get_title(col); | ||
485 | if (!title) | ||
486 | break; | ||
487 | |||
488 | gtk_list_store_append(store, &iter); | ||
489 | gtk_list_store_set(store, &iter, | ||
490 | 0, title, | ||
491 | -1); | ||
492 | |||
493 | col = gtk_tree_view_get_column(treeview, i++); | ||
494 | } | ||
495 | |||
496 | return GTK_TREE_MODEL(store); | ||
497 | } | ||
498 | |||
499 | struct search_info { | ||
500 | GtkTreeView *treeview; | ||
501 | GtkWidget *entry; | ||
502 | GtkWidget *selection; | ||
503 | GtkWidget *column; | ||
504 | }; | ||
505 | |||
506 | #define SELECTION_NAMES \ | ||
507 | C( contains, CONTAINS ), \ | ||
508 | C( full match, FULL_MATCH ), \ | ||
509 | C( does not have, NOT_IN ) | ||
510 | |||
511 | #undef C | ||
512 | #define C(a, b) #a | ||
513 | |||
514 | static gchar *select_names[] = { SELECTION_NAMES, NULL }; | ||
515 | |||
516 | #undef C | ||
517 | #define C(a, b) SEL_##b | ||
518 | |||
519 | enum select_options { SELECTION_NAMES }; | ||
520 | |||
521 | static gboolean test_int(gint val, gint search_val, enum select_options sel) | ||
522 | { | ||
523 | gint tens; | ||
524 | gboolean match = TRUE; | ||
525 | |||
526 | switch (sel) { | ||
527 | case SEL_NOT_IN: | ||
528 | match = FALSE; | ||
529 | case SEL_CONTAINS: | ||
530 | for (tens = 1; search_val / tens; tens *= 10) | ||
531 | ; | ||
532 | |||
533 | while (val) { | ||
534 | if (val - search_val == (val / tens) * tens) | ||
535 | return match; | ||
536 | val /= 10; | ||
537 | } | ||
538 | return !match; | ||
539 | |||
540 | case SEL_FULL_MATCH: | ||
541 | return search_val == val; | ||
542 | } | ||
543 | return FALSE; | ||
544 | } | ||
545 | |||
546 | static gboolean test_text(const gchar *text, const gchar *search_text, enum select_options sel) | ||
547 | { | ||
548 | gboolean match = TRUE; | ||
549 | |||
550 | switch (sel) { | ||
551 | case SEL_NOT_IN: | ||
552 | match = FALSE; | ||
553 | case SEL_CONTAINS: | ||
554 | |||
555 | text = strcasestr(text, search_text); | ||
556 | if (text) | ||
557 | return match; | ||
558 | return !match; | ||
559 | |||
560 | case SEL_FULL_MATCH: | ||
561 | return strcmp(text, search_text) == 0; | ||
562 | } | ||
563 | return FALSE; | ||
564 | } | ||
565 | |||
566 | static void search_tree(gpointer data) | ||
567 | { | ||
568 | struct search_info *info = data; | ||
569 | GtkTreePath *path; | ||
570 | GtkTreeViewColumn *col; | ||
571 | GtkTreeModel *model; | ||
572 | TraceViewStore *store; | ||
573 | GtkTreeIter iter; | ||
574 | GtkEntry *entry = GTK_ENTRY(info->entry); | ||
575 | GtkComboBox *col_combo = GTK_COMBO_BOX(info->column); | ||
576 | GtkComboBox *sel_combo = GTK_COMBO_BOX(info->selection); | ||
577 | const gchar *title; | ||
578 | gint val; | ||
579 | gchar *text = NULL; | ||
580 | const gchar *search_text; | ||
581 | gint col_num; | ||
582 | gint sel; | ||
583 | gint search_val; | ||
584 | gint start_row; | ||
585 | gboolean found = FALSE; | ||
586 | |||
587 | col_num = gtk_combo_box_get_active(col_combo); | ||
588 | sel = gtk_combo_box_get_active(sel_combo); | ||
589 | |||
590 | if (col_num >= TRACE_VIEW_STORE_N_COLUMNS) | ||
591 | return; | ||
592 | |||
593 | search_text = gtk_entry_get_text(entry); | ||
594 | if (!search_text || !strlen(search_text)) | ||
595 | return; | ||
596 | |||
597 | col = gtk_tree_view_get_column(info->treeview, col_num); | ||
598 | if (!col) | ||
599 | return; | ||
600 | |||
601 | title = gtk_tree_view_column_get_title(col); | ||
602 | if (!title) | ||
603 | return; | ||
604 | |||
605 | model = gtk_tree_view_get_model(info->treeview); | ||
606 | store = TRACE_VIEW_STORE(model); | ||
607 | |||
608 | if (!trace_view_store_visible_rows(store)) | ||
609 | return; | ||
610 | |||
611 | start_row = trace_view_get_selected_row(GTK_WIDGET(info->treeview)); | ||
612 | if (start_row < 0) | ||
613 | start_row = 0; | ||
614 | |||
615 | if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, start_row)) | ||
616 | return; | ||
617 | |||
618 | search_val = atoi(search_text); | ||
619 | while (gtk_tree_model_iter_next(model, &iter)) { | ||
620 | switch (col_num) { | ||
621 | case TRACE_VIEW_STORE_COL_INDEX: | ||
622 | case TRACE_VIEW_STORE_COL_CPU: | ||
623 | case TRACE_VIEW_STORE_COL_PID: | ||
624 | /* integers */ | ||
625 | |||
626 | gtk_tree_model_get(model, &iter, | ||
627 | col_num, &val, | ||
628 | -1); | ||
629 | if (test_int(val, search_val, sel)) | ||
630 | found = TRUE; | ||
631 | break; | ||
632 | |||
633 | case TRACE_VIEW_STORE_COL_TS: | ||
634 | case TRACE_VIEW_STORE_COL_COMM: | ||
635 | case TRACE_VIEW_STORE_COL_LAT: | ||
636 | case TRACE_VIEW_STORE_COL_EVENT: | ||
637 | case TRACE_VIEW_STORE_COL_INFO: | ||
638 | /* strings */ | ||
639 | |||
640 | gtk_tree_model_get(model, &iter, | ||
641 | col_num, &text, | ||
642 | -1); | ||
643 | |||
644 | if (test_text(text, search_text, sel)) | ||
645 | found = TRUE; | ||
646 | break; | ||
647 | } | ||
648 | |||
649 | if (found) | ||
650 | break; | ||
651 | } | ||
652 | |||
653 | |||
654 | if (!found) { | ||
655 | printf("NOT FOUND!\n"); | ||
656 | /* show pop up */ | ||
657 | return; | ||
658 | } | ||
659 | |||
660 | path = gtk_tree_model_get_path(model, &iter); | ||
661 | select_row_from_path(info->treeview, path); | ||
662 | gtk_tree_path_free(path); | ||
663 | } | ||
664 | |||
665 | void trace_view_search_setup(GtkBox *box, GtkTreeView *treeview) | ||
666 | { | ||
667 | GtkCellRenderer *renderer; | ||
668 | GtkListStore *store; | ||
669 | GtkTreeModel *model; | ||
670 | GtkTreeIter iter; | ||
671 | GtkWidget *label; | ||
672 | GtkWidget *col_combo; | ||
673 | GtkWidget *sel_combo; | ||
674 | GtkWidget *entry; | ||
675 | gchar **selects = select_names; | ||
676 | int i; | ||
677 | struct search_info *info; | ||
678 | |||
679 | renderer = gtk_cell_renderer_text_new(); | ||
680 | |||
681 | info = g_new0(typeof(*info), 1); | ||
682 | info->treeview = treeview; | ||
683 | |||
684 | label = gtk_label_new("Column: "); | ||
685 | gtk_box_pack_start(box, label, FALSE, FALSE, 0); | ||
686 | gtk_widget_show(label); | ||
687 | |||
688 | /* --- Set up the column selection combo box --- */ | ||
689 | |||
690 | model = create_col_model(treeview); | ||
691 | |||
692 | col_combo = gtk_combo_box_new_with_model(model); | ||
693 | gtk_box_pack_start(box, col_combo, FALSE, FALSE, 0); | ||
694 | gtk_widget_show(col_combo); | ||
695 | |||
696 | /* Free model with combobox */ | ||
697 | g_object_unref(model); | ||
698 | |||
699 | gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(col_combo), | ||
700 | renderer, | ||
701 | TRUE); | ||
702 | gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(col_combo), | ||
703 | renderer, | ||
704 | "text", 0, | ||
705 | NULL); | ||
706 | |||
707 | gtk_combo_box_set_active(GTK_COMBO_BOX(col_combo), 0); | ||
708 | |||
709 | info->column = col_combo; | ||
710 | |||
711 | /* --- Set up the column selection combo box --- */ | ||
712 | |||
713 | store = gtk_list_store_new(1, G_TYPE_STRING); | ||
714 | model = GTK_TREE_MODEL(store); | ||
715 | |||
716 | sel_combo = gtk_combo_box_new_with_model(model); | ||
717 | gtk_box_pack_start(box, sel_combo, FALSE, FALSE, 0); | ||
718 | gtk_widget_show(sel_combo); | ||
719 | |||
720 | info->selection = sel_combo; | ||
721 | |||
722 | gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(sel_combo), | ||
723 | renderer, | ||
724 | TRUE); | ||
725 | gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(sel_combo), | ||
726 | renderer, | ||
727 | "text", 0, | ||
728 | NULL); | ||
729 | |||
730 | for (i = 0; selects[i]; i++ ) { | ||
731 | gtk_list_store_append(store, &iter); | ||
732 | gtk_list_store_set(store, &iter, | ||
733 | 0, selects[i], | ||
734 | -1); | ||
735 | } | ||
736 | |||
737 | gtk_combo_box_set_active(GTK_COMBO_BOX(sel_combo), 0); | ||
738 | |||
739 | /* --- The text entry --- */ | ||
740 | |||
741 | entry = gtk_entry_new(); | ||
742 | gtk_box_pack_start(box, entry, FALSE, FALSE, 0); | ||
743 | gtk_widget_show(entry); | ||
744 | |||
745 | info->entry = entry; | ||
746 | |||
747 | g_signal_connect_swapped (entry, "activate", | ||
748 | G_CALLBACK (search_tree), | ||
749 | (gpointer) info); | ||
750 | } | ||
diff --git a/trace-view.h b/trace-view.h index b637d82..291fa0d 100644 --- a/trace-view.h +++ b/trace-view.h | |||
@@ -29,4 +29,6 @@ void trace_view_cpu_filter_callback(gboolean accept, | |||
29 | guint64 *selected_cpu_mask, | 29 | guint64 *selected_cpu_mask, |
30 | gpointer data); | 30 | gpointer data); |
31 | 31 | ||
32 | void trace_view_search_setup(GtkBox *box, GtkTreeView *treeview); | ||
33 | |||
32 | #endif /* _TRACE_VIEW_H */ | 34 | #endif /* _TRACE_VIEW_H */ |