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
  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 
 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 }