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