/******************************************************************************* * Copyright (c) 2015 Bruno Medeiros and other Contributors. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package melnorme.lang.ide.ui.editor.structure; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.part.IShowInTarget; import org.eclipse.ui.part.ShowInContext; import melnorme.lang.ide.ui.views.StructureElementLabelProvider; import melnorme.lang.tooling.structure.SourceFileStructure; import melnorme.lang.tooling.structure.StructureElement; import melnorme.utilbox.core.CommonException; import melnorme.utilbox.fields.FieldValueListener.FieldChangeListener; import melnorme.utilbox.ownership.IDisposable; import melnorme.utilbox.status.Severity; public class LangOutlinePage extends AbstractContentOutlinePage implements IAdaptable, IDisposable { protected final AbstractLangStructureEditor editor; public LangOutlinePage(AbstractLangStructureEditor editor) { super(); this.editor = editor; } /** * Note: createControl/dispose can be called multiple times per receiver lifetime. * (it's a bit unusual/strange for a control to allow that, but it's helpfull if LangOutlinePage works like that) */ @Override public void createControl(Composite parent) { super.createControl(parent); getTreeViewer().setContentProvider(createContentProvider()); getTreeViewer().setLabelProvider(StructureElementLabelProvider.createLangLabelProvider()); customizeCreateControl(); editor.getStructureField().registerChangeListener(false, structureListener); editor.getSelectedElementField().registerChangeListener(false, structureListener); updateTreeViewer(); } protected StructureElementContentProvider createContentProvider() { return new StructureElementContentProvider(); } protected void customizeCreateControl() { } @Override public void dispose() { editor.getSelectedElementField().removeListener(structureListener); editor.getStructureField().removeListener(structureListener); super.dispose(); } protected final FieldChangeListener structureListener = () -> updateTreeViewer(); protected void updateTreeViewer() { if(getTreeViewer() == null) { return; } SourceFileStructure structure; try { structure = editor.getSourceStructure(); } catch(CommonException e) { statusWidget.setStatusMessage(Severity.ERROR, e.getMultiLineRender()); return; } if(getTreeViewer().getInput() != structure) { statusWidget.setStatusMessage(null); getTreeViewer().setInput(structure); getTreeViewer().refresh(); } updateSelectionFromEditor(); } protected boolean updatingFromEditor = false; protected void updateSelectionFromEditor() { StructuredSelection newSelection = editor.getSelectedElementAsStructureSelection(); try { updatingFromEditor = true; getTreeViewer().setSelection(newSelection, true); } finally { updatingFromEditor = false; } } @Override protected void treeViewerPostSelectionChanged(SelectionChangedEvent event) { Object firstElement = ((IStructuredSelection) event.getSelection()).getFirstElement(); if(firstElement instanceof StructureElement) { StructureElement structureElement = (StructureElement) firstElement; if(!updatingFromEditor) { editor.setElementSelection(structureElement); } } super.treeViewerPostSelectionChanged(event); } /* ----------------- Show in target ----------------- */ @SuppressWarnings("unchecked") @Override public <T> T getAdapter(Class<T> adapter) { if(adapter == IShowInTarget.class) { return (T) getShowInTarget(); } return null; } protected IShowInTarget getShowInTarget() { return new IShowInTarget() { @Override public boolean show(ShowInContext context) { StructureElement structureElement = getStructureElementFor(context.getSelection()); if(structureElement != null) { setSelection(new StructuredSelection(structureElement)); return true; } return false; } }; } public StructureElement getStructureElementFor(ISelection selection) { if(selection instanceof ITextSelection) { ITextSelection textSelection = (ITextSelection) selection; return GetUpdatedStructureUIOperation.run_GetUpdatedStructureElementAt(editor, textSelection.getOffset()); } else if(selection instanceof IStructuredSelection) { IStructuredSelection structuredSelection = (IStructuredSelection) selection; if(structuredSelection.getFirstElement() instanceof StructureElement) { return (StructureElement) structuredSelection.getFirstElement(); } } return null; } }