1 package org.simantics.scl.ui.search;
3 import java.util.Collection;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Iterator;
8 import java.util.Map.Entry;
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.db.SCLExpressionTableEntry;
36 import org.simantics.scl.ui.editor2.OpenSCLDefinition;
37 import org.simantics.ui.workbench.action.DefaultActions;
39 public class SCLSearchResultPage extends AbstractTextSearchViewPage {
41 private SCLSearchResultContentProvider contentProvider;
43 public SCLSearchResultPage() {
47 protected void elementsChanged(Object[] objects) {
48 if (contentProvider != null)
49 contentProvider.elementsChanged(objects);
53 protected void clear() {
57 private static final ViewerComparator comparator = new ViewerComparator() {
59 public int compare(Viewer viewer, Object e1, Object e2) {
60 if (e1 instanceof SymbolReference && e2 instanceof SymbolReference) {
61 SymbolReference r1 = (SymbolReference)e1;
62 SymbolReference r2 = (SymbolReference)e2;
63 int c = r1.referrer.toString().compareTo(r2.referrer.toString());
67 return Integer.compare(Locations.beginOf(r1.referenceLocation), Locations.beginOf(r2.referenceLocation));
69 } else if (e1 instanceof SymbolReference && e2 instanceof SCLExpressionTableEntry) {
71 } else if (e2 instanceof SymbolReference && e1 instanceof SCLExpressionTableEntry) {
74 SCLExpressionTableEntry r1 = (SCLExpressionTableEntry)e1;
75 SCLExpressionTableEntry r2 = (SCLExpressionTableEntry)e2;
76 return r1.getContent().compareTo(r2.getContent());
82 protected void configureTreeViewer(TreeViewer viewer) {
83 viewer.setUseHashlookup(true);
84 contentProvider = new SCLSearchResultContentProvider(this);
85 viewer.setContentProvider(contentProvider);
86 viewer.setComparator(comparator);
87 viewer.setLabelProvider(contentProvider);
91 protected void configureTableViewer(TableViewer viewer) {
92 viewer.setUseHashlookup(true);
93 contentProvider = new SCLSearchResultContentProvider(this);
94 viewer.setContentProvider(contentProvider);
95 viewer.setComparator(comparator);
96 viewer.setLabelProvider(contentProvider);
100 protected void handleOpen(OpenEvent event) {
101 Object selection = ((StructuredSelection)event.getSelection()).getFirstElement();
102 if (selection != null) {
108 protected void showMatch(Match match, int currentOffset, int currentLength) throws PartInitException {
109 open(match.getElement());
112 private void open(Object selection) {
113 if (selection instanceof SymbolReference) {
114 SymbolReference reference = (SymbolReference) selection;
115 OpenSCLDefinition.scheduleOpenDefinition(reference.referrer.module, reference.referenceLocation);
116 } else if (selection instanceof SCLExpressionTableEntry) {
117 SCLExpressionTableEntry entry = (SCLExpressionTableEntry) selection;
118 DefaultActions.performDefaultAction(getControl().getDisplay().getActiveShell(), new StructuredSelection(entry.getResource()));
122 public static class SCLSearchResultContentProvider extends DecoratingStyledCellLabelProvider implements ITreeContentProvider, ILabelProvider {
124 private Map<Object, Set<Object>> fChildrenMap;
125 private AbstractTextSearchResult result;
126 private SCLSearchResultPage page;
128 public SCLSearchResultContentProvider(SCLSearchResultPage sclSearchResultPage) {
129 super(new SCLSearchResultLabelProvider(), PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator(), DecorationContext.DEFAULT_CONTEXT);
130 this.page = sclSearchResultPage;
134 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
135 initialize((AbstractTextSearchResult) newInput);
138 protected void initialize(AbstractTextSearchResult result) {
139 this.result = result;
140 fChildrenMap= new HashMap<>();
141 if (result != null) {
142 Object[] elements= result.getElements();
143 for (int i= 0; i < elements.length; i++) {
144 if (getPage().getDisplayedMatchCount(elements[i]) > 0) {
145 insert(null, null, elements[i]);
151 private AbstractTextSearchResult getSearchResult() {
155 public SCLSearchResultPage getPage() {
159 public void elementsChanged(Object[] updatedElements) {
160 if (getSearchResult() == null)
163 AbstractTreeViewer viewer= (AbstractTreeViewer) getPage().getViewer();
165 Set<Object> toRemove= new HashSet<>();
166 Set<Object> toUpdate= new HashSet<>();
167 Map<Object, Set<Object>> toAdd= new HashMap<>();
169 // TODO: Clear this for now at this point but probably this has some
170 // side-effects once nested children can be shown, never?
171 for (Entry<Object, Set<Object>> e : fChildrenMap.entrySet()) {
172 Collection<Object> refs = (Collection<Object>) e.getValue();
174 remove(toRemove, toUpdate, r);
179 for (int i= 0; i < updatedElements.length; i++) {
180 if (getPage().getDisplayedMatchCount(updatedElements[i]) > 0)
181 insert(toAdd, toUpdate, updatedElements[i]);
183 remove(toRemove, toUpdate, updatedElements[i]);
186 viewer.remove(toRemove.toArray());
187 for (Iterator<Object> iter= toAdd.keySet().iterator(); iter.hasNext();) {
188 Object parent= iter.next();
189 HashSet<Object> children= (HashSet<Object>) toAdd.get(parent);
190 viewer.add(parent, children.toArray());
192 for (Iterator<Object> elementsToUpdate= toUpdate.iterator(); elementsToUpdate.hasNext();) {
193 viewer.refresh(elementsToUpdate.next());
197 protected void insert(Map<Object, Set<Object>> toAdd, Set<Object> toUpdate, Object child) {
198 Object parent= getParent(child);
199 while (parent != null) {
200 if (insertChild(parent, child)) {
202 insertInto(parent, child, toAdd);
204 if (toUpdate != null)
205 toUpdate.add(parent);
209 parent= getParent(child);
211 if (insertChild(getSearchResult(), child)) {
213 insertInto(getSearchResult(), child, toAdd);
217 private boolean insertChild(Object parent, Object child) {
218 return insertInto(parent, child, fChildrenMap);
221 private boolean insertInto(Object parent, Object child, Map<Object, Set<Object>> map) {
222 Set<Object> children= map.get(parent);
223 if (children == null) {
224 children= new HashSet<>();
225 map.put(parent, children);
227 return children.add(child);
230 protected void remove(Set<Object> toRemove, Set<Object> toUpdate, Object element) {
231 // precondition here: fResult.getMatchCount(child) <= 0
233 if (hasChildren(element)) {
234 if (toUpdate != null)
235 toUpdate.add(element);
237 if (getPage().getDisplayedMatchCount(element) == 0) {
238 fChildrenMap.remove(element);
239 Object parent= getParent(element);
240 if (parent != null) {
241 if (removeFromSiblings(element, parent)) {
242 remove(toRemove, toUpdate, parent);
245 if (removeFromSiblings(element, getSearchResult())) {
246 if (toRemove != null)
247 toRemove.add(element);
251 if (toUpdate != null) {
252 toUpdate.add(element);
259 * Tries to remove the given element from the list of stored siblings.
261 * @param element potential child
262 * @param parent potential parent
263 * @return returns true if it really was a remove (i.e. element was a child of parent).
265 private boolean removeFromSiblings(Object element, Object parent) {
266 Set<Object> siblings= fChildrenMap.get(parent);
267 if (siblings != null) {
268 return siblings.remove(element);
275 public Object[] getElements(Object inputElement) {
276 return getChildren(inputElement);
280 public Object getParent(Object element) {
284 protected final Object[] EMPTY_ARR= new Object[0];
287 public Object[] getChildren(Object parentElement) {
288 Set<Object> children= fChildrenMap.get(parentElement);
289 if (children == null)
291 int limit= getPage().getElementLimit().intValue();
292 if (limit != -1 && limit < children.size()) {
293 Object[] limitedArray= new Object[limit];
294 Iterator<Object> iterator= children.iterator();
295 for (int i= 0; i < limit; i++) {
296 limitedArray[i]= iterator.next();
301 return children.toArray();
305 public boolean hasChildren(Object element) {
306 Set<Object> children= fChildrenMap.get(element);
307 return children != null && !children.isEmpty();
311 public String getText(Object element) {
312 if (element instanceof SymbolReference) {
313 SymbolReference ref = (SymbolReference) element;
314 return ref.referrer.toString();
315 } else if (element instanceof SCLExpressionTableEntry) {
316 SCLExpressionTableEntry entry = (SCLExpressionTableEntry) element;
317 return entry.getContent();
319 return "unsupported element " + String.valueOf(element); //$NON-NLS-1$
325 public static class SCLSearchResultLabelProvider implements ILabelProvider, IColorProvider, IStyledLabelProvider {
328 public void addListener(ILabelProviderListener listener) {
333 public void dispose() {
338 public boolean isLabelProperty(Object element, String property) {
343 public void removeListener(ILabelProviderListener listener) {
348 public StyledString getStyledText(Object element) {
349 return new StyledString(getText(element)); //+ " " + ref.referred + " " + ref.referenceLocation);
353 public Color getForeground(Object element) {
358 public Color getBackground(Object element) {
363 public Image getImage(Object element) {
368 public String getText(Object element) {
369 if (element instanceof SymbolReference) {
370 SymbolReference ref = (SymbolReference) element;
371 return ref.referrer.toString();
372 } else if (element instanceof SCLExpressionTableEntry) {
373 SCLExpressionTableEntry entry = (SCLExpressionTableEntry) element;
374 return entry.getContent();
376 return "unsupported element " + String.valueOf(element); //$NON-NLS-1$