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.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.scheduleOpenDefinition(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<>();
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();
154 remove(toRemove, toUpdate, r);
159 for (int i= 0; i < updatedElements.length; i++) {
160 if (getPage().getDisplayedMatchCount(updatedElements[i]) > 0)
161 insert(toAdd, toUpdate, updatedElements[i]);
163 remove(toRemove, toUpdate, updatedElements[i]);
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());
172 for (Iterator<Object> elementsToUpdate= toUpdate.iterator(); elementsToUpdate.hasNext();) {
173 viewer.refresh(elementsToUpdate.next());
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)) {
182 insertInto(parent, child, toAdd);
184 if (toUpdate != null)
185 toUpdate.add(parent);
189 parent= getParent(child);
191 if (insertChild(getSearchResult(), child)) {
193 insertInto(getSearchResult(), child, toAdd);
197 private boolean insertChild(Object parent, Object child) {
198 return insertInto(parent, child, fChildrenMap);
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);
207 return children.add(child);
210 protected void remove(Set<Object> toRemove, Set<Object> toUpdate, Object element) {
211 // precondition here: fResult.getMatchCount(child) <= 0
213 if (hasChildren(element)) {
214 if (toUpdate != null)
215 toUpdate.add(element);
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);
225 if (removeFromSiblings(element, getSearchResult())) {
226 if (toRemove != null)
227 toRemove.add(element);
231 if (toUpdate != null) {
232 toUpdate.add(element);
239 * Tries to remove the given element from the list of stored siblings.
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).
245 private boolean removeFromSiblings(Object element, Object parent) {
246 Set<Object> siblings= fChildrenMap.get(parent);
247 if (siblings != null) {
248 return siblings.remove(element);
255 public Object[] getElements(Object inputElement) {
256 return getChildren(inputElement);
260 public Object getParent(Object element) {
264 protected final Object[] EMPTY_ARR= new Object[0];
267 public Object[] getChildren(Object parentElement) {
268 Set<Object> children= fChildrenMap.get(parentElement);
269 if (children == null)
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();
281 return children.toArray();
285 public boolean hasChildren(Object element) {
286 Set<Object> children= fChildrenMap.get(element);
287 return children != null && !children.isEmpty();
291 public String getText(Object element) {
292 SymbolReference ref = (SymbolReference) element;
293 return ref.referrer.toString();
298 public static class SCLSearchResultLabelProvider implements ILabelProvider, IColorProvider, IStyledLabelProvider {
301 public void addListener(ILabelProviderListener listener) {
306 public void dispose() {
311 public boolean isLabelProperty(Object element, String property) {
316 public void removeListener(ILabelProviderListener listener) {
321 public StyledString getStyledText(Object element) {
322 SymbolReference ref = (SymbolReference) element;
323 return new StyledString(ref.referrer.toString()); //+ " " + ref.referred + " " + ref.referenceLocation);
327 public Color getForeground(Object element) {
332 public Color getBackground(Object element) {
337 public Image getImage(Object element) {
342 public String getText(Object element) {