package com.codeaffine.extras.workingset.internal; import static com.codeaffine.extras.workingset.internal.DynamicWorkingSet.ID; import static java.lang.Boolean.TRUE; import static java.util.Collections.synchronizedSet; import static org.eclipse.core.resources.IResourceChangeEvent.POST_CHANGE; import static org.eclipse.core.resources.IResourceDelta.ADDED; import static org.eclipse.core.resources.IResourceDelta.CHANGED; import static org.eclipse.core.resources.IResourceDelta.REMOVED; import static org.eclipse.ui.IWorkingSetManager.CHANGE_WORKING_SET_ADD; import static org.eclipse.ui.IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE; import static org.eclipse.ui.IWorkingSetManager.CHANGE_WORKING_SET_REMOVE; import java.util.HashSet; import java.util.Set; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.ui.IWorkingSet; import org.eclipse.ui.IWorkingSetManager; import org.eclipse.ui.IWorkingSetUpdater; import org.eclipse.ui.PlatformUI; public class DynamicWorkingSetUpdater implements IWorkingSetUpdater, IPropertyChangeListener, IResourceChangeListener { private final IWorkingSetManager workingSetManager; private final IWorkspace workspace; private final ThreadLocal<Boolean> inPropertyChange; private final Set<IWorkingSet> workingSets; public DynamicWorkingSetUpdater() { workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager(); workspace = ResourcesPlugin.getWorkspace(); inPropertyChange = new ThreadLocal<>(); workingSets = synchronizedSet( new HashSet<IWorkingSet>() ); initialize(); } private void initialize() { workingSetManager.addPropertyChangeListener( this ); workspace.addResourceChangeListener( this, POST_CHANGE ); } @Override public void add( IWorkingSet workingSet ) { update( workingSet ); workingSets.add( workingSet ); } @Override public boolean remove( IWorkingSet workingSet ) { return workingSets.remove( workingSet ); } @Override public boolean contains( IWorkingSet workingSet ) { return workingSets.contains( workingSet ); } @Override public void dispose() { workspace.removeResourceChangeListener( this ); workingSetManager.removePropertyChangeListener( this ); workingSets.clear(); } @Override public void propertyChange( PropertyChangeEvent event ) { if( inPropertyChange.get() == null ) { inPropertyChange.set( TRUE ); try { handlePropertyChange( event ); } finally { inPropertyChange.remove(); } } } @Override public void resourceChanged( IResourceChangeEvent event ) { if( event.getDelta() != null && isUpdateNeeded( event ) ) { update(); } } private void handlePropertyChange( PropertyChangeEvent event ) { if( isWorkingSetAddEvent( event ) ) { add( getWorkingSet( event ) ); } else if( isWorkingSetNameChangeEvent( event ) ) { update( getWorkingSet( event ) ); } else if( isWorkingSetRemoveEvent( event ) ) { remove( getWorkingSet( event ) ); } } private boolean isUpdateNeeded( IResourceChangeEvent event ) { ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(); try { event.getDelta().accept( visitor ); } catch( CoreException ce ) { throw new RuntimeException( ce ); } return visitor.isUpdateNeeded(); } private void update() { for( IWorkingSet workingSet : workingSets.toArray( new IWorkingSet[ 0 ] ) ) { update( workingSet ); } } private static void update( IWorkingSet workingSet ) { new WorkingSetContentUpdater( workingSet ).updateElements(); } private static boolean isWorkingSetAddEvent( PropertyChangeEvent event ) { return CHANGE_WORKING_SET_ADD.equals( event.getProperty() ) && isDynamicWorkingSet( event ); } private static boolean isWorkingSetRemoveEvent( PropertyChangeEvent event ) { return CHANGE_WORKING_SET_REMOVE.equals( event.getProperty() ) && isDynamicWorkingSet( event ); } private static boolean isWorkingSetNameChangeEvent( PropertyChangeEvent event ) { return CHANGE_WORKING_SET_NAME_CHANGE.equals( event.getProperty() ) && isDynamicWorkingSet( event ); } private static boolean isDynamicWorkingSet( PropertyChangeEvent event ) { IWorkingSet workingSet = getWorkingSet( event ); return ID.equals( workingSet.getId() ); } private static IWorkingSet getWorkingSet( PropertyChangeEvent event ) { IWorkingSet result = ( IWorkingSet )event.getNewValue(); if( result == null ) { result = ( IWorkingSet )event.getOldValue(); } return result; } private class ResourceDeltaVisitor implements IResourceDeltaVisitor { private boolean updateNeeded; @Override public boolean visit( IResourceDelta delta ) throws CoreException { updateNeeded = isProjectChange( delta ); return !updateNeeded; } private boolean isProjectChange( IResourceDelta delta ) { int kind = delta.getKind(); IResource resource = delta.getResource(); return ( kind == ADDED || kind == CHANGED || kind == REMOVED ) && resource instanceof IProject; } boolean isUpdateNeeded() { return updateNeeded; } } }