1 package org.simantics.scl.ui.search;
3 import java.util.HashMap;
4 import java.util.HashSet;
5 import java.util.Iterator;
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;
37 public class SCLSearchResultPage extends AbstractTextSearchViewPage {
39 private SCLSearchResultContentProvider contentProvider;
41 public SCLSearchResultPage() {
45 protected void elementsChanged(Object[] objects) {
46 if (contentProvider != null)
47 contentProvider.elementsChanged(objects);
51 protected void clear() {
55 private static final ViewerComparator comparator = new ViewerComparator() {
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());
64 return Integer.compare(Locations.beginOf(r1.referenceLocation), Locations.beginOf(r2.referenceLocation));
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);
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);
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);
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);
102 public static class SCLSearchResultContentProvider extends DecoratingStyledCellLabelProvider implements ITreeContentProvider, ILabelProvider {
104 private Map<Object, Set<Object>> fChildrenMap;
105 private AbstractTextSearchResult result;
106 private SCLSearchResultPage page;
108 public SCLSearchResultContentProvider(SCLSearchResultPage sclSearchResultPage) {
109 super(new SCLSearchResultLabelProvider(), PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator(), DecorationContext.DEFAULT_CONTEXT);
110 this.page = sclSearchResultPage;
114 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
115 initialize((AbstractTextSearchResult) newInput);
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]);
131 private AbstractTextSearchResult getSearchResult() {
135 public SCLSearchResultPage getPage() {
139 public void elementsChanged(Object[] updatedElements) {
140 if (getSearchResult() == null)
143 AbstractTreeViewer viewer= (AbstractTreeViewer) getPage().getViewer();
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]);
152 remove(toRemove, toUpdate, updatedElements[i]);
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());
161 for (Iterator<Object> elementsToUpdate= toUpdate.iterator(); elementsToUpdate.hasNext();) {
162 viewer.refresh(elementsToUpdate.next());
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)) {
171 insertInto(parent, child, toAdd);
173 if (toUpdate != null)
174 toUpdate.add(parent);
178 parent= getParent(child);
180 if (insertChild(getSearchResult(), child)) {
182 insertInto(getSearchResult(), child, toAdd);
186 private boolean insertChild(Object parent, Object child) {
187 return insertInto(parent, child, fChildrenMap);
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);
196 return children.add(child);
199 protected void remove(Set<Object> toRemove, Set<Object> toUpdate, Object element) {
200 // precondition here: fResult.getMatchCount(child) <= 0
202 if (hasChildren(element)) {
203 if (toUpdate != null)
204 toUpdate.add(element);
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);
214 if (removeFromSiblings(element, getSearchResult())) {
215 if (toRemove != null)
216 toRemove.add(element);
220 if (toUpdate != null) {
221 toUpdate.add(element);
228 * Tries to remove the given element from the list of stored siblings.
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).
234 private boolean removeFromSiblings(Object element, Object parent) {
235 Set<Object> siblings= fChildrenMap.get(parent);
236 if (siblings != null) {
237 return siblings.remove(element);
244 public Object[] getElements(Object inputElement) {
245 return getChildren(inputElement);
249 public Object getParent(Object element) {
253 protected final Object[] EMPTY_ARR= new Object[0];
256 public Object[] getChildren(Object parentElement) {
257 Set<Object> children= fChildrenMap.get(parentElement);
258 if (children == null)
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();
270 return children.toArray();
274 public boolean hasChildren(Object element) {
275 Set<Object> children= fChildrenMap.get(element);
276 return children != null && !children.isEmpty();
280 public String getText(Object element) {
281 SymbolReference ref = (SymbolReference) element;
282 return ref.referrer.toString();
287 public static class SCLSearchResultLabelProvider implements ILabelProvider, IColorProvider, IStyledLabelProvider {
290 public void addListener(ILabelProviderListener listener) {
295 public void dispose() {
300 public boolean isLabelProperty(Object element, String property) {
305 public void removeListener(ILabelProviderListener listener) {
310 public StyledString getStyledText(Object element) {
311 SymbolReference ref = (SymbolReference) element;
312 return new StyledString(ref.referrer.toString()); //+ " " + ref.referred + " " + ref.referenceLocation);
316 public Color getForeground(Object element) {
321 public Color getBackground(Object element) {
326 public Image getImage(Object element) {
331 public String getText(Object element) {