package com.anjlab.eclipse.tapestry5.watchdog;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import com.anjlab.eclipse.tapestry5.Activator;
import com.anjlab.eclipse.tapestry5.EclipseUtils;
import com.anjlab.eclipse.tapestry5.TapestryContext;
import com.anjlab.eclipse.tapestry5.TapestryFile;
import com.anjlab.eclipse.tapestry5.TapestryUtils;
public class TapestryContextWatchdog extends AbstractWatchdog
{
private WindowSelectionListener windowListener;
private IResourceChangeListener postBuildListener;
private IResourceChangeListener postChangeListener;
private final Map<IWorkbenchWindow, TapestryContext> currentContexts;
public TapestryContextWatchdog()
{
currentContexts = new ConcurrentHashMap<IWorkbenchWindow, TapestryContext>();
}
private void notifyContextChanged(IWorkbenchWindow targetWindow, TapestryContext newContext)
{
for (ITapestryContextListener listener : listeners.find(ITapestryContextListener.class, targetWindow, true))
{
listener.contextChanged(targetWindow, newContext);
}
}
private void notifySelectionChanged(IWorkbenchWindow targetWindow, TapestryFile selectedFile)
{
for (ITapestryContextListener listener : listeners.find(ITapestryContextListener.class, targetWindow, true))
{
listener.selectionChanged(targetWindow, selectedFile);
}
}
private void changeContext(IWorkbenchWindow window, TapestryContext newContext)
{
if (newContext != currentContexts.get(window))
{
currentContexts.put(window, newContext);
notifyContextChanged(window, newContext);
}
}
@Override
public void start()
{
super.start();
postChangeListener = new IResourceChangeListener()
{
@Override
public void resourceChanged(IResourceChangeEvent event)
{
for (IFile affectedFile : EclipseUtils.getAllAffectedResources(
event.getDelta(), IFile.class))
{
for (Entry<IWorkbenchWindow, TapestryContext> entry : currentContexts.entrySet())
{
IWorkbenchWindow window = entry.getKey();
TapestryContext context = entry.getValue();
if (context.contains(affectedFile))
{
if (!affectedFile.exists())
{
context.remove(affectedFile);
changeContext(window, context);
}
else
{
// This file is already in context and keeps being in this context.
// If the java file changed we should update context, because @Imports could changed.
// Otherwise context should stay the same, because it may be not possible to restore context from non-java file.
if (TapestryUtils.isJavaFile(affectedFile.getProjectRelativePath()))
{
context = Activator.getDefault()
.getTapestryContextFactory()
.createTapestryContext(affectedFile);
changeContext(window, context);
}
}
}
}
}
}
};
ResourcesPlugin.getWorkspace().addResourceChangeListener(postChangeListener, IResourceChangeEvent.POST_CHANGE);
postBuildListener = new IResourceChangeListener()
{
@Override
public void resourceChanged(IResourceChangeEvent event)
{
List<IProject> projects = EclipseUtils.getAllAffectedResources(event.getDelta(), IProject.class);
for (IProject project : projects)
{
TapestryContext.deleteMarkers(project);
}
for (TapestryContext context : currentContexts.values())
{
context.validate();
}
}
};
ResourcesPlugin.getWorkspace().addResourceChangeListener(postBuildListener, IResourceChangeEvent.POST_BUILD);
windowListener = new WindowSelectionListener(new ISelectionListener()
{
private final ActiveEditorTracker activeEditorTracker = new ActiveEditorTracker();
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection)
{
IWorkbenchWindow window = part.getSite().getWorkbenchWindow();
// https://github.com/anjlab/eclipse-tapestry5-plugin/issues/18
if (!activeEditorTracker.editorChanged(window.getActivePage()))
{
return;
}
TapestryFile selectedFile = TapestryUtils.getTapestryFileFromPage(window.getActivePage());
if (selectedFile == null)
{
return;
}
TapestryContext context = currentContexts.get(window);
if (context == null || !context.contains(selectedFile))
{
context = selectedFile.getContext();
}
// In case if we clicked on some file and couldn't obtain tapestry context
// for the file (i.e. because it doesn't follow naming conventions, or this is not a tapestry file)
// we simply keep showing the previous context
if (!context.isEmpty())
{
changeContext(window, context);
}
if (selectedFile != null)
{
notifySelectionChanged(window, selectedFile);
}
}
})
.addListener();
}
@Override
public void stop()
{
windowListener.removeListener();
windowListener = null;
ResourcesPlugin.getWorkspace().removeResourceChangeListener(postChangeListener);
postChangeListener = null;
ResourcesPlugin.getWorkspace().removeResourceChangeListener(postBuildListener);
postBuildListener = null;
currentContexts.clear();;
super.stop();
}
public TapestryContext getTapestryContext(IWorkbenchWindow window)
{
return currentContexts.get(window);
}
}