package org.simantics.scl.ui.outline; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.views.contentoutline.ContentOutlinePage; import org.simantics.scl.compiler.elaboration.modules.SCLValue; import org.simantics.scl.compiler.environment.filter.AcceptAllNamespaceFilter; import org.simantics.scl.compiler.errors.Failable; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.compiler.module.Module; import org.simantics.scl.compiler.module.repository.UpdateListener; import org.simantics.scl.compiler.source.ModuleSource; import org.simantics.scl.compiler.types.TCon; import org.simantics.scl.osgi.SCLOsgi; import org.simantics.scl.ui.Activator; import org.simantics.scl.ui.editor2.SCLModuleEditor2; import org.simantics.scl.ui.editor2.SCLModuleEditorInput; public class SCLModuleOutlinePage extends ContentOutlinePage { private TreeViewer outlineViewer; private SCLModuleEditor2 moduleEditor; private UpdateListener updateListener; private LocalResourceManager resourceManager; private Image publicImage; private Image privateImage; private Image typeImage; public SCLModuleOutlinePage(SCLModuleEditor2 moduleEditor) { this.moduleEditor = moduleEditor; resourceManager = new LocalResourceManager(JFaceResources.getResources()); publicImage = resourceManager .createImage(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/public_co.gif")); privateImage = resourceManager .createImage(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/private_co.gif")); typeImage = resourceManager .createImage(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/typedef_obj.gif")); } @Override public void createControl(Composite parent) { super.createControl(parent); outlineViewer = getTreeViewer(); SCLModuleOutlineProvider provider = new SCLModuleOutlineProvider(); DelegatingStyledCellLabelProvider labelProvider = new DelegatingStyledCellLabelProvider(provider); outlineViewer.setContentProvider(provider); outlineViewer.setLabelProvider(labelProvider); outlineViewer.addSelectionChangedListener(this); SCLModuleEditorInput input = (SCLModuleEditorInput) moduleEditor.getEditorInput(); ModuleSource moduleSource = input.getAdapter(ModuleSource.class); updateListener = new UpdateListener() { @Override public void notifyAboutUpdate() { parent.getDisplay().asyncExec(() -> { if (!outlineViewer.getControl().isDisposed()) { outlineViewer.refresh(); } }); } }; Failable module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleSource.getModuleName(), updateListener); Module result = module.getResult(); outlineViewer.setInput(result); } @Override public void selectionChanged(SelectionChangedEvent event) { super.selectionChanged(event); ISelection selection = event.getSelection(); TreeSelection tselection = (TreeSelection) selection; if (tselection.getFirstElement() instanceof SCLValue) { SCLValue value = (SCLValue) tselection.getFirstElement(); long location = value.definitionLocation; int begin = Locations.beginOf(location); int end = Locations.endOf(location); moduleEditor.selectAndReveal(begin, end - begin); } else { // TCon type = (TCon) tselection.getFirstElement(); // type.loction; // this is missing? } } @Override public void dispose() { resourceManager.dispose(); super.dispose(); } protected class SCLModuleOutlineProvider implements ITreeContentProvider, IStyledLabelProvider { @Override public Object[] getElements(Object inputElement) { Module result = (Module) inputElement; List values = new ArrayList<>(); result.findValuesForPrefix("", AcceptAllNamespaceFilter.INSTANCE, value -> { values.add(value); }); values.sort(new Comparator() { @Override public int compare(SCLValue o1, SCLValue o2) { int isPrivate = Boolean.compare(o1.isPrivate(), o2.isPrivate()); if (isPrivate != 0) return isPrivate; else return o1.getName().name.compareTo(o2.getName().name); } }); List types = new ArrayList<>(); result.findTypesForPrefix("", AcceptAllNamespaceFilter.INSTANCE, type -> { types.add(type); }); types.sort(new Comparator() { @Override public int compare(TCon o1, TCon o2) { return o1.name.compareTo(o2.name); } }); List results = new ArrayList<>(); results.addAll(types); results.addAll(values); return results.toArray(); } @Override public Object[] getChildren(Object parentElement) { return null; } @Override public Object getParent(Object element) { return null; } @Override public boolean hasChildren(Object element) { return false; } @Override public void addListener(ILabelProviderListener listener) { } @Override public boolean isLabelProperty(Object element, String property) { return false; } @Override public void removeListener(ILabelProviderListener listener) { } @Override public Image getImage(Object element) { if (element instanceof SCLValue) { SCLValue value = (SCLValue) element; if (value.isPrivate()) { return privateImage; } else { return publicImage; } } else if (element instanceof TCon) { return typeImage; } else { return null; } } @Override public void dispose() { ITreeContentProvider.super.dispose(); } @Override public StyledString getStyledText(Object element) { if (element instanceof SCLValue) { SCLValue value = (SCLValue) element; StyledString ss = new StyledString(value.getName().name); ss.append(" :: " + value.getType().toString(), StyledString.COUNTER_STYLER); return ss; } else { TCon type = (TCon) element; return new StyledString(type.name); } } } }