]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/search/SCLSearchResultPage.java
f38d8d539ead6f35c863b9c89bcb057c8ee02e53
[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.Collection;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Iterator;
7 import java.util.Map;
8 import java.util.Map.Entry;
9 import java.util.Set;
10
11 import org.eclipse.jface.viewers.AbstractTreeViewer;
12 import org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider;
13 import org.eclipse.jface.viewers.DecorationContext;
14 import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
15 import org.eclipse.jface.viewers.IColorProvider;
16 import org.eclipse.jface.viewers.ILabelProvider;
17 import org.eclipse.jface.viewers.ILabelProviderListener;
18 import org.eclipse.jface.viewers.ITreeContentProvider;
19 import org.eclipse.jface.viewers.OpenEvent;
20 import org.eclipse.jface.viewers.StructuredSelection;
21 import org.eclipse.jface.viewers.StyledString;
22 import org.eclipse.jface.viewers.TableViewer;
23 import org.eclipse.jface.viewers.TreeViewer;
24 import org.eclipse.jface.viewers.Viewer;
25 import org.eclipse.jface.viewers.ViewerComparator;
26 import org.eclipse.search.ui.text.AbstractTextSearchResult;
27 import org.eclipse.search.ui.text.AbstractTextSearchViewPage;
28 import org.eclipse.search.ui.text.Match;
29 import org.eclipse.swt.graphics.Color;
30 import org.eclipse.swt.graphics.Image;
31 import org.eclipse.ui.PartInitException;
32 import org.eclipse.ui.PlatformUI;
33 import org.simantics.scl.compiler.errors.Locations;
34 import org.simantics.scl.compiler.module.debug.SymbolReference;
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             
149             // TODO: Clear this for now at this point but probably this has some 
150             // side-effects once nested children can be shown, never?
151             for (Entry<Object, Set<Object>> e : fChildrenMap.entrySet()) {
152                 Collection<Object> refs = (Collection<Object>) e.getValue();
153                 refs.forEach(r -> {
154                     remove(toRemove, toUpdate, r);
155                 });
156             }
157             
158             
159             for (int i= 0; i < updatedElements.length; i++) {
160                 if (getPage().getDisplayedMatchCount(updatedElements[i]) > 0)
161                     insert(toAdd, toUpdate, updatedElements[i]);
162                 else
163                     remove(toRemove, toUpdate, updatedElements[i]);
164             }
165
166             viewer.remove(toRemove.toArray());
167             for (Iterator<Object> iter= toAdd.keySet().iterator(); iter.hasNext();) {
168                 Object parent= iter.next();
169                 HashSet<Object> children= (HashSet<Object>) toAdd.get(parent);
170                 viewer.add(parent, children.toArray());
171             }
172             for (Iterator<Object> elementsToUpdate= toUpdate.iterator(); elementsToUpdate.hasNext();) {
173                 viewer.refresh(elementsToUpdate.next());
174             }
175         }
176         
177         protected void insert(Map<Object, Set<Object>> toAdd, Set<Object> toUpdate, Object child) {
178             Object parent= getParent(child);
179             while (parent != null) {
180                 if (insertChild(parent, child)) {
181                     if (toAdd != null)
182                         insertInto(parent, child, toAdd);
183                 } else {
184                     if (toUpdate != null)
185                         toUpdate.add(parent);
186                     return;
187                 }
188                 child= parent;
189                 parent= getParent(child);
190             }
191             if (insertChild(getSearchResult(), child)) {
192                 if (toAdd != null)
193                     insertInto(getSearchResult(), child, toAdd);
194             }
195         }
196
197         private boolean insertChild(Object parent, Object child) {
198             return insertInto(parent, child, fChildrenMap);
199         }
200
201         private boolean insertInto(Object parent, Object child, Map<Object, Set<Object>> map) {
202             Set<Object> children= map.get(parent);
203             if (children == null) {
204                 children= new HashSet<>();
205                 map.put(parent, children);
206             }
207             return children.add(child);
208         }
209
210         protected void remove(Set<Object> toRemove, Set<Object> toUpdate, Object element) {
211             // precondition here:  fResult.getMatchCount(child) <= 0
212
213             if (hasChildren(element)) {
214                 if (toUpdate != null)
215                     toUpdate.add(element);
216             } else {
217                 if (getPage().getDisplayedMatchCount(element) == 0) {
218                     fChildrenMap.remove(element);
219                     Object parent= getParent(element);
220                     if (parent != null) {
221                         if (removeFromSiblings(element, parent)) {
222                             remove(toRemove, toUpdate, parent);
223                         }
224                     } else {
225                         if (removeFromSiblings(element, getSearchResult())) {
226                             if (toRemove != null)
227                                 toRemove.add(element);
228                         }
229                     }
230                 } else {
231                     if (toUpdate != null) {
232                         toUpdate.add(element);
233                     }
234                 }
235             }
236         }
237
238         /**
239          * Tries to remove the given element from the list of stored siblings.
240          * 
241          * @param element potential child
242          * @param parent potential parent
243          * @return returns true if it really was a remove (i.e. element was a child of parent).
244          */
245         private boolean removeFromSiblings(Object element, Object parent) {
246             Set<Object> siblings= fChildrenMap.get(parent);
247             if (siblings != null) {
248                 return siblings.remove(element);
249             } else {
250                 return false;
251             }
252         }
253         
254         @Override
255         public Object[] getElements(Object inputElement) {
256             return getChildren(inputElement);
257         }
258
259         @Override
260         public Object getParent(Object element) {
261             return null;
262         }
263
264         protected final Object[] EMPTY_ARR= new Object[0];
265         
266         @Override
267         public Object[] getChildren(Object parentElement) {
268             Set<Object> children= fChildrenMap.get(parentElement);
269             if (children == null)
270                 return EMPTY_ARR;
271             int limit= getPage().getElementLimit().intValue();
272             if (limit != -1 && limit < children.size()) {
273                 Object[] limitedArray= new Object[limit];
274                 Iterator<Object> iterator= children.iterator();
275                 for (int i= 0; i < limit; i++) {
276                     limitedArray[i]= iterator.next();
277                 }
278                 return limitedArray;
279             }
280
281             return children.toArray();
282         }
283
284         @Override
285         public boolean hasChildren(Object element) {
286             Set<Object> children= fChildrenMap.get(element);
287             return children != null && !children.isEmpty();
288         }
289
290         @Override
291         public String getText(Object element) {
292             SymbolReference ref = (SymbolReference) element;
293             return ref.referrer.toString();
294         }
295
296     }
297     
298     public static class SCLSearchResultLabelProvider implements ILabelProvider, IColorProvider, IStyledLabelProvider {
299
300         @Override
301         public void addListener(ILabelProviderListener listener) {
302             
303         }
304
305         @Override
306         public void dispose() {
307             
308         }
309
310         @Override
311         public boolean isLabelProperty(Object element, String property) {
312             return true;
313         }
314
315         @Override
316         public void removeListener(ILabelProviderListener listener) {
317             
318         }
319
320         @Override
321         public StyledString getStyledText(Object element) {
322             SymbolReference ref = (SymbolReference) element;
323             return new StyledString(ref.referrer.toString()); //+ " " + ref.referred + " " + ref.referenceLocation);
324         }
325
326         @Override
327         public Color getForeground(Object element) {
328             return null;
329         }
330
331         @Override
332         public Color getBackground(Object element) {
333             return null;
334         }
335
336         @Override
337         public Image getImage(Object element) {
338             return null;
339         }
340
341         @Override
342         public String getText(Object element) {
343             return null;
344         }
345         
346     }
347 }