]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/search/SCLSearchResultPage.java
List SCL references in order of reference location in search results
[simantics/platform.git] / bundles / org.simantics.scl.ui / src / org / simantics / scl / ui / search / SCLSearchResultPage.java
1 package org.simantics.scl.ui.search;
2
3 import java.util.HashMap;
4 import java.util.HashSet;
5 import java.util.Iterator;
6 import java.util.Map;
7 import java.util.Set;
8
9 import org.eclipse.jface.viewers.AbstractTreeViewer;
10 import org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider;
11 import org.eclipse.jface.viewers.DecorationContext;
12 import org.eclipse.jface.viewers.IBaseLabelProvider;
13 import org.eclipse.jface.viewers.IColorProvider;
14 import org.eclipse.jface.viewers.ILabelProvider;
15 import org.eclipse.jface.viewers.ILabelProviderListener;
16 import org.eclipse.jface.viewers.ITreeContentProvider;
17 import org.eclipse.jface.viewers.OpenEvent;
18 import org.eclipse.jface.viewers.StructuredSelection;
19 import org.eclipse.jface.viewers.StyledString;
20 import org.eclipse.jface.viewers.TableViewer;
21 import org.eclipse.jface.viewers.TreeViewer;
22 import org.eclipse.jface.viewers.Viewer;
23 import org.eclipse.jface.viewers.ViewerComparator;
24 import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
25 import org.eclipse.search.ui.text.AbstractTextSearchResult;
26 import org.eclipse.search.ui.text.AbstractTextSearchViewPage;
27 import org.eclipse.search.ui.text.Match;
28 import org.eclipse.swt.graphics.Color;
29 import org.eclipse.swt.graphics.Image;
30 import org.eclipse.ui.PartInitException;
31 import org.eclipse.ui.PlatformUI;
32 import org.simantics.scl.compiler.errors.Locations;
33 import org.simantics.scl.compiler.module.debug.SymbolReference;
34 import org.simantics.scl.ui.editor2.OpenDeclaration;
35 import org.simantics.scl.ui.editor2.OpenSCLDefinition;
36
37 public class SCLSearchResultPage extends AbstractTextSearchViewPage {
38
39     private SCLSearchResultContentProvider contentProvider;
40
41     public SCLSearchResultPage() {
42         setElementLimit(-1);
43     }
44     @Override
45     protected void elementsChanged(Object[] objects) {
46         if (contentProvider != null)
47             contentProvider.elementsChanged(objects);
48     }
49
50     @Override
51     protected void clear() {
52
53     }
54
55     private static final ViewerComparator comparator = new ViewerComparator() {
56         @Override
57         public int compare(Viewer viewer, Object e1, Object e2) {
58             SymbolReference r1 = (SymbolReference)e1;
59             SymbolReference r2 = (SymbolReference)e2;
60             int c = r1.referrer.toString().compareTo(r2.referrer.toString());
61             if (c != 0) {
62                 return c;
63             } else {
64                 return Integer.compare(Locations.beginOf(r1.referenceLocation), Locations.beginOf(r2.referenceLocation));
65             }
66         }
67     };
68
69     @Override
70     protected void configureTreeViewer(TreeViewer viewer) {
71         viewer.setUseHashlookup(true);
72         contentProvider = new SCLSearchResultContentProvider(this);
73         viewer.setContentProvider(contentProvider);
74         viewer.setComparator(comparator);
75         viewer.setLabelProvider(contentProvider);
76     }
77
78     @Override
79     protected void configureTableViewer(TableViewer viewer) {
80         viewer.setUseHashlookup(true);
81         contentProvider = new SCLSearchResultContentProvider(this);
82         viewer.setContentProvider(contentProvider);
83         viewer.setComparator(comparator);
84         viewer.setLabelProvider(contentProvider);
85     }
86     
87     @Override
88     protected void handleOpen(OpenEvent event) {
89         Object selection = ((StructuredSelection)event.getSelection()).getFirstElement();
90         if (selection != null) {
91             SymbolReference reference = (SymbolReference) selection;
92             OpenSCLDefinition.openDefinition(reference.referrer.module, reference.referenceLocation);
93         }
94     }
95     
96     @Override
97     protected void showMatch(Match match, int currentOffset, int currentLength) throws PartInitException {
98         SymbolReference reference = (SymbolReference) match.getElement();
99         OpenSCLDefinition.openDefinition(reference.referrer.module, reference.referenceLocation);
100     }
101
102     public static class SCLSearchResultContentProvider extends DecoratingStyledCellLabelProvider implements ITreeContentProvider, ILabelProvider {
103         
104         private Map<Object, Set<Object>> fChildrenMap;
105         private AbstractTextSearchResult result;
106         private SCLSearchResultPage page;
107
108         public SCLSearchResultContentProvider(SCLSearchResultPage sclSearchResultPage) {
109             super(new SCLSearchResultLabelProvider(), PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator(), DecorationContext.DEFAULT_CONTEXT);
110             this.page = sclSearchResultPage;
111         }
112
113         @Override
114         public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
115             initialize((AbstractTextSearchResult) newInput);
116         }
117
118         protected void initialize(AbstractTextSearchResult result) {
119             this.result = result;
120             fChildrenMap= new HashMap<>();
121             if (result != null) {
122                 Object[] elements= result.getElements();
123                 for (int i= 0; i < elements.length; i++) {
124                     if (getPage().getDisplayedMatchCount(elements[i]) > 0) {
125                         insert(null, null, elements[i]);
126                     }
127                 }
128             }
129         }
130
131         private AbstractTextSearchResult getSearchResult() {
132             return result;
133         }
134         
135         public SCLSearchResultPage getPage() {
136             return page;
137         }
138
139         public void elementsChanged(Object[] updatedElements) {
140             if (getSearchResult() == null)
141                 return;
142             
143             AbstractTreeViewer viewer= (AbstractTreeViewer) getPage().getViewer();
144
145             Set<Object> toRemove= new HashSet<>();
146             Set<Object> toUpdate= new HashSet<>();
147             Map<Object, Set<Object>> toAdd= new HashMap<>();
148             for (int i= 0; i < updatedElements.length; i++) {
149                 if (getPage().getDisplayedMatchCount(updatedElements[i]) > 0)
150                     insert(toAdd, toUpdate, updatedElements[i]);
151                 else
152                     remove(toRemove, toUpdate, updatedElements[i]);
153             }
154
155             viewer.remove(toRemove.toArray());
156             for (Iterator<Object> iter= toAdd.keySet().iterator(); iter.hasNext();) {
157                 Object parent= iter.next();
158                 HashSet<Object> children= (HashSet<Object>) toAdd.get(parent);
159                 viewer.add(parent, children.toArray());
160             }
161             for (Iterator<Object> elementsToUpdate= toUpdate.iterator(); elementsToUpdate.hasNext();) {
162                 viewer.refresh(elementsToUpdate.next());
163             }
164         }
165         
166         protected void insert(Map<Object, Set<Object>> toAdd, Set<Object> toUpdate, Object child) {
167             Object parent= getParent(child);
168             while (parent != null) {
169                 if (insertChild(parent, child)) {
170                     if (toAdd != null)
171                         insertInto(parent, child, toAdd);
172                 } else {
173                     if (toUpdate != null)
174                         toUpdate.add(parent);
175                     return;
176                 }
177                 child= parent;
178                 parent= getParent(child);
179             }
180             if (insertChild(getSearchResult(), child)) {
181                 if (toAdd != null)
182                     insertInto(getSearchResult(), child, toAdd);
183             }
184         }
185
186         private boolean insertChild(Object parent, Object child) {
187             return insertInto(parent, child, fChildrenMap);
188         }
189
190         private boolean insertInto(Object parent, Object child, Map<Object, Set<Object>> map) {
191             Set<Object> children= map.get(parent);
192             if (children == null) {
193                 children= new HashSet<>();
194                 map.put(parent, children);
195             }
196             return children.add(child);
197         }
198
199         protected void remove(Set<Object> toRemove, Set<Object> toUpdate, Object element) {
200             // precondition here:  fResult.getMatchCount(child) <= 0
201
202             if (hasChildren(element)) {
203                 if (toUpdate != null)
204                     toUpdate.add(element);
205             } else {
206                 if (getPage().getDisplayedMatchCount(element) == 0) {
207                     fChildrenMap.remove(element);
208                     Object parent= getParent(element);
209                     if (parent != null) {
210                         if (removeFromSiblings(element, parent)) {
211                             remove(toRemove, toUpdate, parent);
212                         }
213                     } else {
214                         if (removeFromSiblings(element, getSearchResult())) {
215                             if (toRemove != null)
216                                 toRemove.add(element);
217                         }
218                     }
219                 } else {
220                     if (toUpdate != null) {
221                         toUpdate.add(element);
222                     }
223                 }
224             }
225         }
226
227         /**
228          * Tries to remove the given element from the list of stored siblings.
229          * 
230          * @param element potential child
231          * @param parent potential parent
232          * @return returns true if it really was a remove (i.e. element was a child of parent).
233          */
234         private boolean removeFromSiblings(Object element, Object parent) {
235             Set<Object> siblings= fChildrenMap.get(parent);
236             if (siblings != null) {
237                 return siblings.remove(element);
238             } else {
239                 return false;
240             }
241         }
242         
243         @Override
244         public Object[] getElements(Object inputElement) {
245             return getChildren(inputElement);
246         }
247
248         @Override
249         public Object getParent(Object element) {
250             return null;
251         }
252
253         protected final Object[] EMPTY_ARR= new Object[0];
254         
255         @Override
256         public Object[] getChildren(Object parentElement) {
257             Set<Object> children= fChildrenMap.get(parentElement);
258             if (children == null)
259                 return EMPTY_ARR;
260             int limit= getPage().getElementLimit().intValue();
261             if (limit != -1 && limit < children.size()) {
262                 Object[] limitedArray= new Object[limit];
263                 Iterator<Object> iterator= children.iterator();
264                 for (int i= 0; i < limit; i++) {
265                     limitedArray[i]= iterator.next();
266                 }
267                 return limitedArray;
268             }
269
270             return children.toArray();
271         }
272
273         @Override
274         public boolean hasChildren(Object element) {
275             Set<Object> children= fChildrenMap.get(element);
276             return children != null && !children.isEmpty();
277         }
278
279         @Override
280         public String getText(Object element) {
281             SymbolReference ref = (SymbolReference) element;
282             return ref.referrer.toString();
283         }
284
285     }
286     
287     public static class SCLSearchResultLabelProvider implements ILabelProvider, IColorProvider, IStyledLabelProvider {
288
289         @Override
290         public void addListener(ILabelProviderListener listener) {
291             
292         }
293
294         @Override
295         public void dispose() {
296             
297         }
298
299         @Override
300         public boolean isLabelProperty(Object element, String property) {
301             return true;
302         }
303
304         @Override
305         public void removeListener(ILabelProviderListener listener) {
306             
307         }
308
309         @Override
310         public StyledString getStyledText(Object element) {
311             SymbolReference ref = (SymbolReference) element;
312             return new StyledString(ref.referrer.toString()); //+ " " + ref.referred + " " + ref.referenceLocation);
313         }
314
315         @Override
316         public Color getForeground(Object element) {
317             return null;
318         }
319
320         @Override
321         public Color getBackground(Object element) {
322             return null;
323         }
324
325         @Override
326         public Image getImage(Object element) {
327             return null;
328         }
329
330         @Override
331         public String getText(Object element) {
332             return null;
333         }
334         
335     }
336 }