/******************************************************************************* * Copyright (c) 2004, 2017 Tasktop Technologies and others. * 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: * Tasktop Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.dltk.internal.mylyn.editor; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Preferences.IPropertyChangeListener; import org.eclipse.core.runtime.Status; import org.eclipse.dltk.core.IMember; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.IParent; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.internal.mylyn.DLTKStructureBridge; import org.eclipse.dltk.internal.mylyn.DLTKUiBridgePlugin; import org.eclipse.dltk.internal.ui.editor.ScriptEditor; import org.eclipse.dltk.ui.DLTKUIPlugin; import org.eclipse.dltk.ui.text.folding.IFoldingStructureProvider; import org.eclipse.dltk.ui.text.folding.IFoldingStructureProviderExtension; import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.context.core.AbstractContextListener; import org.eclipse.mylyn.context.core.ContextChangeEvent; import org.eclipse.mylyn.context.core.ContextCore; import org.eclipse.mylyn.context.core.IInteractionElement; import org.eclipse.ui.IEditorPart; /** * @author Mik Kersten */ public class ActiveFoldingListener extends AbstractContextListener { private final IEditorPart editor; private IFoldingStructureProviderExtension updater; private static DLTKStructureBridge bridge = (DLTKStructureBridge) ContextCore .getStructureBridge(DLTKStructureBridge.CONTENT_TYPE); private boolean enabled = false; private final IPropertyChangeListener PREFERENCE_LISTENER = event -> { if (event.getProperty().equals(DLTKUiBridgePlugin.AUTO_FOLDING_ENABLED)) { if (event.getNewValue().equals(Boolean.TRUE.toString())) { enabled = true; } else { enabled = false; } updateFolding(); } }; public ActiveFoldingListener(ScriptEditor editor) { this.editor = editor; ContextCore.getContextManager().addListener(this); DLTKUiBridgePlugin.getDefault().getPluginPreferences().addPropertyChangeListener(PREFERENCE_LISTENER); enabled = DLTKUiBridgePlugin.getDefault().getPreferenceStore().getBoolean( DLTKUiBridgePlugin.AUTO_FOLDING_ENABLED); try { Object adapter = editor.getAdapter(IFoldingStructureProvider.class); if (adapter instanceof IFoldingStructureProviderExtension) { updater = (IFoldingStructureProviderExtension) adapter; } else { StatusHandler.log(new Status(IStatus.ERROR, DLTKUiBridgePlugin.ID_PLUGIN, "Could not install active folding on provider: " + adapter + ", must extend " //$NON-NLS-1$ //$NON-NLS-2$ + IFoldingStructureProviderExtension.class.getName())); } } catch (Exception e) { StatusHandler.log(new Status(IStatus.ERROR, DLTKUiBridgePlugin.ID_PLUGIN, "Could not install auto folding, reflection denied", e)); //$NON-NLS-1$ } updateFolding(); } public void dispose() { ContextCore.getContextManager().removeListener(this); DLTKUiBridgePlugin.getDefault().getPluginPreferences().removePropertyChangeListener(PREFERENCE_LISTENER); } public static void resetProjection(IEditorPart javaEditor) { // XXX 3.2 ignore for 3.2, leave for 3.1? } public void updateFolding() { if (!enabled || !ContextCore.getContextManager().isContextActive()) { if (editor instanceof ScriptEditor) { ((ScriptEditor) editor).resetProjection(); } } else if (editor.getEditorInput() == null) { return; } else { try { List<IModelElement> toExpand = new ArrayList<>(); List<IModelElement> toCollapse = new ArrayList<>(); IModelElement element = DLTKUIPlugin.getEditorInputModelElement(editor.getEditorInput()); if (element instanceof ISourceModule) { ISourceModule compilationUnit = (ISourceModule) element; List<IModelElement> allChildren = getAllChildren(compilationUnit); for (IModelElement child : allChildren) { IInteractionElement interactionElement = ContextCore.getContextManager() .getElement(bridge.getHandleIdentifier(child)); if (interactionElement != null && interactionElement.getInterest().isInteresting()) { toExpand.add(child); } else { toCollapse.add(child); } } } if (updater != null) { updater.collapseComments(); updater.collapseMembers(); updater.expandElements(toExpand.toArray(new IModelElement[toExpand.size()])); } } catch (Exception e) { StatusHandler .log(new Status(IStatus.ERROR, DLTKUiBridgePlugin.ID_PLUGIN, "Could not update folding", e)); //$NON-NLS-1$ } } } private static List<IModelElement> getAllChildren(IParent parentElement) { List<IModelElement> allChildren = new ArrayList<>(); try { for (IModelElement child : parentElement.getChildren()) { allChildren.add(child); if (child instanceof IParent) { allChildren.addAll(getAllChildren((IParent) child)); } } } catch (ModelException e) { // ignore failures } return allChildren; } public void updateFolding(List<IInteractionElement> elements) { for (IInteractionElement element : elements) { if (updater == null || !enabled) { return; } else { Object object = bridge.getObjectForHandle(element.getHandleIdentifier()); if (object instanceof IMember) { IMember member = (IMember) object; if (element.getInterest().isInteresting()) { updater.expandElements(new IModelElement[] { member }); // expand the next 2 children down (e.g. anonymous types) try { IModelElement[] children = ((IParent) member).getChildren(); if (children.length == 1) { updater.expandElements(new IModelElement[] { children[0] }); if (children[0] instanceof IParent) { IModelElement[] childsChildren = ((IParent) children[0]).getChildren(); if (childsChildren.length == 1) { updater.expandElements(new IModelElement[] { childsChildren[0] }); } } } } catch (ModelException e) { // ignore } } else { updater.collapseElements(new IModelElement[] { member }); } } } } } @Override public void contextChanged(ContextChangeEvent event) { switch (event.getEventKind()) { case ACTIVATED: case DEACTIVATED: if (DLTKUiBridgePlugin.getDefault().getPreferenceStore().getBoolean( DLTKUiBridgePlugin.AUTO_FOLDING_ENABLED)) { updateFolding(); } break; case CLEARED: if (event.isActiveContext()) { if (DLTKUiBridgePlugin.getDefault().getPreferenceStore().getBoolean( DLTKUiBridgePlugin.AUTO_FOLDING_ENABLED)) { updateFolding(); } } break; case INTEREST_CHANGED: updateFolding(event.getElements()); break; } } }