/*
* Copyright (c) 2005,2006 PMD for Eclipse Development Team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * The end-user documentation included with the redistribution, if
* any, must include the following acknowledgement:
* "This product includes software developed in part by support from
* the Defense Advanced Research Project Agency (DARPA)"
* * Neither the name of "PMD for Eclipse Development Team" nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.sourceforge.pmd.eclipse.ui.actions;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import net.sourceforge.pmd.eclipse.runtime.PMDRuntimeConstants;
import net.sourceforge.pmd.eclipse.runtime.cmd.AbstractDefaultCommand;
import net.sourceforge.pmd.eclipse.ui.nls.StringKeys;
import net.sourceforge.pmd.eclipse.util.IOUtil;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
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.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
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.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
/**
* Implements the clear reviews action
*
* @author Philippe Herlin
*
*/
public class ClearReviewsAction extends AbstractUIAction implements IResourceVisitor, IViewActionDelegate {
private static final Logger log = Logger.getLogger(ClearReviewsAction.class);
private IProgressMonitor monitor;
/**
* @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)
*/
public void init(IViewPart view) {
setActivePart(null, view.getSite().getPage().getActivePart() );
}
/**
* @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
*/
public void run(IAction action) {
log.info("Remove violation reviews requested.");
ProgressMonitorDialog monitorDialog = new ProgressMonitorDialog(Display.getCurrent().getActiveShell());
try {
monitorDialog.run(false, false, new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
setMonitor(monitor);
clearReviews();
monitor.done();
}
});
} catch (InvocationTargetException e) {
logError("Invocation Target Exception when removing violation reviews", e.getTargetException());
} catch (InterruptedException e) {
logError("Interrupted Exception when removing violation reviews", e);
}
}
/**
* @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
*/
public void selectionChanged(IAction action, ISelection selection) {
}
/**
* Get the monitor
*
* @return
*/
protected IProgressMonitor getMonitor() {
return monitor;
}
/**
* Set the monitor
*
* @param monitor
*/
protected void setMonitor(IProgressMonitor monitor) {
this.monitor = monitor;
}
/**
* Progress monitor
*/
protected void monitorWorked() {
if (getMonitor() != null) {
getMonitor().worked(1);
}
}
/**
* Set a substask
*
* @param message
*/
protected void monitorSubTask(String message) {
if (getMonitor() != null) {
getMonitor().subTask(message);
}
}
/**
* Process the clear review action
*/
protected void clearReviews() {
try {
// If action is started from a view, the process all selected resource
if (isViewPart()) {
ISelection selection = targetSelection();
if (selection != null && selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
if (getMonitor() != null) {
getMonitor().beginTask(getString(StringKeys.MONITOR_REMOVE_REVIEWS), IProgressMonitor.UNKNOWN);
Iterator<?> i = structuredSelection.iterator();
while (i.hasNext()) {
Object object = i.next();
IResource resource = null;
if (object instanceof IMarker) {
resource = ((IMarker) object).getResource();
} else if (object instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) object;
resource = (IResource) adaptable.getAdapter(IResource.class);
} else {
log.warn("The selected object is not adaptable");
log.debug(" -> selected object = " + object);
}
if (resource != null) {
resource.accept(this);
} else {
log.warn("The selected object cannot adapt to a resource.");
log.debug(" -> selected object" + object);
}
}
}
}
}
// If action is started from an editor, process the file currently edited
if (isEditorPart()) {
IEditorInput editorInput = ((IEditorPart) this.targetPart()).getEditorInput();
if (editorInput instanceof IFileEditorInput) {
((IFileEditorInput) editorInput).getFile().accept(this);
} else {
log.debug("The kind of editor input is not supported. The editor input if of type: "
+ editorInput.getClass().getName());
}
}
// else this is not supported
else {
log.debug("This action is not supported on this kind of part. This part type is: " + targetPartClassName());
}
} catch (CoreException e) {
logError("Core Exception when clearing violations reviews", e);
}
}
/**
* Clear reviews for a file
*
* @param file
*/
private void clearReviews(IFile file) {
monitorSubTask(file.getName());
String updatedFileContent = removeReviews(file);
if (updatedFileContent != null) {
saveNewContent(file, updatedFileContent);
}
monitorWorked();
}
private static boolean isReviewable(IFile file) {
if (AbstractDefaultCommand.isJavaFile(file)) return true;
return file.getName().toLowerCase().endsWith(".jsp");
}
/**
* remove reviews from file content
*
* @param file
* @return
*/
private String removeReviews(IFile file) {
if (!isReviewable(file)) return null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter out = null;
boolean noChange = true;
try {
boolean comment = false;
BufferedReader reader = new BufferedReader(new InputStreamReader(file.getContents()));
out = new PrintWriter(baos);
while (reader.ready()) {
String origLine = reader.readLine();
String line = origLine.trim();
if (line == null) break;
int index = origLine.indexOf(PMDRuntimeConstants.PMD_STYLE_REVIEW_COMMENT);
int quoteIndex = origLine.indexOf('"');
if (line.startsWith("/*")) {
if (line.indexOf("*/") == -1) {
comment = true;
}
out.println(origLine);
} else if (comment && line.indexOf("*/") != -1) {
comment = false;
out.println(origLine);
} else if (!comment && line.startsWith(PMDRuntimeConstants.PLUGIN_STYLE_REVIEW_COMMENT)) {
noChange = false;
} else if (!comment && index != -1 && !(quoteIndex != -1 && quoteIndex < index && index < origLine.lastIndexOf('"'))) {
noChange = false;
out.println(origLine.substring(0, index));
} else {
out.println(origLine);
}
}
out.flush();
} catch (CoreException e) {
logError(StringKeys.ERROR_CORE_EXCEPTION, e);
} catch (IOException e) {
logError(StringKeys.ERROR_IO_EXCEPTION, e);
} finally{
IOUtil.closeQuietly(baos);
IOUtil.closeQuietly(out);
}
return noChange ? null : baos.toString();
}
/**
* Save the file
*
* @param file
* @param newContent
*/
private void saveNewContent(IFile file, String newContent) {
try {
file.setContents(new ByteArrayInputStream(newContent.getBytes()), false, true, getMonitor());
} catch (CoreException e) {
logError(StringKeys.ERROR_CORE_EXCEPTION, e);
}
}
/**
* @see org.eclipse.core.resources.IResourceVisitor#visit(org.eclipse.core.resources.IResource)
*/
public boolean visit(IResource resource) throws CoreException {
if (resource instanceof IFile) {
clearReviews((IFile) resource);
}
return resource instanceof IProject || resource instanceof IFolder;
}
}