1// Copyright (C) 2019 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import {searchSegment} from '../base/binary_search'; 16import {Actions} from '../common/actions'; 17import {toNs} from '../common/time'; 18 19import {globals} from './globals'; 20import {scrollToTrackAndTs} from './scroll_helper'; 21 22export function executeSearch(reverse = false) { 23 const state = globals.frontendLocalState; 24 const index = state.searchIndex; 25 const startNs = toNs(globals.frontendLocalState.visibleWindowTime.start); 26 const endNs = toNs(globals.frontendLocalState.visibleWindowTime.end); 27 const currentTs = globals.currentSearchResults.tsStarts[index]; 28 29 // If this is a new search or the currentTs is not in the viewport, 30 // select the first/last item in the viewport. 31 if (index === -1 || currentTs < startNs || currentTs > endNs) { 32 if (reverse) { 33 const [smaller,] = 34 searchSegment(globals.currentSearchResults.tsStarts, endNs); 35 globals.frontendLocalState.setSearchIndex(smaller); 36 } else { 37 const [, larger] = 38 searchSegment(globals.currentSearchResults.tsStarts, startNs); 39 globals.frontendLocalState.setSearchIndex(larger); 40 } 41 } else { 42 // If the currentTs is in the viewport, increment the index. 43 if (reverse) { 44 globals.frontendLocalState.setSearchIndex(Math.max(index - 1, 0)); 45 } else { 46 globals.frontendLocalState.setSearchIndex(Math.min( 47 index + 1, globals.currentSearchResults.sliceIds.length - 1)); 48 } 49 } 50 selectCurrentSearchResult(); 51 52 // TODO(taylori): If the user does a search before any other selection, 53 // the details panel will pop up when the search is executed. If the search 54 // result is behind where the details panel appears then it won't get scrolled 55 // to. This time delay is a workaround for this specific situation. 56 // A better solution will be a callback that allows something to happen on the 57 // first redraw after an Action is applied. 58 const delay = index === -1 ? 50 : 0; 59 setTimeout(() => moveViewportToCurrentSearch(), delay); 60} 61 62function moveViewportToCurrentSearch() { 63 const searchIndex = globals.frontendLocalState.searchIndex; 64 if (searchIndex === -1) return; 65 const currentTs = globals.currentSearchResults.tsStarts[searchIndex]; 66 const trackId = globals.currentSearchResults.trackIds[searchIndex]; 67 scrollToTrackAndTs(trackId, currentTs); 68} 69 70function selectCurrentSearchResult() { 71 const state = globals.frontendLocalState; 72 const searchIndex = state.searchIndex; 73 const source = globals.currentSearchResults.sources[searchIndex]; 74 const currentId = globals.currentSearchResults.sliceIds[searchIndex]; 75 const trackId = globals.currentSearchResults.trackIds[searchIndex]; 76 77 if (currentId === undefined) return; 78 79 if (source === 'cpu') { 80 globals.dispatch(Actions.selectSlice({id: currentId, trackId})); 81 } else { 82 // Search results only include slices from the slice table for now. 83 // When we include annotations we need to pass the correct table. 84 globals.dispatch( 85 Actions.selectChromeSlice({id: currentId, trackId, table: 'slice'})); 86 } 87} 88