1 /*
2  * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 package com.sun.hotspot.igv.view;
25 
26 import com.sun.hotspot.igv.data.InputGraph;
27 import com.sun.hotspot.igv.data.InputNode;
28 import com.sun.hotspot.igv.data.Properties;
29 import com.sun.hotspot.igv.data.Properties.RegexpPropertyMatcher;
30 import com.sun.hotspot.igv.data.services.InputGraphProvider;
31 import com.sun.hotspot.igv.util.LookupHistory;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.Set;
35 import java.util.regex.Pattern;
36 import org.netbeans.spi.quicksearch.SearchProvider;
37 import org.netbeans.spi.quicksearch.SearchRequest;
38 import org.netbeans.spi.quicksearch.SearchResponse;
39 import org.openide.DialogDisplayer;
40 import org.openide.NotifyDescriptor;
41 import org.openide.NotifyDescriptor.Message;
42 
43 /**
44  *
45  * @author Thomas Wuerthinger
46  */
47 public class NodeQuickSearch implements SearchProvider {
48 
49     private static final String DEFAULT_PROPERTY = "name";
50 
51     /**
52      * Method is called by infrastructure when search operation was requested.
53      * Implementors should evaluate given request and fill response object with
54      * apropriate results
55      *
56      * @param request Search request object that contains information what to search for
57      * @param response Search response object that stores search results. Note that it's important to react to return value of SearchResponse.addResult(...) method and stop computation if false value is returned.
58      */
59     @Override
evaluate(SearchRequest request, SearchResponse response)60     public void evaluate(SearchRequest request, SearchResponse response) {
61         String query = request.getText();
62         if (query.trim().isEmpty()) {
63             return;
64         }
65 
66         final String[] parts = query.split("=", 2);
67 
68         String name;
69         String value;
70 
71         if (parts.length == 1) {
72             name = DEFAULT_PROPERTY;
73             value = ".*" + Pattern.quote(parts[0]) + ".*";
74         } else {
75             name = parts[0];
76             value = parts[1];
77         }
78 
79         if (value.isEmpty()) {
80             value = ".*";
81         }
82 
83         final InputGraphProvider p = LookupHistory.getLast(InputGraphProvider.class);
84         if (p != null && p.getGraph() != null) {
85             InputGraph matchGraph = p.getGraph();
86             // Search the current graph
87             List<InputNode> matches = findMatches(name, value, p.getGraph(), response);
88             if (matches == null) {
89                 // See if the it hits in a later graph
90                 for (InputGraph graph : p.searchForward()) {
91                     matches = findMatches(name, value, graph, response);
92                     if (matches != null) {
93                         matchGraph = graph;
94                         break;
95                     }
96                 }
97             }
98             if (matches == null) {
99                 // See if it hits in a earlier graph
100                 for (InputGraph graph : p.searchBackward()) {
101                     matches = findMatches(name, value, graph, response);
102                     if (matches != null) {
103                         matchGraph = graph;
104                         break;
105                     }
106                 }
107             }
108 
109             if (matches != null) {
110                 final Set<InputNode> set = new HashSet<>(matches);
111                 final InputGraph theGraph = p.getGraph() != matchGraph ? matchGraph : null;
112                 response.addResult(new Runnable() {
113                     @Override
114                     public void run() {
115                         final EditorTopComponent comp = EditorTopComponent.getActive();
116                         if (comp != null) {
117                             if (theGraph != null) {
118                                 comp.getDiagramModel().selectGraph(theGraph);
119                             }
120                             comp.setSelectedNodes(set);
121                             comp.requestActive();
122                         }
123                     }
124                 },
125                         "All " + matches.size() + " matching nodes (" + name + "=" + value + ")" + (theGraph != null ? " in " + theGraph.getName() : "")
126                 );
127 
128                 // Single matches
129                 for (final InputNode n : matches) {
130                     response.addResult(new Runnable() {
131                         @Override
132                         public void run() {
133                             final EditorTopComponent comp = EditorTopComponent.getActive();
134                             if (comp != null) {
135                                 final Set<InputNode> tmpSet = new HashSet<>();
136                                 tmpSet.add(n);
137                                 if (theGraph != null) {
138                                     comp.getDiagramModel().selectGraph(theGraph);
139                                 }
140                                 comp.setSelectedNodes(tmpSet);
141                                 comp.requestActive();
142                             }
143                         }
144                     },
145                             n.getProperties().get(name) + " (" + n.getId() + " " + n.getProperties().get("name") + ")" + (theGraph != null ? " in " + theGraph.getName() : "")
146                     );
147                 }
148             }
149         } else {
150             System.out.println("no input graph provider!");
151         }
152     }
153 
findMatches(String name, String value, InputGraph inputGraph, SearchResponse response)154     private List<InputNode> findMatches(String name, String value, InputGraph inputGraph, SearchResponse response) {
155         try {
156             RegexpPropertyMatcher matcher = new RegexpPropertyMatcher(name, value, Pattern.CASE_INSENSITIVE);
157             Properties.PropertySelector<InputNode> selector = new Properties.PropertySelector<>(inputGraph.getNodes());
158             List<InputNode> matches = selector.selectMultiple(matcher);
159             return matches.size() == 0 ? null : matches;
160         } catch (Exception e) {
161             final String msg = e.getMessage();
162             response.addResult(new Runnable() {
163                 @Override
164                 public void run() {
165                     Message desc = new NotifyDescriptor.Message("An exception occurred during the search, "
166                             + "perhaps due to a malformed query string:\n" + msg,
167                             NotifyDescriptor.WARNING_MESSAGE);
168                     DialogDisplayer.getDefault().notify(desc);
169                 }
170             },
171                     "(Error during search)"
172             );
173         }
174         return null;
175     }
176 }
177