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 */ |
