blob: 2d35a42f38e94343049746861fd82d90aeda0039 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 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.jsdt.internal.ui.compare;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import org.eclipse.compare.HistoryItem;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.ResourceNode;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFileState;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.RewriteSessionEditProcessor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
import org.eclipse.wst.jsdt.core.IMember;
import org.eclipse.wst.jsdt.core.ISourceRange;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.core.dom.AST;
import org.eclipse.wst.jsdt.core.dom.ASTNode;
import org.eclipse.wst.jsdt.core.dom.ASTParser;
import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
import org.eclipse.wst.jsdt.core.dom.TypeDeclaration;
import org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.wst.jsdt.internal.corext.dom.NodeFinder;
import org.eclipse.wst.jsdt.internal.corext.util.Strings;
import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
import org.eclipse.wst.jsdt.internal.ui.actions.SelectionConverter;
import org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaEditor;
/**
* Base class for the "Replace with local history"
* and "Add from local history" actions.
*/
abstract class JavaHistoryActionImpl /* extends Action implements IActionDelegate*/ {
private boolean fModifiesFile;
private ISelection fSelection;
JavaHistoryActionImpl(boolean modifiesFile) {
fModifiesFile= modifiesFile;
}
ISelection getSelection() {
return fSelection;
}
final IFile getFile(Object input) {
return JavaElementHistoryPageSource.getInstance().getFile(input);
}
final ITypedElement[] buildEditions(ITypedElement target, IFile file) {
// setup array of editions
IFileState[] states= null;
// add available editions
try {
states= file.getHistory(null);
} catch (CoreException ex) {
JavaScriptPlugin.log(ex);
}
int count= 1;
if (states != null)
count+= states.length;
ITypedElement[] editions= new ITypedElement[count];
editions[0]= new ResourceNode(file);
if (states != null)
for (int i= 0; i < states.length; i++)
editions[i+1]= new HistoryItem(target, states[i]);
return editions;
}
final Shell getShell() {
if (fEditor != null)
return fEditor.getEditorSite().getShell();
return JavaScriptPlugin.getActiveWorkbenchShell();
}
/**
* Tries to find the given element in a working copy.
*/
final IJavaScriptElement getWorkingCopy(IJavaScriptElement input) {
// TODO: With new working copy story: original == working copy.
// Note that the previous code could result in a reconcile as side effect. Should check if that
// is still required.
return input;
}
final ASTNode getBodyContainer(JavaScriptUnit root, IMember parent) throws JavaScriptModelException {
ISourceRange sourceRange= parent.getNameRange();
ASTNode parentNode= NodeFinder.perform(root, sourceRange);
do {
if (parentNode instanceof TypeDeclaration )
return parentNode;
parentNode= parentNode.getParent();
} while (parentNode != null);
return null;
}
/**
* Returns true if the given file is open in an editor.
*/
final boolean beingEdited(IFile file) {
IDocumentProvider dp= JavaScriptPlugin.getDefault().getCompilationUnitDocumentProvider();
FileEditorInput input= new FileEditorInput(file);
return dp.getDocument(input) != null;
}
/**
* Returns an IMember or null.
*/
final IMember getEditionElement(ISelection selection) {
if (selection instanceof IStructuredSelection) {
IStructuredSelection ss= (IStructuredSelection) selection;
if (ss.size() == 1) {
Object o= ss.getFirstElement();
if (o instanceof IMember) {
IMember m= (IMember) o;
if (m.exists() && !m.isBinary() && JavaStructureCreator.hasEdition(m))
return m;
}
}
}
return null;
}
final boolean isEnabled(IFile file) {
if (file == null || ! file.exists())
return false;
if (fModifiesFile) {
// without validate/edit we would do this:
// return !file.isReadOnly();
// with validate/edit we have to return true
return true;
}
return true;
}
boolean isEnabled(ISelection selection) {
IMember m= getEditionElement(selection);
if (m == null)
return false;
IFile file= getFile(m);
if (!isEnabled(file))
return false;
return true;
}
void applyChanges(ASTRewrite rewriter, final IDocument document, final ITextFileBuffer textFileBuffer, Shell shell, boolean inEditor, Map options)
throws CoreException, InvocationTargetException, InterruptedException {
MultiTextEdit edit= new MultiTextEdit();
try {
TextEdit res= rewriter.rewriteAST(document, options);
edit.addChildren(res.removeChildren());
} catch (IllegalArgumentException e) {
JavaScriptPlugin.log(e);
}
try {
new RewriteSessionEditProcessor(document, edit, TextEdit.UPDATE_REGIONS).performEdits();
} catch (BadLocationException e) {
JavaScriptPlugin.log(e);
}
IRunnableWithProgress r= new IRunnableWithProgress() {
public void run(IProgressMonitor pm) throws InvocationTargetException {
try {
textFileBuffer.commit(pm, false);
} catch (CoreException ex) {
throw new InvocationTargetException(ex);
}
}
};
if (inEditor) {
// we don't show progress
r.run(new NullProgressMonitor());
} else {
PlatformUI.getWorkbench().getProgressService().run(true, false, r);
}
}
static String trimTextBlock(String content, String delimiter, IJavaScriptProject currentProject) {
if (content != null) {
String[] lines= Strings.convertIntoLines(content);
if (lines != null) {
Strings.trimIndentation(lines, currentProject);
return Strings.concatenate(lines, delimiter);
}
}
return null;
}
final JavaEditor getEditor(IFile file) {
FileEditorInput fei= new FileEditorInput(file);
IWorkbench workbench= JavaScriptPlugin.getDefault().getWorkbench();
IWorkbenchWindow[] windows= workbench.getWorkbenchWindows();
for (int i= 0; i < windows.length; i++) {
IWorkbenchPage[] pages= windows[i].getPages();
for (int x= 0; x < pages.length; x++) {
IEditorPart[] editors= pages[x].getDirtyEditors();
for (int z= 0; z < editors.length; z++) {
IEditorPart ep= editors[z];
if (ep instanceof JavaEditor) {
JavaEditor je= (JavaEditor) ep;
if (fei.equals(je.getEditorInput()))
return (JavaEditor) ep;
}
}
}
}
return null;
}
/**
* Executes this action with the given selection.
*/
public abstract void run(ISelection selection);
//---- Action
private JavaEditor fEditor;
private String fTitle;
private String fMessage;
void init(JavaEditor editor, String title, String message) {
fEditor= editor;
fTitle= title;
fMessage= message;
}
final JavaEditor getEditor() {
return fEditor;
}
final public void runFromEditor(IAction uiProxy) {
// this run is called from Editor
IJavaScriptElement element= null;
try {
element= SelectionConverter.getElementAtOffset(fEditor);
} catch (JavaScriptModelException e) {
// ignored
}
fSelection= element != null
? new StructuredSelection(element)
: StructuredSelection.EMPTY;
boolean isEnabled= isEnabled(fSelection);
uiProxy.setEnabled(isEnabled);
if (!isEnabled) {
MessageDialog.openInformation(getShell(), fTitle, fMessage);
return;
}
run(fSelection);
}
boolean checkEnabled() {
IJavaScriptUnit unit= SelectionConverter.getInputAsCompilationUnit(fEditor);
IFile file= getFile(unit);
return isEnabled(file);
}
final public void update(IAction uiProxy) {
uiProxy.setEnabled(checkEnabled());
}
//---- IActionDelegate
final public void selectionChanged(IAction uiProxy, ISelection selection) {
fSelection= selection;
uiProxy.setEnabled(isEnabled(selection));
}
final public void run(IAction action) {
run(fSelection);
}
static JavaScriptUnit parsePartialCompilationUnit(IJavaScriptUnit unit) {
if (unit == null) {
throw new IllegalArgumentException();
}
try {
ASTParser c= ASTParser.newParser(AST.JLS3);
c.setSource(unit);
c.setFocalPosition(0);
c.setResolveBindings(false);
c.setWorkingCopyOwner(null);
ASTNode result= c.createAST(null);
return (JavaScriptUnit) result;
} catch (IllegalStateException e) {
// convert ASTParser's complaints into old form
throw new IllegalArgumentException();
}
}
}