| /******************************************************************************* |
| * Copyright (c) 2001, 2008 IBM Corporation 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: |
| * 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.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| 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.SubProgressMonitor; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.dialogs.ProgressMonitorDialog; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IViewActionDelegate; |
| import org.eclipse.ui.IViewPart; |
| import org.eclipse.wst.validation.ValidationFramework; |
| import org.eclipse.wst.validation.internal.ConfigurationManager; |
| import org.eclipse.wst.validation.internal.DisabledResourceManager; |
| import org.eclipse.wst.validation.internal.ValType; |
| import org.eclipse.wst.validation.internal.ValidationRegistryReader; |
| import org.eclipse.wst.validation.internal.ValidationSelectionHandlerRegistryReader; |
| import org.eclipse.wst.validation.internal.plugin.ValidationPlugin; |
| import org.eclipse.wst.validation.internal.ui.plugin.ValidationUIPlugin; |
| import org.eclipse.wst.validation.ui.internal.ManualValidationRunner; |
| |
| /** |
| * This class implements the pop-up menu item "Run Validation" When the item is selected, this |
| * action triggers a validation of the project, using all configured, enabled validators. |
| */ |
| public class ValidationMenuAction implements IViewActionDelegate { |
| private ISelection _currentSelection; |
| protected static final String SEP = "/"; //$NON-NLS-1$ |
| private Display _currentDisplay; |
| private IResourceVisitor _folderVisitor; |
| private IResourceVisitor _projectVisitor; |
| private Map<IProject, Set<IResource>> _selectedResources; |
| |
| public ValidationMenuAction() { |
| // cache the display before this action is forked. After the action is forked, |
| // Display.getCurrent() returns null. |
| _currentDisplay = Display.getCurrent(); |
| _selectedResources = new HashMap<IProject, Set<IResource>>(); |
| } |
| |
| private Display getDisplay() { |
| return (_currentDisplay == null) ? Display.getCurrent() : _currentDisplay; |
| } |
| |
| /** |
| * Return the wizard's shell. |
| */ |
| Shell getShell() { |
| Display display = getDisplay(); |
| Shell shell = (display == null) ? null : display.getActiveShell(); |
| if (shell == null && display != null) { |
| Shell[] shells = display.getShells(); |
| if (shells.length > 0) |
| shell = shells[0]; |
| } |
| return shell; |
| } |
| |
| /** |
| * 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(ValidateAction action) { |
| // 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 ((_currentSelection == null) || _currentSelection.isEmpty() || |
| !(_currentSelection instanceof IStructuredSelection))return null; |
| |
| Object[] elements = ((IStructuredSelection) _currentSelection).toArray(); |
| for (Object element : elements) { |
| if (element != null)addSelected(action, element); |
| } |
| return _selectedResources; |
| } |
| |
| 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) { |
| // 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 Object getExtendedType(Object selected) { |
| Object result = ValidationSelectionHandlerRegistryReader.getInstance().getExtendedType(selected); |
| return result == null ? selected : result; |
| } |
| |
| private boolean isValidType(Object object) { |
| return object instanceof IProject || object instanceof IFile || object instanceof IFolder; |
| } |
| |
| |
| 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 addVisitor(IFolder selected) { |
| // add the folder and its children |
| try { |
| selected.accept(getFolderVisitor()); |
| } catch (CoreException exc) { |
| ValidationUIPlugin.getPlugin().handleException(exc); |
| return; |
| } |
| } |
| |
| 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; |
| } |
| |
| 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; |
| } |
| } |
| |
| 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; |
| } |
| |
| /** |
| * The delegating action has been invoked. This method does the actual work. |
| * |
| * @param action |
| * Action proxy that handles the presentation portion of the plug-in action. |
| */ |
| public void run(IAction action) { |
| ValidateAction vaction = null; |
| if (action instanceof ValidateAction) { |
| vaction = (ValidateAction) action; |
| } |
| final Map<IProject, Set<IResource>> projects = loadSelected(vaction); |
| if ((projects == null) || (projects.size() == 0)) { |
| return; |
| } |
| |
| // If the files aren't saved do not run validation. |
| if(!handleFilesToSave(projects))return; |
| |
| boolean confirm = org.eclipse.wst.validation.internal.ValManager.getDefault().getGlobalPreferences() |
| .getConfirmDialog(); |
| ManualValidationRunner.validate(projects, ValType.Manual, confirm); |
| } |
| |
| /** |
| * Selection in the desktop has changed. Plug-in provider can use it to change the availability |
| * of the action or to modify other presentation properties. |
| * |
| * <p> |
| * Action delegate cannot be notified about selection changes before it is loaded. For that |
| * reason, control of action's enable state should also be performed through simple XML rules |
| * defined for the extension point. These rules allow enable state control before the delegate |
| * has been loaded. |
| * </p> |
| * |
| * @param action |
| * action proxy that handles presentation portion of the plug-in action |
| * @param selection |
| * current selection in the desktop |
| */ |
| public void selectionChanged(IAction action, ISelection selection) { |
| _currentSelection = selection; |
| boolean enabled = quickCheck(selection); |
| |
| // Don't force the plug-in to be activated just to check this setting. |
| if (enabled && ValidationPlugin.isActivated() && ValidationRegistryReader.isActivated()){ |
| enabled = hasManualValidators(selection); |
| } |
| action.setEnabled(enabled); |
| } |
| |
| /** |
| * Do a quick check on the selection, so see if we know that we don't want to validate the selection. |
| * |
| * @param selection |
| * @return false if we are sure that we don't want to validate it. Return true if we are still not sure. |
| */ |
| private boolean quickCheck(ISelection selection){ |
| if (selection == null || selection.isEmpty())return false; |
| if (selection instanceof IStructuredSelection){ |
| IStructuredSelection ss = (IStructuredSelection)selection; |
| Object sel = ss.getFirstElement(); |
| if (sel != null){ |
| if (sel instanceof IProject){ |
| IProject project = (IProject)sel; |
| if (!project.isOpen())return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Answer true if any of the selected items have manual validators enabled. |
| * @param selection |
| */ |
| private boolean hasManualValidators(ISelection selection){ |
| |
| if (selection instanceof IStructuredSelection){ |
| IStructuredSelection ss = (IStructuredSelection)selection; |
| for (Iterator it = ss.iterator(); it.hasNext();){ |
| Object sel = it.next(); |
| if (sel instanceof IResource){ |
| IResource resource = (IResource)sel; |
| if (ValidationFramework.getDefault().hasValidators(resource, true, false))return true; |
| } |
| } |
| } |
| |
| return false; |
| |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart) |
| */ |
| public void init(IViewPart view) { |
| } |
| |
| /** |
| * 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) |
| { |
| 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(getShell()); |
| |
| IRunnableWithProgress runnable = new IRunnableWithProgress(){ |
| public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException{ |
| try { |
| monitor.beginTask(ValidationUIMessages.SaveFilesDialog_saving, dirtyEditors.length); |
| int numDirtyEditors = dirtyEditors.length; |
| for(int i = 0; i < numDirtyEditors; i++){ |
| dirtyEditors[i].doSave(new SubProgressMonitor(monitor, 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; |
| } |
| |
| 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; |
| } |
| |
| } |