blob: 7032c211dfad9f8aa5468f33603946256ed3ce55 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 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.jst.jsp.ui.internal.java.refactoring;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jst.jsp.core.internal.java.search.JSPSearchSupport;
import org.eclipse.jst.jsp.ui.internal.JSPUIMessages;
import org.eclipse.jst.jsp.ui.internal.Logger;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.DocumentChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.wst.sse.core.internal.document.DocumentReader;
import org.eclipse.wst.sse.core.internal.encoding.CodedStreamCreator;
/**
* {@link DocumentChange} implementation for JSP Documents
*/
public class JSPRenameChange extends DocumentChange {
/**
* The JSP file this {@link Change} will change
*/
protected IFile fJSPFile = null;
/**
* The description of this change
*/
private String fDescription;
/**
* Create a new {@link JSPRenameChange}
*
* @param jspFile
* @param jspDoc
* @param edit
* @param description
*/
public JSPRenameChange(IFile jspFile, IDocument jspDoc, TextEdit edit, String description) {
super(JSPUIMessages.BasicRefactorSearchRequestor_6, jspDoc);
MultiTextEdit parentEdit = new MultiTextEdit();
parentEdit.addChild(edit);
super.setEdit(parentEdit);
this.fJSPFile = jspFile;
this.fDescription = description;
}
/**
* Create a new {@link JSPRenameChange} by shallow copying the given
* original {@link JSPRenameChange}.
*
* @param originalChange the {@link JSPRenameChange} to shallow copy to create
* a new {@link JSPRenameChange}
*/
public JSPRenameChange(JSPRenameChange originalChange) {
super(JSPUIMessages.BasicRefactorSearchRequestor_6, originalChange.getJSPDoc());
super.setEdit(originalChange.getEdit());
this.fJSPFile = originalChange.fJSPFile;
this.fDescription = originalChange.fDescription;
}
/**
* <p>Currently will always be {@link RefactoringStatus#OK}</p>
*
* @see org.eclipse.ltk.core.refactoring.DocumentChange#isValid(org.eclipse.core.runtime.IProgressMonitor)
*/
public RefactoringStatus isValid(IProgressMonitor pm)throws CoreException {
return new RefactoringStatus();
}
/**
* @see org.eclipse.ltk.core.refactoring.TextChange#getPreviewDocument(org.eclipse.core.runtime.IProgressMonitor)
*/
public IDocument getPreviewDocument(IProgressMonitor pm) throws CoreException {
IDocument copyDoc = new Document(this.getJSPDoc().get());
try {
super.getEdit().apply(copyDoc);
}
catch (MalformedTreeException e) {
// ignore
}
catch (BadLocationException e) {
// ignore
}
return copyDoc;
}
/**
* Performs this change and returns a {@link JSPRenameUndoChange} to undo the change.
*
* @return a {@link JSPRenameUndoChange} to undo this performed {@link Change}
* @see org.eclipse.ltk.core.refactoring.TextChange#perform(org.eclipse.core.runtime.IProgressMonitor)
*/
public Change perform(IProgressMonitor pm) throws CoreException {
Change undoChange = null;
try {
//apply edit
undoChange = super.perform(pm);
undoChange = new JSPRenameUndoChange(this, undoChange);
//save the model
saveJSPFile(this.fJSPFile, this.getJSPDoc());
} catch (MalformedTreeException e) {
Logger.logException(e);
}
return undoChange;
}
/**
* @see org.eclipse.ltk.core.refactoring.TextEditBasedChange#getName()
*/
public String getName() {
return this.fDescription;
}
/**
* <p>The modified element is the JSP {@link IFile} that this {@link Change}
* changes.</p>
*
* @see org.eclipse.ltk.core.refactoring.DocumentChange#getModifiedElement()
*/
public Object getModifiedElement() {
return this.fJSPFile;
}
/**
* <p>Convenience method to get the JSP {@link IDocument} that this {@link Change}
* edits.</p>
*
* @return the JSP {@link IDocument} that this {@link Change} edits
*/
protected IDocument getJSPDoc() {
IDocument doc = null;
try {
doc = this.acquireDocument(null);
} catch(CoreException e) {
//ignore, DocumentChange.acquireDocument will never throw it
}
return doc;
}
/**
* <p>Saves a JSP file. If the file is not open in an editor then modifies the file directly, else
* if the file is open an editor then run the save method on the open editor.</p>
*
* @param jspFile the {@link IFile} to save
* @param jspDoc the {@link IDocument} with the new content for the given {@link IFile}
*/
protected static void saveJSPFile(IFile jspFile, IDocument jspDoc) {
//if not open then save model
final ITextEditor editor = findOpenEditor(jspDoc);
try {
/* if no open editor then save the document to the file
* else save the open editor
*/
if(editor == null) {
SaveJspFileOp op = new SaveJspFileOp(jspFile, jspDoc);
op.run(JSPSearchSupport.getInstance().getProgressMonitor());
} else {
//editor save must be done on UI thread
IRunnableWithProgress runnable= new IRunnableWithProgress() {
public void run(IProgressMonitor pm) throws InterruptedException {
editor.doSave(pm);
}
};
PlatformUI.getWorkbench().getProgressService().runInUI(editor.getSite().getWorkbenchWindow(), runnable, null);
}
} catch (InvocationTargetException e) {
Logger.logException(e);
} catch (InterruptedException e) {
Logger.logException(e);
}
}
/**
* <p>Checks if a document is open in an editor and returns it if it is</p>
*
* @param jspDoc check to see if this {@link IDocument} is currently open in an editor
* @return the open {@link ITextEditor} associated with the given {@link IDocument} or
* <code>null</code> if none can be found.
*/
private static ITextEditor findOpenEditor(IDocument jspDoc) {
IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
IWorkbenchWindow w = null;
for (int i = 0; i < windows.length; i++) {
w = windows[i];
IWorkbenchPage page = w.getActivePage();
if (page != null) {
IEditorReference[] references = page.getEditorReferences();
IEditorPart editor = null;
Object o = null;
IDocument doc = null;
for (int j = 0; j < references.length; j++) {
editor = references[j].getEditor(false);
// https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=3764
// use adapter to get ITextEditor (for things like
// page designer)
o = editor.getAdapter(ITextEditor.class);
if (o != null && o instanceof ITextEditor) {
doc = ((ITextEditor) o).getDocumentProvider().getDocument(editor.getEditorInput());
if (doc != null && doc.equals(jspDoc)) {
return (ITextEditor) o;
}
}
}
}
}
return null;
}
/**
* Workspace operation to perform save on model for updated documents.
* Should only be done on models not open in an editor.
*/
private static class SaveJspFileOp extends WorkspaceModifyOperation {
private IDocument fJSPDoc = null;
private IFile fJSPFile = null;
public SaveJspFileOp(IFile jspFile, IDocument jspDoc) {
this.fJSPDoc = jspDoc;
this.fJSPFile = jspFile;
}
protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException {
// https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=3765
// save file w/ no intermediate model creation
CodedStreamCreator codedStreamCreator = new CodedStreamCreator();
Reader reader = new DocumentReader(this.fJSPDoc);
codedStreamCreator.set(this.fJSPFile, reader);
ByteArrayOutputStream codedByteStream = null;
InputStream codedStream = null;
try {
codedByteStream = codedStreamCreator.getCodedByteArrayOutputStream();
codedStream = new ByteArrayInputStream(codedByteStream.toByteArray());
if (this.fJSPFile.exists())
this.fJSPFile.setContents(codedStream, true, true, null);
else
this.fJSPFile.create(codedStream, false, null);
} catch (CoreException e) {
Logger.logException(e);
} catch (IOException e) {
Logger.logException(e);
}
finally {
try {
if(codedByteStream != null)
codedByteStream.close();
if(codedStream != null)
codedStream.close();
}
catch (IOException e){
// unlikely
}
}
}
}
}