blob: 12fec8186210d9f01bc6e06de8e3d1165396929c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2018 IBM Corporation and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.validation.internal.ui;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.part.IContributedContentsView;
import org.eclipse.wst.validation.internal.ConfigurationManager;
import org.eclipse.wst.validation.internal.DisabledResourceManager;
import org.eclipse.wst.validation.internal.ValManager;
import org.eclipse.wst.validation.internal.ValType;
import org.eclipse.wst.validation.internal.ValidationSelectionHandlerRegistryReader;
import org.eclipse.wst.validation.internal.ui.plugin.ValidationUIPlugin;
import org.eclipse.wst.validation.ui.internal.ManualValidationRunner;
public class ValidationHandler extends AbstractHandler {
private IResourceVisitor _folderVisitor;
private IResourceVisitor _projectVisitor;
private Map<IProject, Set<IResource>> _selectedResources;
public ValidationHandler() {
_selectedResources = new HashMap<IProject, Set<IResource>>();
}
void addSelected(IResource selected) {
IProject project = selected.getProject();
boolean added = _selectedResources.containsKey(project);
Set<IResource> changedRes = null;
if (added) {
// If the value is null, the entire project needs to be validated anyway.
changedRes = _selectedResources.get(project);
if (changedRes == null)
return;
} else {
changedRes = new HashSet<IResource>();
}
if (changedRes.add(selected)) {
_selectedResources.put(project, changedRes);
}
}
private void addSelected(ValidateAction action, Object selected) {
if (selected instanceof IProject) {
addVisitor((IProject) selected);
} else if (selected instanceof IFile) {
addSelected((IFile) selected);
} else if (selected instanceof IFolder) {
addVisitor((IFolder) selected);
} else if (isValidType(getExtendedType(selected))) {
addSelected(action, getExtendedType(selected));
} else {
// Not a valid input type. Must be IProject, IJavaProject, or IResource.
// If this ValidationMenuAction is a delegate of ValidateAction, is
// the input type recognized by the ValidateAction?
boolean valid = false;
if (action != null) {
IResource[] resources = action.getResource(selected);
if (resources != null) {
valid = true;
for (int i = 0; i < resources.length; i++) {
addSelected(action, resources[i]);
}
}
}
if (!valid) {
IResource resource = Platform.getAdapterManager().getAdapter(selected, IResource.class);
if (resource != null) {
valid = true;
addSelected(action, resource);
}
}
if (!valid) {
// Stop processing. This allows the "Run Validation" menu item
// to gray out once an element that can not be validated is selected.
_selectedResources.clear();
}
}
}
private void addVisitor(IFolder selected) {
// add the folder and its children
try {
selected.accept(getFolderVisitor());
} catch (CoreException exc) {
ValidationUIPlugin.getPlugin().handleException(exc);
return;
}
}
private void addVisitor(IProject selected) {
// add the folder and its children
if (!selected.isAccessible())
return;
try {
selected.accept(getProjectVisitor());
} catch (CoreException exc) {
ValidationUIPlugin.getPlugin().handleException(exc);
return;
}
}
public Object execute(ExecutionEvent event) throws ExecutionException {
Shell activeShell = HandlerUtil.getActiveShell(event);
IWorkbenchPart interestedPart = HandlerUtil.getActivePart(event);
IStructuredSelection sel = HandlerUtil.getCurrentStructuredSelection(event);
Map<IProject, Set<IResource>> projects = loadSelected(sel);
if (projects == null || projects.isEmpty()) {
if (!(interestedPart instanceof IEditorPart)) {
IContributedContentsView contributedContentsView = interestedPart
.getAdapter(IContributedContentsView.class);
if (contributedContentsView != null) {
interestedPart = contributedContentsView.getContributingPart();
}
}
if (interestedPart instanceof IEditorPart) {
IEditorInput editorInput = HandlerUtil.getActiveEditorInput(event);
if (editorInput != null) {
IResource resource = editorInput.getAdapter(IResource.class);
if (resource != null) {
sel = new StructuredSelection(resource);
}
}
}
projects = loadSelected(sel);
}
if (projects == null || projects.isEmpty()) {
return null;
}
// If the files aren't saved do not run validation.
if (!handleFilesToSave(projects, activeShell))
return null;
boolean confirm = ValManager.getDefault().getGlobalPreferences()
.getConfirmDialog();
ManualValidationRunner.validate(projects, ValType.Manual, confirm);
return null;
}
private Object getExtendedType(Object selected) {
Object result = ValidationSelectionHandlerRegistryReader.getInstance().getExtendedType(selected);
return result == null ? selected : result;
}
private IResourceVisitor getFolderVisitor() {
if (_folderVisitor == null) {
_folderVisitor = new IResourceVisitor() {
public boolean visit(IResource res) {
if (res instanceof IFile) {
addSelected(res);
} else if (res instanceof IFolder) {
addSelected(res);
}
return true; // visit the resource's children
}
};
}
return _folderVisitor;
}
protected List<IFile> getIFiles(Map<IProject, Set<IResource>> projects) {
List<IFile> fileList = new LinkedList<IFile>();
for (IProject project : projects.keySet()) {
for (IResource resource : projects.get(project)) {
if (resource instanceof IFile)
fileList.add((IFile) resource);
}
}
return fileList;
}
private IResourceVisitor getProjectVisitor() {
if (_projectVisitor == null) {
_projectVisitor = new IResourceVisitor() {
public boolean visit(IResource res) {
if (DisabledResourceManager.getDefault().isDisabled(res))
return false;
if (res instanceof IFile)
addSelected(res);
else if (res instanceof IFolder)
addSelected(res);
else if (res instanceof IProject)
addSelected(res);
return true;
}
};
}
return _projectVisitor;
}
/**
* Handle any files that must be saved prior to running validation.
*
* @param projects The list of projects that will be validated.
* @return True if all files have been saved, false otherwise.
*/
protected boolean handleFilesToSave(Map<IProject, Set<IResource>> projects, Shell shell) {
List fileList = getIFiles(projects);
final IEditorPart[] dirtyEditors = SaveFilesHelper.getDirtyEditors(fileList);
if (dirtyEditors == null || dirtyEditors.length == 0)
return true;
boolean saveAutomatically = false;
try {
saveAutomatically = ConfigurationManager.getManager().getGlobalConfiguration().getSaveAutomatically();
} catch (InvocationTargetException e) {
// In this case simply default to false.
}
SaveFilesDialog sfDialog = null;
if (!saveAutomatically) {
sfDialog = new SaveFilesDialog(
ValidationUIPlugin.getPlugin().getWorkbench().getActiveWorkbenchWindow().getShell());
sfDialog.setInput(Arrays.asList(dirtyEditors));
}
if (saveAutomatically || sfDialog.open() == Window.OK) {
ProgressMonitorDialog ctx = new ProgressMonitorDialog(shell);
IRunnableWithProgress runnable = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
SubMonitor submonitor = SubMonitor.convert(monitor, ValidationUIMessages.SaveFilesDialog_saving, dirtyEditors.length);
for (int i = 0; i < dirtyEditors.length; i++) {
dirtyEditors[i].doSave(submonitor.newChild(1));
}
} finally {
monitor.done();
}
}
};
try {
ctx.run(false, true, runnable);
return true;
} catch (InvocationTargetException e) {
ValidationUIPlugin.getPlugin().handleException(e);
} catch (InterruptedException e) {
ValidationUIPlugin.getPlugin().handleException(e);
}
}
return false;
}
private boolean isValidType(Object object) {
return object instanceof IProject || object instanceof IFile || object instanceof IFolder;
}
/**
* Return a map of the selected elements. Each key of the map is an IProject,
* and the value is a Set of the selected resources in that project. If a
* project is selected, and nothing else in the project is selected, a full
* validation (null value) will be done on the project. If a project is
* selected, and some files/folders in the project are also selected, only the
* files/folders will be validated. If a folder is selected, all of its contents
* are also validated.
*
* @return null if there is no selection.
*/
private Map<IProject, Set<IResource>> loadSelected(IStructuredSelection selection) {
// GRK previously this did not do a clear, but I couldn't understand why that
// would be so I am forcing a clear
// GRK In my testing, not doing a clear caused duplicate validations
_selectedResources.clear();
if ((selection == null) || selection.isEmpty() )
return null;
Object[] elements = selection.toArray();
for (Object element : elements) {
if (element != null)
addSelected(null, element);
}
return _selectedResources;
}
}