]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/search/SCLSearchResultPage.java
Find SCL references in SCLModuleEditor with Ctrl+Shift+G
[simantics/platform.git] / bundles / org.simantics.scl.ui / src / org / simantics / scl / ui / search / SCLSearchResultPage.java
diff --git a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/search/SCLSearchResultPage.java b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/search/SCLSearchResultPage.java
new file mode 100644 (file)
index 0000000..ebc2cbf
--- /dev/null
@@ -0,0 +1,323 @@
+package org.simantics.scl.ui.search;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider;
+import org.eclipse.jface.viewers.DecorationContext;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.OpenEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
+import org.eclipse.search.ui.text.AbstractTextSearchResult;
+import org.eclipse.search.ui.text.AbstractTextSearchViewPage;
+import org.eclipse.search.ui.text.Match;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.simantics.scl.compiler.module.debug.SymbolReference;
+import org.simantics.scl.ui.editor2.OpenDeclaration;
+import org.simantics.scl.ui.editor2.OpenSCLDefinition;
+
+public class SCLSearchResultPage extends AbstractTextSearchViewPage {
+
+    private SCLSearchResultContentProvider contentProvider;
+
+    public SCLSearchResultPage() {
+        setElementLimit(-1);
+    }
+    @Override
+    protected void elementsChanged(Object[] objects) {
+        if (contentProvider != null)
+            contentProvider.elementsChanged(objects);
+    }
+
+    @Override
+    protected void clear() {
+
+    }
+
+    private static final ViewerComparator comparator = new ViewerComparator((o1, o2) -> o1.compareTo(o2));
+
+    @Override
+    protected void configureTreeViewer(TreeViewer viewer) {
+        viewer.setUseHashlookup(true);
+        contentProvider = new SCLSearchResultContentProvider(this);
+        viewer.setContentProvider(contentProvider);
+        viewer.setComparator(comparator);
+        viewer.setLabelProvider(contentProvider);
+    }
+
+    @Override
+    protected void configureTableViewer(TableViewer viewer) {
+        viewer.setUseHashlookup(true);
+        contentProvider = new SCLSearchResultContentProvider(this);
+        viewer.setContentProvider(contentProvider);
+        viewer.setComparator(comparator);
+        viewer.setLabelProvider(contentProvider);
+    }
+    
+    @Override
+    protected void handleOpen(OpenEvent event) {
+        Object selection = ((StructuredSelection)event.getSelection()).getFirstElement();
+        if (selection != null) {
+            SymbolReference reference = (SymbolReference) selection;
+            OpenSCLDefinition.openDefinition(reference.referrer.module, reference.referenceLocation);
+        }
+    }
+    
+    @Override
+    protected void showMatch(Match match, int currentOffset, int currentLength) throws PartInitException {
+        SymbolReference reference = (SymbolReference) match.getElement();
+        OpenSCLDefinition.openDefinition(reference.referrer.module, reference.referenceLocation);
+    }
+
+    public static class SCLSearchResultContentProvider extends DecoratingStyledCellLabelProvider implements ITreeContentProvider, ILabelProvider {
+        
+        private Map<Object, Set<Object>> fChildrenMap;
+        private AbstractTextSearchResult result;
+        private SCLSearchResultPage page;
+
+        public SCLSearchResultContentProvider(SCLSearchResultPage sclSearchResultPage) {
+            super(new SCLSearchResultLabelProvider(), PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator(), DecorationContext.DEFAULT_CONTEXT);
+            this.page = sclSearchResultPage;
+        }
+
+        @Override
+        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+            initialize((AbstractTextSearchResult) newInput);
+        }
+
+        protected void initialize(AbstractTextSearchResult result) {
+            this.result = result;
+            fChildrenMap= new HashMap<>();
+            if (result != null) {
+                Object[] elements= result.getElements();
+                for (int i= 0; i < elements.length; i++) {
+                    if (getPage().getDisplayedMatchCount(elements[i]) > 0) {
+                        insert(null, null, elements[i]);
+                    }
+                }
+            }
+        }
+
+        private AbstractTextSearchResult getSearchResult() {
+            return result;
+        }
+        
+        public SCLSearchResultPage getPage() {
+            return page;
+        }
+
+        public void elementsChanged(Object[] updatedElements) {
+            if (getSearchResult() == null)
+                return;
+            
+            AbstractTreeViewer viewer= (AbstractTreeViewer) getPage().getViewer();
+
+            Set<Object> toRemove= new HashSet<>();
+            Set<Object> toUpdate= new HashSet<>();
+            Map<Object, Set<Object>> toAdd= new HashMap<>();
+            for (int i= 0; i < updatedElements.length; i++) {
+                if (getPage().getDisplayedMatchCount(updatedElements[i]) > 0)
+                    insert(toAdd, toUpdate, updatedElements[i]);
+                else
+                    remove(toRemove, toUpdate, updatedElements[i]);
+            }
+
+            viewer.remove(toRemove.toArray());
+            for (Iterator<Object> iter= toAdd.keySet().iterator(); iter.hasNext();) {
+                Object parent= iter.next();
+                HashSet<Object> children= (HashSet<Object>) toAdd.get(parent);
+                viewer.add(parent, children.toArray());
+            }
+            for (Iterator<Object> elementsToUpdate= toUpdate.iterator(); elementsToUpdate.hasNext();) {
+                viewer.refresh(elementsToUpdate.next());
+            }
+        }
+        
+        protected void insert(Map<Object, Set<Object>> toAdd, Set<Object> toUpdate, Object child) {
+            Object parent= getParent(child);
+            while (parent != null) {
+                if (insertChild(parent, child)) {
+                    if (toAdd != null)
+                        insertInto(parent, child, toAdd);
+                } else {
+                    if (toUpdate != null)
+                        toUpdate.add(parent);
+                    return;
+                }
+                child= parent;
+                parent= getParent(child);
+            }
+            if (insertChild(getSearchResult(), child)) {
+                if (toAdd != null)
+                    insertInto(getSearchResult(), child, toAdd);
+            }
+        }
+
+        private boolean insertChild(Object parent, Object child) {
+            return insertInto(parent, child, fChildrenMap);
+        }
+
+        private boolean insertInto(Object parent, Object child, Map<Object, Set<Object>> map) {
+            Set<Object> children= map.get(parent);
+            if (children == null) {
+                children= new HashSet<>();
+                map.put(parent, children);
+            }
+            return children.add(child);
+        }
+
+        protected void remove(Set<Object> toRemove, Set<Object> toUpdate, Object element) {
+            // precondition here:  fResult.getMatchCount(child) <= 0
+
+            if (hasChildren(element)) {
+                if (toUpdate != null)
+                    toUpdate.add(element);
+            } else {
+                if (getPage().getDisplayedMatchCount(element) == 0) {
+                    fChildrenMap.remove(element);
+                    Object parent= getParent(element);
+                    if (parent != null) {
+                        if (removeFromSiblings(element, parent)) {
+                            remove(toRemove, toUpdate, parent);
+                        }
+                    } else {
+                        if (removeFromSiblings(element, getSearchResult())) {
+                            if (toRemove != null)
+                                toRemove.add(element);
+                        }
+                    }
+                } else {
+                    if (toUpdate != null) {
+                        toUpdate.add(element);
+                    }
+                }
+            }
+        }
+
+        /**
+         * Tries to remove the given element from the list of stored siblings.
+         * 
+         * @param element potential child
+         * @param parent potential parent
+         * @return returns true if it really was a remove (i.e. element was a child of parent).
+         */
+        private boolean removeFromSiblings(Object element, Object parent) {
+            Set<Object> siblings= fChildrenMap.get(parent);
+            if (siblings != null) {
+                return siblings.remove(element);
+            } else {
+                return false;
+            }
+        }
+        
+        @Override
+        public Object[] getElements(Object inputElement) {
+            return getChildren(inputElement);
+        }
+
+        @Override
+        public Object getParent(Object element) {
+            return null;
+        }
+
+        protected final Object[] EMPTY_ARR= new Object[0];
+        
+        @Override
+        public Object[] getChildren(Object parentElement) {
+            Set<Object> children= fChildrenMap.get(parentElement);
+            if (children == null)
+                return EMPTY_ARR;
+            int limit= getPage().getElementLimit().intValue();
+            if (limit != -1 && limit < children.size()) {
+                Object[] limitedArray= new Object[limit];
+                Iterator<Object> iterator= children.iterator();
+                for (int i= 0; i < limit; i++) {
+                    limitedArray[i]= iterator.next();
+                }
+                return limitedArray;
+            }
+
+            return children.toArray();
+        }
+
+        @Override
+        public boolean hasChildren(Object element) {
+            Set<Object> children= fChildrenMap.get(element);
+            return children != null && !children.isEmpty();
+        }
+
+        @Override
+        public String getText(Object element) {
+            SymbolReference ref = (SymbolReference) element;
+            return ref.referrer.toString();
+        }
+
+    }
+    
+    public static class SCLSearchResultLabelProvider implements ILabelProvider, IColorProvider, IStyledLabelProvider {
+
+        @Override
+        public void addListener(ILabelProviderListener listener) {
+            
+        }
+
+        @Override
+        public void dispose() {
+            
+        }
+
+        @Override
+        public boolean isLabelProperty(Object element, String property) {
+            return true;
+        }
+
+        @Override
+        public void removeListener(ILabelProviderListener listener) {
+            
+        }
+
+        @Override
+        public StyledString getStyledText(Object element) {
+            SymbolReference ref = (SymbolReference) element;
+            return new StyledString(ref.referrer.toString()); //+ " " + ref.referred + " " + ref.referenceLocation);
+        }
+
+        @Override
+        public Color getForeground(Object element) {
+            return null;
+        }
+
+        @Override
+        public Color getBackground(Object element) {
+            return null;
+        }
+
+        @Override
+        public Image getImage(Object element) {
+            return null;
+        }
+
+        @Override
+        public String getText(Object element) {
+            return null;
+        }
+        
+    }
+}