/*******************************************************************************
* Copyright (c) 2007 Business Objects Software Limited and others.
* All rights reserved.
* This file is 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:
* Business Objects Software Limited - initial API and implementation
*******************************************************************************/
/*
* WorkspaceTreeContentProvider.java
* Created: 28-Mar-07
* By: Rick Cameron
*/
package org.openquark.cal.eclipse.ui.views;
import java.util.Collection;
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.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.openquark.cal.compiler.ModuleName;
import org.openquark.cal.compiler.ModuleSourceDefinition;
import org.openquark.cal.eclipse.core.builder.CALBuilder;
import org.openquark.cal.eclipse.ui.CALUIMessages;
import org.openquark.cal.eclipse.ui.actions.ActionMessages;
import org.openquark.cal.services.CALSourcePathMapper;
/**
* @author rcameron
*
*/
final class WorkspaceTreeContentProvider extends ModuleTreeContentProvider {
/**
* Helper class to visit a delta and return whether anything in the delta corresponds to a deleted .cal file.
* @author Edward Lam
*/
private static class RemovedCalFileFinderDeltaVisitor implements IResourceDeltaVisitor {
private boolean removedCalFileFound = false;
public boolean visit(IResourceDelta delta) {
//only interested in changed resources (not added or removed)
if (delta.getKind() != IResourceDelta.REMOVED) {
return true;
}
IResource resource = delta.getResource();
if (resource.getType() == IResource.FILE && CALSourcePathMapper.CAL_FILE_EXTENSION.equalsIgnoreCase(resource.getFileExtension())) {
removedCalFileFound = true;
}
return true;
}
boolean wasRemovedCalFileFound() {
return removedCalFileFound;
}
};
protected Action showHierarchyOfModulesAction;
/**
* Listens for deleted projects so the workspaceview can be updated.
*/
private final IResourceChangeListener resourceChangeListener = new IResourceChangeListener () {
public void resourceChanged (IResourceChangeEvent event) {
/*
* TODO: we could be smarter about what we update here.
* Since we have the resource change event, we could traverse the delta and just find out which .cal files
* were added or removed, while still handling events like open and close projects.
*/
boolean updateViewer = false;
IResourceDelta[] deleted = event.getDelta ().getAffectedChildren (IResourceDelta.REMOVED);
// Projects that are removed
if (deleted.length > 0) {
Object maybeProject = deleted[0].getResource ();
if (maybeProject instanceof IProject) {
updateViewer = true;
}
} else {
// Opens or closes of the project
IResourceDelta[] changed = event.getDelta ().getAffectedChildren (IResourceDelta.CHANGED);
if (changed.length > 0 && (changed[0].getFlags () & IResourceDelta.OPEN) > 0) {
updateViewer = true;
}
}
if (!updateViewer) {
RemovedCalFileFinderDeltaVisitor removedCalFileFinderDeltaVisitor = new RemovedCalFileFinderDeltaVisitor();
try {
event.getDelta().accept(removedCalFileFinderDeltaVisitor);
} catch (CoreException e) {
//open error dialog with syncExec or print to plugin log file
}
updateViewer = removedCalFileFinderDeltaVisitor.wasRemovedCalFileFound();
}
if (updateViewer) {
initialize ();
setCalBuilderWasEnabled (true);
getViewer ().getControl ().getDisplay ().asyncExec (new Runnable () {
public void run () {
getViewer ().refresh (true);
}
});
}
}
};
/**
* Constructor WorkspaceTreeContentProvider
* @param moduleContentProvider
* @param viewer
*/
public WorkspaceTreeContentProvider (CALModuleContentProvider moduleContentProvider, ILabelProvider labelProvider, TreeViewer viewer) {
super (moduleContentProvider, labelProvider, viewer);
makeActions ();
}
/**
* @see org.openquark.cal.eclipse.ui.views.ModuleTreeContentProvider#initialize()
*/
@Override
protected void initialize () {
super.initialize ();
ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener, IResourceChangeEvent.POST_CHANGE);
}
/**
* @see org.openquark.cal.eclipse.ui.views.ModuleTreeContentProvider#dispose()
*/
@Override
public void dispose () {
super.dispose ();
ResourcesPlugin.getWorkspace().removeResourceChangeListener(resourceChangeListener);
}
private void makeActions () {
showHierarchyOfModulesAction = new Action("", IAction.AS_CHECK_BOX) {
@Override
public void run() {
setShowModuleHierarchy(isChecked());
}
};
showHierarchyOfModulesAction.setText(CALUIMessages.CALWorkspace_showHierarchyOfModules);
showHierarchyOfModulesAction.setChecked(getModuleContentProvider ().getShowModuleHierarchy());
showHierarchyOfModulesAction.setToolTipText(CALUIMessages.CALWorkspace_showHierarchyOfModules_tooltip);
// showHierarchyOfModulesAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().
// getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));
}
/**
* @see org.openquark.cal.eclipse.ui.views.ModuleTreeContentProvider#getRootElements()
*/
@Override
protected Object[] getRootElements () {
if (getInvisibleRoot () == null) {
initialize ();
}
if (CALBuilder.isEnabled ()) {
if (getInvisibleRoot () instanceof Collection) {
Collection<?> collection = ((Collection<?>)getInvisibleRoot ());
return collection.toArray ();
} else if (getInvisibleRoot () instanceof HierarchicalNode) {
return ((HierarchicalNode)getInvisibleRoot ()).getChildren ();
} else {
return new Object[0];
}
} else {
// CAL Builder is not enabled
setCalBuilderWasEnabled (false);
return new Object[] { ActionMessages.error_calBuilderNotEnabled_message };
}
}
/**
* @see org.openquark.cal.eclipse.ui.views.ModuleTreeContentProvider#fillLocalPullDown(org.eclipse.jface.action.IMenuManager)
*/
@Override
public void fillLocalPullDown (IMenuManager manager) {
manager.add(showHierarchyOfModulesAction);
addStandardLocalMenuActions (manager);
}
/**
* @see org.openquark.cal.eclipse.ui.views.ModuleTreeContentProvider#fillContextMenu(org.eclipse.jface.action.IMenuManager)
*/
@Override
public void fillContextMenu (IMenuManager manager) {
manager.add(showHierarchyOfModulesAction);
addStandardContextMenuActions (manager);
}
private void refreshAncestors(Object object){
Object parent = getParent(object);
while(parent instanceof HierarchicalNode){
getViewer().update(parent, null);
parent = getParent(parent);
}
}
/**
* @see org.openquark.cal.eclipse.ui.views.ModuleTreeContentProvider#refreshForModule(org.openquark.cal.compiler.ModuleSourceDefinition, boolean)
*/
@Override
protected void refreshForModule (ModuleSourceDefinition moduleSourceDefinition, boolean updateOnlyModule) {
final ModuleName moduleName = moduleSourceDefinition.getModuleName();
if (wasCalBuilderEnabled () && null != getViewer ().testFindItem(moduleName)){
if (updateOnlyModule){
getViewer().update(moduleName, null);
}
else{
getViewer().refresh(moduleName, true);
}
refreshAncestors(moduleName);
}
else {
initialize ();
if (!getViewer().getControl().isDisposed()){
getViewer().refresh(true);
}
}
}
}