blob: 5aff561b5269e63cd23a07ff63cfa43f2e1d23e8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2008 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ltk.internal.ui.refactoring.scripting;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.core.runtime.Assert;
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.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.IWizardContainer;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ltk.core.refactoring.RefactoringCore;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptorProxy;
import org.eclipse.ltk.core.refactoring.history.RefactoringHistory;
import org.eclipse.ltk.internal.core.refactoring.IRefactoringSerializationConstants;
import org.eclipse.ltk.internal.core.refactoring.history.RefactoringHistoryManager;
import org.eclipse.ltk.internal.ui.refactoring.Messages;
import org.eclipse.ltk.internal.ui.refactoring.RefactoringPluginImages;
import org.eclipse.ltk.internal.ui.refactoring.RefactoringUIMessages;
import org.eclipse.ltk.internal.ui.refactoring.RefactoringUIPlugin;
/**
* Wizard to create a refactoring script.
*
* @since 3.2
*/
public final class CreateRefactoringScriptWizard extends Wizard {
/** The dialog settings key */
private static String DIALOG_SETTINGS_KEY= "CreateRefactoringScriptWizard"; //$NON-NLS-1$
/** Has the wizard new dialog settings? */
private boolean fNewSettings;
/** The selected refactoring descriptors, or the empty array */
private RefactoringDescriptorProxy[] fRefactoringDescriptors= {};
/** The refactoring history */
private RefactoringHistory fRefactoringHistory;
/** The refactoring script location, or <code>null</code> */
private URI fScriptLocation= null;
/** Should the wizard put the refactoring script to the clipboard? */
private boolean fUseClipboard= false;
/** The create refactoring script wizard page */
private final CreateRefactoringScriptWizardPage fWizardPage;
/**
* Creates a new create refactoring script wizard.
*/
public CreateRefactoringScriptWizard() {
setNeedsProgressMonitor(false);
setWindowTitle(ScriptingMessages.CreateRefactoringScriptWizard_caption);
setDefaultPageImageDescriptor(RefactoringPluginImages.DESC_WIZBAN_CREATE_SCRIPT);
final IDialogSettings settings= RefactoringUIPlugin.getDefault().getDialogSettings();
final IDialogSettings section= settings.getSection(DIALOG_SETTINGS_KEY);
if (section == null)
fNewSettings= true;
else {
fNewSettings= false;
setDialogSettings(section);
}
fWizardPage= new CreateRefactoringScriptWizardPage(this);
}
@Override
public void addPages() {
super.addPages();
addPage(fWizardPage);
}
@Override
public boolean canFinish() {
return (fUseClipboard || fScriptLocation != null) && fRefactoringDescriptors.length > 0;
}
/**
* Returns the refactoring history to create a script from.
*
* @return the refactoring history.
*/
public RefactoringHistory getRefactoringHistory() {
return fRefactoringHistory;
}
/**
* Performs the actual refactoring script export.
*
* @return <code>true</code> if the wizard can be finished,
* <code>false</code> otherwise
*/
private boolean performExport() {
RefactoringDescriptorProxy[] writable= fRefactoringDescriptors;
if (fScriptLocation != null) {
final File file= new File(fScriptLocation);
if (file.exists()) {
final MessageDialog message= new MessageDialog(getShell(), getShell().getText(), null, Messages.format(ScriptingMessages.CreateRefactoringScriptWizard_overwrite_query, new String[] { ScriptingMessages.CreateRefactoringScriptWizard_merge_button, ScriptingMessages.CreateRefactoringScriptWizard_overwrite_button}), MessageDialog.QUESTION, new String[] { ScriptingMessages.CreateRefactoringScriptWizard_merge_button, ScriptingMessages.CreateRefactoringScriptWizard_overwrite_button, IDialogConstants.CANCEL_LABEL}, 0);
final int result= message.open();
if (result == 0) {
InputStream stream= null;
try {
stream= new BufferedInputStream(new FileInputStream(file));
final RefactoringDescriptorProxy[] existing= RefactoringCore.getHistoryService().readRefactoringHistory(stream, RefactoringDescriptor.NONE).getDescriptors();
final Set<RefactoringDescriptorProxy> set= new HashSet<>();
set.addAll(Arrays.asList(existing));
set.addAll(Arrays.asList(fRefactoringDescriptors));
writable= new RefactoringDescriptorProxy[set.size()];
set.toArray(writable);
} catch (FileNotFoundException exception) {
MessageDialog.openError(getShell(), RefactoringUIMessages.ChangeExceptionHandler_refactoring, exception.getLocalizedMessage());
return false;
} catch (CoreException exception) {
handleCoreException(exception);
return false;
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException exception) {
// Do nothing
}
}
}
} else if (result == 2)
return false;
}
OutputStream stream= null;
try {
File parentFile= file.getParentFile();
if (parentFile != null)
parentFile.mkdirs();
stream= new BufferedOutputStream(new FileOutputStream(file));
writeRefactoringDescriptorProxies(writable, stream);
return true;
} catch (CoreException exception) {
handleCoreException(exception);
return false;
} catch (FileNotFoundException exception) {
MessageDialog.openError(getShell(), RefactoringUIMessages.ChangeExceptionHandler_refactoring, exception.getLocalizedMessage());
return false;
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException exception) {
// Do nothing
}
}
}
} else if (fUseClipboard) {
try {
final ByteArrayOutputStream stream= new ByteArrayOutputStream(2048);
writeRefactoringDescriptorProxies(writable, stream);
try {
final String string= stream.toString(IRefactoringSerializationConstants.OUTPUT_ENCODING);
Clipboard clipboard= null;
try {
clipboard= new Clipboard(getShell().getDisplay());
try {
clipboard.setContents(new Object[] { string}, new Transfer[] { TextTransfer.getInstance()});
return true;
} catch (SWTError error) {
MessageDialog.openError(getShell(), RefactoringUIMessages.ChangeExceptionHandler_refactoring, error.getLocalizedMessage());
return false;
}
} finally {
if (clipboard != null)
clipboard.dispose();
}
} catch (UnsupportedEncodingException exception) {
// Does not happen
return false;
}
} catch (CoreException exception) {
handleCoreException(exception);
return false;
}
}
return false;
}
private void handleCoreException(CoreException exception) {
IStatus status= exception.getStatus();
final Throwable throwable= status.getException();
if (throwable instanceof IOException) {
MessageDialog.openError(getShell(), RefactoringUIMessages.ChangeExceptionHandler_refactoring, throwable.getLocalizedMessage());
} else {
MessageDialog.openError(getShell(), RefactoringUIMessages.ChangeExceptionHandler_refactoring, status.getMessage());
RefactoringUIPlugin.log(exception);
}
}
@Override
public boolean performFinish() {
if (fNewSettings) {
final IDialogSettings settings= RefactoringUIPlugin.getDefault().getDialogSettings();
IDialogSettings section= settings.getSection(DIALOG_SETTINGS_KEY);
section= settings.addNewSection(DIALOG_SETTINGS_KEY);
setDialogSettings(section);
}
fWizardPage.performFinish();
return performExport();
}
/**
* Sets the selected refactoring descriptors.
*
* @param proxies
* the selected refactoring descriptors
*/
public void setRefactoringDescriptors(final RefactoringDescriptorProxy[] proxies) {
Assert.isNotNull(proxies);
fRefactoringDescriptors= proxies;
final IWizardContainer wizard= getContainer();
if (wizard.getCurrentPage() != null)
wizard.updateButtons();
}
/**
* Sets the refactoring history to use.
*
* @param history
* the refactoring history to use
*/
public void setRefactoringHistory(final RefactoringHistory history) {
Assert.isNotNull(history);
fRefactoringHistory= history;
}
/**
* Sets the refactoring script location.
*
* @param location
* the refactoring script location, or <code>null</code>
*/
public void setRefactoringScript(final URI location) {
fScriptLocation= location;
final IWizardContainer wizard= getContainer();
if (wizard.getCurrentPage() != null)
wizard.updateButtons();
}
/**
* Determines whether the wizard should save the refactoring script to the
* clipboard.
*
* @param clipboard
* <code>true</code> to save the script to clipboard,
* <code>false</code> otherwise
*/
public void setUseClipboard(final boolean clipboard) {
fUseClipboard= clipboard;
final IWizardContainer wizard= getContainer();
if (wizard.getCurrentPage() != null)
wizard.updateButtons();
}
/**
* Writes the refactoring descriptor proxies to the specified output stream.
*
* @param writable
* the refactoring descriptor proxies
* @param stream
* the output stream to write to
* @throws CoreException
* if an error occurs
*/
private void writeRefactoringDescriptorProxies(final RefactoringDescriptorProxy[] writable, final OutputStream stream) throws CoreException {
RefactoringHistoryManager.sortRefactoringDescriptorsAscending(writable);
try {
getContainer().run(false, false, new IRunnableWithProgress() {
@Override
public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
RefactoringCore.getHistoryService().writeRefactoringDescriptors(writable, stream, RefactoringDescriptor.NONE, false, monitor);
} catch (CoreException exception) {
throw new InvocationTargetException(exception);
}
}
});
} catch (InvocationTargetException exception) {
final Throwable throwable= exception.getTargetException();
if (throwable instanceof CoreException) {
final CoreException extended= (CoreException) throwable;
throw extended;
} else {
throw new CoreException(new Status(IStatus.ERROR, RefactoringCore.ID_PLUGIN, ScriptingMessages.CreateRefactoringScriptWizard_unexpected_exception, throwable));
}
} catch (InterruptedException exception) {
// Do nothing
}
}
}