blob: 378ab54a8edff63c679672b8bfd3b5fc6e086ad8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2017 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
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 490755
* Lucas Bullen <lbullen@redhat.com> & Ian Pun <ipun@redhat.com> - Bug 518652
* Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes
*******************************************************************************/
package org.eclipse.debug.internal.ui.importexport.launchconfigurations;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
import org.eclipse.debug.internal.core.LaunchConfiguration;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
import org.eclipse.debug.internal.ui.SWTFactory;
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchCategoryFilter;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.model.WorkbenchViewerComparator;
import org.eclipse.ui.progress.UIJob;
/**
* This calls provides the one and only wizard page to the
* export launch configurations wizard.
* @since 3.4.0
*/
public class ExportLaunchConfigurationsWizardPage extends WizardPage {
private ILaunchManager lm = DebugPlugin.getDefault().getLaunchManager();
/**
* The content provider for the tree viewer
* @since 3.4.0
*/
class ConfigContentProvider implements ITreeContentProvider {
@Override
public Object[] getChildren(Object parentElement) {
if(parentElement instanceof ILaunchConfigurationType) {
try {
return getConfigurationTypeChildren((ILaunchConfigurationType) parentElement);
}
catch (Exception e) {
DebugUIPlugin.logErrorMessage(e.getMessage());
}
}
return null;
}
@Override
public Object getParent(Object element) {
if(element instanceof ILaunchConfiguration) {
try {
return ((ILaunchConfiguration)element).getType();
} catch (CoreException e) {
return null;
}
}
return null;
}
@Override
public boolean hasChildren(Object element) {
return element instanceof ILaunchConfigurationType;
}
@Override
public Object[] getElements(Object inputElement) {
return getUsedLaunchConfigurationTypes();
}
}
private String OVERWRITE = "overwrite"; //$NON-NLS-1$
private String OLD_PATH = "oldpath"; //$NON-NLS-1$
private CheckboxTreeViewer fViewer = null;
private Text fFilePath = null;
private Button fOverwrite = null;
private ConfigContentProvider fContentProvider = null;
private IStructuredSelection selectedElements;
/**
* Constructor
*/
protected ExportLaunchConfigurationsWizardPage() {
super(WizardMessages.ExportLaunchConfigurationsWizard_0);
setTitle(WizardMessages.ExportLaunchConfigurationsWizard_0);
}
protected ExportLaunchConfigurationsWizardPage(IStructuredSelection selection) {
this();
selectedElements = selection;
}
@Override
public void createControl(Composite parent) {
Composite comp = SWTFactory.createComposite(parent, 2, 1, GridData.FILL_BOTH);
//add the check table
createViewer(comp);
//add the file path and browse button
createFilePath(comp);
//add the overwrite option
fOverwrite = SWTFactory.createCheckButton(comp, WizardMessages.ExportLaunchConfigurationsWizardPage_1, null, getDialogSettings().getBoolean(OVERWRITE), 2);
setControl(comp);
PlatformUI .getWorkbench().getHelpSystem().setHelp(comp, IDebugHelpContextIds.EXPORT_LAUNCH_CONFIGURATIONS_PAGE);
setMessage(WizardMessages.ExportLaunchConfigurationsWizardPage_7);
setPageComplete(isComplete());
}
/**
* Creates the check table viewer portion of the control
* @param parent the parent to add the check table viewer to
*/
protected void createViewer(Composite parent) {
SWTFactory.createWrapLabel(parent, WizardMessages.ExportLaunchConfigurationsWizardPage_3, 2);
Tree tree = new Tree(parent, SWT.BORDER | SWT.SINGLE | SWT.CHECK);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.horizontalSpan = 2;
tree.setLayoutData(gd);
fViewer = new CheckboxTreeViewer(tree);
fViewer.setLabelProvider(DebugUITools.newDebugModelPresentation());
fViewer.setComparator(new WorkbenchViewerComparator());
fContentProvider = new ConfigContentProvider();
fViewer.setContentProvider(fContentProvider);
fViewer.setInput(getUsedLaunchConfigurationTypes());
//we don't want to see builders....
fViewer.addFilter(new LaunchCategoryFilter(IInternalDebugUIConstants.ID_EXTERNAL_TOOL_BUILDER_LAUNCH_CATEGORY));
//need to force load the children so that select all works initially
fViewer.expandAll();
fViewer.collapseAll();
if (selectedElements != null) {
Object[] checkedElements = selectedElements.toArray();
fViewer.setCheckedElements(checkedElements);
fViewer.setExpandedElements(checkedElements);
for (Object element : checkedElements) {
updateCheckedState(element);
}
}
fViewer.addCheckStateListener(event -> {
updateCheckedState(event.getElement());
setPageComplete(isComplete());
});
Composite buttoncomp = SWTFactory.createComposite(parent, parent.getFont(), 2, 2, GridData.FILL_HORIZONTAL, 0, 0);
Button button = SWTFactory.createPushButton(buttoncomp, WizardMessages.ExportLaunchConfigurationsWizardPage_8, null);
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Object[] items = fContentProvider.getElements(fViewer.getInput());
for (Object item : items) {
fViewer.setSubtreeChecked(item, true);
}
setPageComplete(isComplete());
}
});
button = SWTFactory.createPushButton(buttoncomp, WizardMessages.ExportLaunchConfigurationsWizardPage_9, null);
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Object[] items = fContentProvider.getElements(fViewer.getInput());
for (Object item : items) {
fViewer.setSubtreeChecked(item, false);
}
setPageComplete(isComplete());
}
});
}
/**
* @return launch configuration types which currently have configuration or
* prototype children, and are therefore relevant for exporting
*/
private ILaunchConfigurationType[] getUsedLaunchConfigurationTypes() {
return Arrays.stream(DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationTypes()).filter(launchConfigType -> {
try {
return getConfigurationTypeChildren(launchConfigType).length > 0;
} catch (CoreException e) {
DebugUIPlugin.logErrorMessage(e.getMessage());
}
return true;
}).toArray(ILaunchConfigurationType[]::new);
}
private ILaunchConfiguration[] getConfigurationTypeChildren(ILaunchConfigurationType launchConfigurationTypeParent) throws CoreException {
return lm.getLaunchConfigurations(launchConfigurationTypeParent, ILaunchConfiguration.CONFIGURATION | ILaunchConfiguration.PROTOTYPE);
}
/**
* Updates the checked state of child launch configurations if the parent type is checked
* @param item
*/
protected void updateCheckedState(Object element) {
boolean state = fViewer.getChecked(element);
if(element instanceof ILaunchConfigurationType) {
Object[] items = ((ConfigContentProvider)fViewer.getContentProvider()).getChildren(element);
for (Object item : items) {
fViewer.setChecked(item, state);
}
fViewer.setGrayed(element, false);
}
else if(element instanceof ILaunchConfiguration) {
ConfigContentProvider ccp = (ConfigContentProvider) fViewer.getContentProvider();
Object parent = ccp.getParent(element);
Object[] items = ccp.getChildren(parent);
boolean checked = true;
boolean onechecked = false;
for (Object item : items) {
state = fViewer.getChecked(item);
checked &= state;
if(state) {
onechecked = true;
}
}
fViewer.setGrayed(parent, onechecked & !checked);
fViewer.setChecked(parent, checked | onechecked);
}
}
/**
* Creates the controls for the file path selection area of the page
* @param parent
*/
protected void createFilePath(Composite parent) {
Composite comp = SWTFactory.createComposite(parent, parent.getFont(), 3, 2, GridData.FILL_HORIZONTAL, 0, 10);
SWTFactory.createLabel(comp, WizardMessages.ExportLaunchConfigurationsWizardPage_4, 1);
fFilePath = SWTFactory.createText(comp, SWT.SINGLE | SWT.BORDER, 1);
String opath = getDialogSettings().get(OLD_PATH);
fFilePath.setText((opath == null ? IInternalDebugCoreConstants.EMPTY_STRING : opath));
fFilePath.addModifyListener(e -> setPageComplete(isComplete()));
Button button = SWTFactory.createPushButton(comp, WizardMessages.ExportLaunchConfigurationsWizardPage_0, null, GridData.END);
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
DirectoryDialog dd = new DirectoryDialog(getContainer().getShell(), SWT.SHEET);
dd.setText(WizardMessages.ExportLaunchConfigurationsWizard_0);
String file = dd.open();
if(file != null) {
IPath path = new Path(file);
if (path != null) {
fFilePath.setText(path.toString());
setPageComplete(isComplete());
}
}
}
});
}
/**
* Returns if the page is complete
* @return true if the page is complete and can be 'finished', false otherwise
*/
protected boolean isComplete() {
Object[] elements = fViewer.getCheckedElements();
boolean oneconfig = false;
for (Object element : elements) {
if (element instanceof ILaunchConfiguration) {
oneconfig = true;
break;
}
}
if(elements.length < 1 || !oneconfig) {
setErrorMessage(WizardMessages.ExportLaunchConfigurationsWizardPage_5);
return false;
}
String path = fFilePath.getText().trim();
if(path.equals(IInternalDebugCoreConstants.EMPTY_STRING)) {
setErrorMessage(WizardMessages.ExportLaunchConfigurationsWizardPage_6);
return false;
}
if ((new File(path)).isFile()) {
setErrorMessage(WizardMessages.ExportLaunchConfigurationsWizardPage_2);
return false;
}
setErrorMessage(null);
setMessage(WizardMessages.ExportLaunchConfigurationsWizardPage_7);
return true;
}
@Override
public Image getImage() {
return DebugUITools.getImage(IInternalDebugUIConstants.IMG_WIZBAN_EXPORT_CONFIGS);
}
/**
* This method performs the work of the page
* @return if the export job was successful or not
*/
public boolean finish() {
final String dpath = fFilePath.getText().trim();
IDialogSettings settings = getDialogSettings();
settings.put(OVERWRITE, fOverwrite.getSelection());
settings.put(OLD_PATH, dpath);
final Object[] configs = fViewer.getCheckedElements();
final boolean overwrite = fOverwrite.getSelection();
UIJob exportjob = new UIJob(getContainer().getShell().getDisplay(), WizardMessages.ExportLaunchConfigurationsWizard_0) {
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
IProgressMonitor progressMonitor = monitor != null ? monitor : new NullProgressMonitor();
IPath destpath = new Path(dpath);
File destfolder = destpath.toFile();
if(!destfolder.exists()) {
destfolder.mkdirs();
}
progressMonitor.beginTask(WizardMessages.ExportLaunchConfigurationsWizardPage_10, configs.length);
try {
List<IStatus> errors = null;
IFileStore file = null;
File newfile = null;
boolean owall = false, nowall = false;
MessageDialog dialog = null;
for (Object config : configs) {
if (progressMonitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
if (config instanceof ILaunchConfiguration) {
try {
LaunchConfiguration launchConfig = (LaunchConfiguration) config;
file = launchConfig.getFileStore();
if (file == null) {
if (errors == null) {
errors = new ArrayList<>(configs.length);
}
errors.add(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), MessageFormat.format(WizardMessages.ExportLaunchConfigurationsWizardPage_19, new Object[] { launchConfig.getName() }), null));
} else {
newfile = new File(destpath.append(file.getName()).toOSString());
if(newfile.exists() & !overwrite) {
if(nowall) {
continue;
}
dialog = new MessageDialog(DebugUIPlugin.getShell(), WizardMessages.ExportLaunchConfigurationsWizardPage_11, null, MessageFormat.format(WizardMessages.ExportLaunchConfigurationsWizardPage_12, new Object[] { file.getName() }), MessageDialog.QUESTION, new String[] {
WizardMessages.ExportLaunchConfigurationsWizardPage_13,
WizardMessages.ExportLaunchConfigurationsWizardPage_14,
WizardMessages.ExportLaunchConfigurationsWizardPage_15,
WizardMessages.ExportLaunchConfigurationsWizardPage_16,
WizardMessages.ExportLaunchConfigurationsWizardPage_17 }, 0);
if(!owall) {
int ret = dialog.open();
switch(ret) {
case 0: {
copyFile(file, newfile);
break;
}
case 1: {
owall = true;
copyFile(file, newfile);
break;
}
case 3: {
nowall = true;
break;
}
case 4: {
progressMonitor.setCanceled(true);
break;
}
default:
break;
}
}
else if(!nowall) {
copyFile(file, newfile);
}
}
else {
copyFile(file, newfile);
}
}
} catch (IOException e) {
if (errors == null) {
errors = new ArrayList<>(configs.length);
}
errors.add(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(),
e.getMessage(), e));
} catch (CoreException e) {
if (errors == null) {
errors = new ArrayList<>(configs.length);
}
errors.add(e.getStatus());
}
}
if (!progressMonitor.isCanceled()) {
progressMonitor.worked(1);
}
}
if (errors == null || errors.isEmpty()) {
return Status.OK_STATUS;
} else {
if (errors.size() == 1) {
return errors.get(0);
} else {
return new MultiStatus(DebugUIPlugin.getUniqueIdentifier(), 0,
errors.toArray(new IStatus[errors.size()]),
WizardMessages.ExportLaunchConfigurationsWizardPage_18, null);
}
}
}
finally {
progressMonitor.done();
}
}
};
exportjob.schedule();
return true;
}
/**
* Copies a file from one location to another
* @param in the file to copy
* @param out the file to be copied out to
* @throws Exception
* @since 3.5
*/
protected void copyFile(IFileStore in, File out) throws CoreException, IOException {
try (BufferedInputStream is = new BufferedInputStream(in.openInputStream(EFS.NONE, null)); BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(out))) {
byte[] buf = new byte[1024];
int i = 0;
while ((i = is.read(buf)) != -1) {
os.write(buf, 0, i);
}
}
}
}