blob: 8f6c3aecb262fff61f25cfe4d95c7a2d254900e0 [file] [log] [blame]
// $codepro.audit.disable com.instantiations.assist.eclipse.analysis.audit.rule.effectivejava.alwaysOverridetoString.alwaysOverrideToString, com.instantiations.assist.eclipse.analysis.deserializeabilitySecurity, com.instantiations.assist.eclipse.analysis.disallowReturnMutable, com.instantiations.assist.eclipse.analysis.enforceCloneableUsageSecurity
/*******************************************************************************
* Copyright (c) 2012 Ericsson AB 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
*
* Description:
*
* This class implements various utility methods used in Anomaly handling
*
* Contributors:
* Sebastien Dubois - Created for Mylyn Review R4E project
*
*******************************************************************************/
package org.eclipse.mylyn.reviews.r4e.ui.internal.utils;
import java.util.Date;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.mylyn.reviews.r4e.core.model.R4EAnomaly;
import org.eclipse.mylyn.reviews.r4e.core.model.R4EFileVersion;
import org.eclipse.mylyn.reviews.r4e.core.model.serial.impl.OutOfSyncException;
import org.eclipse.mylyn.reviews.r4e.core.model.serial.impl.ResourceHandlingException;
import org.eclipse.mylyn.reviews.r4e.core.rfs.spi.ReviewsFileStorageException;
import org.eclipse.mylyn.reviews.r4e.ui.R4EUIPlugin;
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.IR4EUIModelElement;
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.IR4EUIPosition;
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIAnomalyBasic;
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIAnomalyContainer;
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIComment;
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIContent;
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIFileContext;
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIModelController;
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIReviewBasic;
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIReviewItem;
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUITextPosition;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
/**
* This class implements various utility methods used in anomaly-related commands
*
* @author Sebastien Dubois
* @version $Revision: 1.0 $
*/
public class AnomalyUtils {
// ------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------
/**
* Field WARNING_BUTTONS_LABELS.
*/
private static final String[] WARNING_BUTTONS_LABELS = { "Continue", "Cancel" }; //$NON-NLS-1$ //$NON-NLS-2$
/**
* Field VERSION_STR. (value is ""Version: "")
*/
private static final String VERSION_STR = "Version: "; //$NON-NLS-1$
/**
* Field QUESTION_TITLE. (value is ""R4E question"")
*/
private static final String QUESTION_TITLE = "R4E question"; //$NON-NLS-1$
/**
* Field WORKSPACE_FILE_STR. (value is ""Workspace file: "")
*/
private static final String WORKSPACE_FILE_STR = "Workspace file: "; //$NON-NLS-1$
/**
* Field FILE_VERSION_STR. (value is ""Selected file version to review: "")
*/
private static final String FILE_VERSION_STR = "Selected file version to review: "; //$NON-NLS-1$
/**
* Field QUESTION_STR. (value is ""Are you sure you want to add this anomaly to the workspace file ?"")
*/
private static final String QUESTION_STR = "Are you sure you want to add this anomaly to the workspace file ?"; //$NON-NLS-1$
/**
* Field MESSAGE_STR. (value is ""You are adding an anomaly to a file version which is different from the one
* selected for review."")
*/
private static final String MESSAGE_STR = "You are adding an anomaly to a file version which is different from the one selected for review."; //$NON-NLS-1$
// ------------------------------------------------------------------------
// Methods
// ------------------------------------------------------------------------
/**
* Method addAnomalyFromText.
*
* @param aSelection
* ITextSelection
* @param aInput
* - IEditorInput
*/
public static void addAnomalyFromText(ITextSelection aSelection, IEditorInput aInput, boolean aClone) {
//This is a text selection in a text editor, we need to get the file path and
//the position of the selection within the file
try {
final R4EUITextPosition position = CommandUtils.getPosition(aSelection);
final R4EFileVersion baseVersion = CommandUtils.getBaseFileData(aInput);
final R4EFileVersion targetVersion = CommandUtils.getTargetFileData(aInput);
//Add anomaly to model
if (null != targetVersion) {
addAnomaly(baseVersion, targetVersion, position, aClone);
} else {
R4EUIPlugin.Ftracer.traceWarning("Trying to add review item to base file"); //$NON-NLS-1$
final ErrorDialog dialog = new ErrorDialog(null, R4EUIConstants.DIALOG_TITLE_ERROR,
"Add Anomaly Error", new Status(IStatus.ERROR, R4EUIPlugin.PLUGIN_ID, 0, //$NON-NLS-1$
"No Target File present to Add Anomaly", null), IStatus.ERROR); //$NON-NLS-1$
Display.getDefault().syncExec(new Runnable() {
public void run() {
dialog.open();
}
});
}
} catch (CoreException e) {
UIUtils.displayCoreErrorDialog(e);
} catch (ReviewsFileStorageException e) {
UIUtils.displayReviewsFileStorageErrorDialog(e);
}
}
/**
* Method addAnomalyFromTree.
*
* @param aSelection
* ITreeSelection
* @param aMonitor
* IProgressMonitor
*/
public static void addAnomalyFromTree(Object aSelection, IProgressMonitor aMonitor, boolean aClone) {
//This is a selection from the tree view (e.g. Review Navigator, Package Explorer etc...)
//We will need to get the parent file path and the position of the element in a text editor
//If the selection is on the File itself, then the selection will include all the lines
//in the file. Otherwise it will include all the lines corresponding to the currently
//selected element
try {
R4EUITextPosition position = null;
IFile workspaceFile = null;
if (aSelection instanceof IFile) {
position = CommandUtils.getPosition((IFile) aSelection);
workspaceFile = (IFile) aSelection;
} else if (R4EUIPlugin.isJDTAvailable() && aSelection instanceof ISourceReference) {
//NOTE: This is always true because all elements that implement ISourceReference
// also implement IJavaElement. The resource is always an IFile
workspaceFile = (IFile) ((IJavaElement) aSelection).getResource();
//TODO is that the right file to get the position???
position = CommandUtils.getPosition((ISourceReference) aSelection, workspaceFile);
} else if (R4EUIPlugin.isCDTAvailable()
&& aSelection instanceof org.eclipse.cdt.core.model.ISourceReference) {
//NOTE: This is always true because all elements that implement ISourceReference
// also implement ICElement. The resource is always an IFile
if (aSelection instanceof org.eclipse.cdt.core.model.ITranslationUnit) {
workspaceFile = (IFile) ((org.eclipse.cdt.core.model.ICElement) aSelection).getResource();
} else if (aSelection instanceof org.eclipse.cdt.core.model.ICElement) {
workspaceFile = (IFile) ((org.eclipse.cdt.core.model.ICElement) aSelection).getParent()
.getResource();
} else {
//This should never happen
R4EUIPlugin.Ftracer.traceWarning("Invalid selection " + aSelection.getClass().toString() //$NON-NLS-1$
+ ". Ignoring"); //$NON-NLS-1$
return;
}
//TODO is that the right file to get the position???
position = CommandUtils.getPosition((org.eclipse.cdt.core.model.ISourceReference) aSelection,
workspaceFile);
} else {
//This should never happen
R4EUIPlugin.Ftracer.traceWarning("Invalid selection " + aSelection.getClass().toString() //$NON-NLS-1$
+ ". Ignoring"); //$NON-NLS-1$
return;
}
//Add anomaly to model
final R4EFileVersion baseVersion = CommandUtils.updateBaseFile(workspaceFile);
final R4EFileVersion targetVersion = CommandUtils.updateTargetFile(workspaceFile);
//Add anomaly to model
if (null != targetVersion) {
aMonitor.subTask("Adding " + targetVersion.getName()); //$NON-NLS-1$
addAnomaly(baseVersion, targetVersion, position, aClone);
aMonitor.worked(1);
} else {
R4EUIPlugin.Ftracer.traceWarning("Trying to add review item to base file"); //$NON-NLS-1$
final ErrorDialog dialog = new ErrorDialog(null, R4EUIConstants.DIALOG_TITLE_ERROR,
"Add Anomaly Error", new Status(IStatus.ERROR, R4EUIPlugin.PLUGIN_ID, 0, //$NON-NLS-1$
"No Target File present to Add Anomaly", null), IStatus.ERROR); //$NON-NLS-1$
Display.getDefault().syncExec(new Runnable() {
public void run() {
dialog.open();
}
});
}
} catch (CoreException e) {
UIUtils.displayCoreErrorDialog(e);
} catch (ReviewsFileStorageException e) {
UIUtils.displayReviewsFileStorageErrorDialog(e);
}
}
/**
* Method AddAnomaly. Adds an anomaly to the model based on user input
*
* @param aBaseFileVersion
* R4EFileVersion
* @param aTargetFileVersion
* R4EFileVersion
* @param aUIPosition
* IR4EUIPosition
*/
public static void addAnomaly(R4EFileVersion aBaseFileVersion, final R4EFileVersion aTargetFileVersion,
IR4EUIPosition aUIPosition, final boolean aClone) {
R4EUIFileContext tempFileContext = null;
//Find the latest commit for the selected target file
//Check if the file element and/or anomaly already exist
//If so, verify if the anomaly exist
//If not, then add anomaly element to the target file
//If anomaly element already exist, then add a new comment to it
//for all other cases, create the parent elements as needed as well.
//If the target file is not the same file version in any commit,
//Look for the file name (No version) exist in the workspace
//If found, then ask the user to continue or cancel the adding of the anomaly
final List<R4EUIReviewItem> reviewItems = R4EUIModelController.getActiveReview().getReviewItems();
//Select the latest commit to store the anomaly
Date date1 = null;
Date datelatest = null;
R4EUIAnomalyContainer anomalyContainer = null;
R4EUIFileContext file = null;
for (R4EUIReviewItem reviewItem : reviewItems) {
R4EUIFileContext[] files = (R4EUIFileContext[]) reviewItem.getChildren();
for (R4EUIFileContext selectedFile : files) {
if (null != selectedFile.getFileContext().getTarget()
&& aTargetFileVersion.getLocalVersionID().equals(
selectedFile.getFileContext().getTarget().getLocalVersionID())) {
//Initial setting
if (file == null && selectedFile.getAnomalyContainerElement() != null) {
//Set the anomaly container
file = selectedFile;
datelatest = reviewItem.getItem().getSubmitted();
}
//Set the date based on the current commit
date1 = reviewItem.getItem().getSubmitted();
if (date1 != null) { //Can be null for the review item as a resource
//Test for the latest commit up to now
if (datelatest == null || datelatest.before(date1)) {
datelatest = date1;
file = selectedFile;
}
}
}
}
}
if (null != file) {
anomalyContainer = file.getAnomalyContainerElement();
addAnomalyToExistingFileContext(file, anomalyContainer, aUIPosition, aClone);
R4EUIPlugin.Ftracer.traceInfo("Added anomaly: Target = " //$NON-NLS-1$
+ file.getFileContext().getTarget().getName()
+ ((null != file.getFileContext().getBase()) ? "Base = " //$NON-NLS-1$
+ file.getFileContext().getBase().getName() : "") + " Position = " //$NON-NLS-1$//$NON-NLS-2$
+ aUIPosition.toString());
return; //We found the file so we are done here
} else {
//Did not find the same file version, look for the same file with different version
String targetPlatformURI = aTargetFileVersion.getPlatformURI();
String targetPlatformPath = aTargetFileVersion.getRepositoryPath();
//Look if the file exist in the workspace
if (null != targetPlatformURI) {
for (R4EUIReviewItem reviewItem : reviewItems) {
R4EUIFileContext[] files = (R4EUIFileContext[]) reviewItem.getChildren();
for (R4EUIFileContext searchFile : files) {
if (null != searchFile.getFileContext().getTarget()) {
//Test if we find the file in the workspace
String reviewPlatformURI = searchFile.getFileContext().getTarget().getPlatformURI();
String reviewPlatformPath = searchFile.getFileContext().getTarget().getRepositoryPath();
if (null != reviewPlatformURI) {
//Now we can compare the path
if (reviewPlatformURI.equals(targetPlatformURI)) {
//Found the same file but not the same version
tempFileContext = searchFile;
}
} else if (null != reviewPlatformPath) {
//Test the repository path
//Now we can compare the path
if (reviewPlatformPath.equals(targetPlatformPath)) {
//Found the same file but not the same version
tempFileContext = searchFile;
}
}
}
}
}
}
//Ask a question to see if the end-user wants to continue or not
if (null != tempFileContext) {
//The file exist with a different file version
final int[] result = new int[1]; //We need this to be able to pass the result value outside. This is safe as we are using SyncExec
final R4EUIFileContext dContext = tempFileContext;
if (!UIUtils.TEST_MODE) {
Display.getDefault().syncExec(new Runnable() {
public void run() {
final MessageDialog dialog = displayDifferentFileVersionDialog(aTargetFileVersion, dContext);
result[0] = dialog.open();
}
});
} else {
result[0] = Window.OK;
}
if (result[0] == Window.CANCEL) {
// Cancel selected, so just exit here and do not add anomaly
return;
}
}
//This is a new file create it (and its parent reviewItem) and all its children
addAnomalyToNewFileContext(aBaseFileVersion, aTargetFileVersion, aUIPosition, aClone);
R4EUIPlugin.Ftracer.traceInfo("Added Anomaly: Target = " //$NON-NLS-1$
+ aTargetFileVersion.getName()
+ "_" //$NON-NLS-1$
+ aTargetFileVersion.getVersionID()
+ ((null != aBaseFileVersion) ? "Base = " + aBaseFileVersion.getName() + "_" //$NON-NLS-1$//$NON-NLS-2$
+ aBaseFileVersion.getVersionID() : "") + " Position = " + aUIPosition.toString()); //$NON-NLS-1$//$NON-NLS-2$
}
}
/**
* Method displayDifferentFileVersionDialog.
*
* @param aTargetFileVersion
* R4EFileVersion
* @param aTempFileContext
* R4EUIFileContext
* @return MessageDialog
*/
private static MessageDialog displayDifferentFileVersionDialog(R4EFileVersion aTargetFileVersion,
R4EUIFileContext aTempFileContext) {
//The file exist with a different file version
final String wsFileName = aTargetFileVersion.getRepositoryPath();
final String wsFileVersion = aTargetFileVersion.getVersionID();
final String riFileName = aTempFileContext.getTargetFileVersion().getRepositoryPath();
final String riFileVersion = aTempFileContext.getTargetFileVersion().getVersionID();
final StringBuilder sb = new StringBuilder();
sb.append(MESSAGE_STR + R4EUIConstants.LINE_FEED + R4EUIConstants.LINE_FEED);
sb.append(FILE_VERSION_STR);
sb.append(riFileName + R4EUIConstants.LINE_FEED);
sb.append(VERSION_STR);
sb.append(riFileVersion + R4EUIConstants.LINE_FEED + R4EUIConstants.LINE_FEED);
sb.append(WORKSPACE_FILE_STR);
sb.append(wsFileName + R4EUIConstants.LINE_FEED);
sb.append(VERSION_STR);
sb.append(wsFileVersion + R4EUIConstants.LINE_FEED + R4EUIConstants.LINE_FEED);
sb.append(QUESTION_STR);
final MessageDialog dialog = new MessageDialog(null, // Shell
QUESTION_TITLE, // Dialog title
null, // Dialog title image message
sb.toString(), // Dialog message
MessageDialog.WARNING, // Dialog type
WARNING_BUTTONS_LABELS, // Dialog button labels
Window.OK // Default index (selection)
);
return dialog;
}
/**
* Method addAnomalyToExistingFileContext.
*
* @param aTargetFile
* R4EUIFileContext
* @param aContainer
* R4EUIAnomalyContainer
* @param aUIPosition
* IR4EUIPosition
* @param aClone
* - boolean
*/
private static void addAnomalyToExistingFileContext(R4EUIFileContext aTargetFile, R4EUIAnomalyContainer aContainer,
IR4EUIPosition aUIPosition, boolean aClone) {
aContainer.createAnomaly(aTargetFile, (R4EUITextPosition) aUIPosition, aClone);
}
/**
* Method addAnomalyToNewFileContext.
*
* @param aBaseFileVersion
* R4EFileVersion
* @param aTargetFileVersion
* R4EFileVersion
* @param aUIPosition
* IR4EUIPosition
*/
private static void addAnomalyToNewFileContext(final R4EFileVersion aBaseFileVersion,
final R4EFileVersion aTargetFileVersion, final IR4EUIPosition aUIPosition, final boolean aClone) {
final R4EAnomaly tempAnomaly = R4EUIAnomalyContainer.createDetachedAnomaly(aClone);
if (null != tempAnomaly) {
final Job job = new Job(R4EUIAnomalyContainer.CREATE_ANOMALY_MESSAGE) {
public String familyName = R4EUIConstants.R4E_UI_JOB_FAMILY;
@Override
public boolean belongsTo(Object family) {
return familyName.equals(family);
}
@Override
public IStatus run(IProgressMonitor monitor) {
try {
final R4EUIReviewBasic uiReview = R4EUIModelController.getActiveReview();
final R4EUIReviewItem uiReviewItem = uiReview.createResourceReviewItem(aTargetFileVersion.getName());
if (null == uiReviewItem) {
return Status.CANCEL_STATUS;
}
final R4EUIFileContext uiFileContext = uiReviewItem.createFileContext(aBaseFileVersion,
aTargetFileVersion, null);
if (null == uiFileContext) {
uiReview.removeChildren(uiReviewItem, false);
return Status.CANCEL_STATUS;
}
final R4EUIAnomalyContainer uiAnomalyContainer = uiFileContext.getAnomalyContainerElement();
final R4EUIAnomalyBasic uiAnomaly = uiAnomalyContainer.createAnomalyFromDetached(
aTargetFileVersion, tempAnomaly, (R4EUITextPosition) aUIPosition, false);
R4EUIModelController.setJobInProgress(false);
UIUtils.setNavigatorViewFocus(uiAnomaly, AbstractTreeViewer.ALL_LEVELS);
} catch (ResourceHandlingException e) {
UIUtils.displayResourceErrorDialog(e);
} catch (OutOfSyncException e) {
UIUtils.displaySyncErrorDialog(e);
}
monitor.done();
return Status.OK_STATUS;
}
};
job.setUser(true);
job.schedule();
}
}
/**
* Method isAnomalyExist.
*
* @param aFile
* R4EUIFileContext
* @param aNewUiAnomaly
* R4EUIAnomalyBasic
* @return String - the name of the existing anomaly or null if none
*/
public static String isAnomalyExist(R4EUIFileContext aFile, IR4EUIPosition aNewAnomalyPosition,
String aNewAnomalyDescription) {
//Check if the same anomaly as the one to be added already exists
R4EUIAnomalyContainer anomalyContainer = aFile.getAnomalyContainerElement();
R4EUIAnomalyBasic[] existingAnomalies = (R4EUIAnomalyBasic[]) anomalyContainer.getChildren();
for (R4EUIAnomalyBasic uiAnomaly : existingAnomalies) {
if (uiAnomaly.getPosition().isSameAs(aNewAnomalyPosition)
&& uiAnomaly.getAnomaly().getDescription().equals(aNewAnomalyDescription)) {
return aNewAnomalyDescription;
}
}
return null;
}
/**
* Method isCommentExist.
*
* @param aAnomaly
* R4EUIAnomalyBasic
* @param String
* aNewCommentDescription
* @return String - the description of the existing comment or null if none
*/
public static String isCommentExist(R4EUIAnomalyBasic aAnomaly, String aNewCommentDescription) {
//Check if the same anomaly as the one to be added already exists
IR4EUIModelElement[] existingUiComments = aAnomaly.getChildren();
for (IR4EUIModelElement uiComment : existingUiComments) {
if (((R4EUIComment) uiComment).getComment().getDescription().equals(aNewCommentDescription)) {
return aNewCommentDescription;
}
}
return null;
}
/**
* Method cloneLinkedAnomaly.
*
* @param aElement
* R4EUIContent
* @throws OutOfSyncException
* @throws ResourceHandlingException
*/
public static void cloneLinkedAnomaly(R4EUIContent aTargetContent, R4EUIAnomalyBasic aSourceAnomaly)
throws ResourceHandlingException, OutOfSyncException {
final R4EUIFileContext fileContext = (R4EUIFileContext) aTargetContent.getParent().getParent();
final R4EUIAnomalyContainer container = (fileContext.getAnomalyContainerElement());
R4EUIAnomalyBasic newUiAnomaly = container.createAnomalyFromDetached(fileContext.getTargetFileVersion(),
aSourceAnomaly.getAnomaly(), (R4EUITextPosition) aTargetContent.getPosition(), true);
UIUtils.setNavigatorViewFocus(newUiAnomaly, AbstractTreeViewer.ALL_LEVELS);
}
}