blob: d445e3bea0e2c71c04ca2586ed3167ef0979c0b4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 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.debug.ui;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import com.ibm.icu.text.MessageFormat;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
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.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.internal.ui.DebugPluginImages;
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.stringsubstitution.SelectedResourceManager;
import org.eclipse.debug.internal.ui.stringsubstitution.StringSubstitutionMessages;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
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.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;
import org.eclipse.ui.dialogs.IWorkingSetEditWizard;
/**
* A launch configuration tab which allows the user to specify
* which resources should be refreshed when the launch
* terminates.
* <p>
* This class may be instantiated; this class is not intended
* to be subclassed.
* </p>
* @since 3.0
*/
public class RefreshTab extends AbstractLaunchConfigurationTab {
/**
* Boolean attribute indicating if a refresh scope is recursive. Default
* value is <code>false</code>.
*/
public static final String ATTR_REFRESH_RECURSIVE = DebugPlugin.getUniqueIdentifier() + ".ATTR_REFRESH_RECURSIVE"; //$NON-NLS-1$
/**
* String attribute identifying the scope of resources that should be
* refreshed after an external tool is run. The value is either a refresh
* variable or the default value, <code>null</code>, indicating no refresh.
*/
public static final String ATTR_REFRESH_SCOPE = DebugPlugin.getUniqueIdentifier() + ".ATTR_REFRESH_SCOPE"; //$NON-NLS-1$
// indicates no working set has been selected
private static final String NO_WORKING_SET = "NONE"; //$NON-NLS-1$
// Check Buttons
private Button fRefreshButton;
private Button fRecursiveButton;
// Group box
private Group fGroup;
// Radio Buttons
private Button fContainerButton;
private Button fProjectButton;
private Button fResourceButton;
private Button fWorkingSetButton;
private Button fWorkspaceButton;
// Push Button
private Button fSelectButton;
// Working set
private IWorkingSet fWorkingSet;
/**
* XML tag used to designate the root of the persisted IWorkingSet
*/
private static final String TAG_LAUNCH_CONFIGURATION_WORKING_SET= "launchConfigurationWorkingSet"; //$NON-NLS-1$
/**
* XML tag used for setting / getting the factory ID of the persisted IWorkingSet
* Bug 37143
*/
private static final String TAG_FACTORY_ID = "factoryID"; //$NON-NLS-1$
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(org.eclipse.swt.widgets.Composite)
*/
public void createControl(Composite parent) {
Composite mainComposite = new Composite(parent, SWT.NONE);
setControl(mainComposite);
PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IDebugHelpContextIds.LAUNCH_CONFIGURATION_DIALOG_REFRESH_TAB);
GridLayout layout = new GridLayout();
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
mainComposite.setLayout(layout);
mainComposite.setLayoutData(gd);
mainComposite.setFont(parent.getFont());
fRefreshButton = createCheckButton(mainComposite, StringSubstitutionMessages.RefreshTab_31);
fRefreshButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
updateEnabledState();
updateLaunchConfigurationDialog();
}
});
fGroup = new Group(mainComposite, SWT.NONE);
fGroup.setFont(mainComposite.getFont());
layout = new GridLayout();
layout.numColumns = 2;
layout.makeColumnsEqualWidth = false;
fGroup.setLayout(layout);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
fGroup.setLayoutData(gd);
SelectionAdapter adapter = new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (((Button)e.getSource()).getSelection()) {
updateEnabledState();
updateLaunchConfigurationDialog();
}
}
};
fWorkspaceButton = createRadioButton(fGroup, StringSubstitutionMessages.RefreshTab_32);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
fWorkspaceButton.setLayoutData(gd);
fWorkspaceButton.addSelectionListener(adapter);
fResourceButton = createRadioButton(fGroup, StringSubstitutionMessages.RefreshTab_33);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
fResourceButton.setLayoutData(gd);
fResourceButton.addSelectionListener(adapter);
fProjectButton = createRadioButton(fGroup, StringSubstitutionMessages.RefreshTab_34);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
fProjectButton.setLayoutData(gd);
fProjectButton.addSelectionListener(adapter);
fContainerButton = createRadioButton(fGroup, StringSubstitutionMessages.RefreshTab_35);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
fContainerButton.setLayoutData(gd);
fContainerButton.addSelectionListener(adapter);
fWorkingSetButton = createRadioButton(fGroup, StringSubstitutionMessages.RefreshTab_36);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 1;
fWorkingSetButton.setLayoutData(gd);
fWorkingSetButton.addSelectionListener(adapter);
fSelectButton = createPushButton(fGroup, StringSubstitutionMessages.RefreshTab_37, null);
gd = (GridData)fSelectButton.getLayoutData();
gd.horizontalAlignment = GridData.HORIZONTAL_ALIGN_END;
fSelectButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
selectResources();
}
});
createVerticalSpacer(fGroup, 2);
createRecursiveComponent(fGroup);
}
/**
* Prompts the user to select the resources to refresh.
*/
private void selectResources() {
IWorkingSetManager workingSetManager= PlatformUI.getWorkbench().getWorkingSetManager();
if (fWorkingSet == null){
fWorkingSet = workingSetManager.createWorkingSet(StringSubstitutionMessages.RefreshTab_40, new IAdaptable[0]);
}
IWorkingSetEditWizard wizard= workingSetManager.createWorkingSetEditWizard(fWorkingSet);
WizardDialog dialog = new WizardDialog(DebugUIPlugin.getStandardDisplay().getActiveShell(), wizard);
dialog.create();
if (dialog.open() == Window.CANCEL) {
return;
}
fWorkingSet = wizard.getSelection();
updateLaunchConfigurationDialog();
}
/**
* Creates the controls needed to edit the refresh recursive
* attribute of a launch configuration
*
* @param parent the composite to create the controls in
*/
private void createRecursiveComponent(Composite parent) {
fRecursiveButton = createCheckButton(parent, StringSubstitutionMessages.RefreshTab_0);
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
data.horizontalSpan = 2;
fRecursiveButton.setLayoutData(data);
fRecursiveButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
updateLaunchConfigurationDialog();
}
});
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
*/
public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration)
*/
public void initializeFrom(ILaunchConfiguration configuration) {
updateRefresh(configuration);
updateRecursive(configuration);
updateScope(configuration);
updateEnabledState();
}
/**
* Updates the tab to display the refresh scope specified by the launch config
*/
private void updateScope(ILaunchConfiguration configuration) {
String scope = null;
try {
scope= configuration.getAttribute(ATTR_REFRESH_SCOPE, (String)null);
} catch (CoreException ce) {
DebugUIPlugin.log(DebugUIPlugin.newErrorStatus("Exception reading launch configuration", ce)); //$NON-NLS-1$
}
fWorkspaceButton.setSelection(false);
fResourceButton.setSelection(false);
fContainerButton.setSelection(false);
fProjectButton.setSelection(false);
fWorkingSetButton.setSelection(false);
if (scope == null) {
// select the workspace by default
fWorkspaceButton.setSelection(true);
} else {
if (scope.equals("${workspace}")) { //$NON-NLS-1$
fWorkspaceButton.setSelection(true);
} else if (scope.equals("${resource}")) { //$NON-NLS-1$
fResourceButton.setSelection(true);
} else if (scope.equals("${container}")) { //$NON-NLS-1$
fContainerButton.setSelection(true);
} else if (scope.equals("${project}")) { //$NON-NLS-1$
fProjectButton.setSelection(true);
} else if (scope.startsWith("${resource:")) { //$NON-NLS-1$
fWorkingSetButton.setSelection(true);
try {
IResource[] resources = getRefreshResources(scope);
IWorkingSetManager workingSetManager= PlatformUI.getWorkbench().getWorkingSetManager();
fWorkingSet = workingSetManager.createWorkingSet(StringSubstitutionMessages.RefreshTab_40, resources);
} catch (CoreException e) {
fWorkingSet = null;
}
} else if (scope.startsWith("${working_set:")) { //$NON-NLS-1$
fWorkingSetButton.setSelection(true);
String memento = scope.substring(14, scope.length() - 1);
fWorkingSet = restoreWorkingSet(memento);
}
}
}
/**
* Method updateRecursive.
* @param configuration
*/
private void updateRecursive(ILaunchConfiguration configuration) {
boolean recursive= true;
try {
recursive= configuration.getAttribute(ATTR_REFRESH_RECURSIVE, true);
} catch (CoreException ce) {
DebugUIPlugin.log(DebugUIPlugin.newErrorStatus("Exception reading launch configuration", ce)); //$NON-NLS-1$
}
fRecursiveButton.setSelection(recursive);
}
/**
* Method updateRefresh.
* @param configuration
*/
private void updateRefresh(ILaunchConfiguration configuration) {
String scope= null;
try {
scope= configuration.getAttribute(ATTR_REFRESH_SCOPE, (String)null);
} catch (CoreException ce) {
DebugUIPlugin.log(DebugUIPlugin.newErrorStatus("Exception reading launch configuration", ce)); //$NON-NLS-1$
}
fRefreshButton.setSelection(scope != null);
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
*/
public void performApply(ILaunchConfigurationWorkingCopy configuration) {
if (fRefreshButton.getSelection()) {
String scope = generateScopeMemento();
configuration.setAttribute(ATTR_REFRESH_SCOPE, scope);
setAttribute(ATTR_REFRESH_RECURSIVE, configuration, fRecursiveButton.getSelection(), true);
} else {
//clear the refresh attributes
configuration.setAttribute(ATTR_REFRESH_SCOPE, (String)null);
setAttribute(ATTR_REFRESH_RECURSIVE, configuration, true, true);
}
}
/**
* Generates a memento for the refresh scope. This is based on old refresh
* variables.
*
* @return a memento
*/
private String generateScopeMemento() {
if (fWorkspaceButton.getSelection()) {
return "${workspace}"; //$NON-NLS-1$
}
if (fResourceButton.getSelection()) {
return "${resource}"; //$NON-NLS-1$
}
if (fContainerButton.getSelection()) {
return "${container}"; //$NON-NLS-1$
}
if (fProjectButton.getSelection()) {
return "${project}"; //$NON-NLS-1$
}
if (fWorkingSetButton.getSelection()) {
return getRefreshAttribute(fWorkingSet);
}
return null;
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName()
*/
public String getName() {
return StringSubstitutionMessages.RefreshTab_6;
}
/**
* Updates the enablement state of the fields.
*/
private void updateEnabledState() {
boolean enabled= fRefreshButton.getSelection();
fRecursiveButton.setEnabled(enabled);
fGroup.setEnabled(enabled);
fWorkspaceButton.setEnabled(enabled);
fResourceButton.setEnabled(enabled);
fContainerButton.setEnabled(enabled);
fProjectButton.setEnabled(enabled);
fWorkingSetButton.setEnabled(enabled);
fSelectButton.setEnabled(enabled && fWorkingSetButton.getSelection());
if (!enabled) {
super.setErrorMessage(null);
}
}
/**
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#getImage()
*/
public Image getImage() {
return DebugPluginImages.getImage(IInternalDebugUIConstants.IMG_OBJS_REFRESH_TAB);
}
public boolean isValid(ILaunchConfiguration launchConfig) {
setErrorMessage(null);
setMessage(null);
if (fRefreshButton.getSelection() && (fWorkingSetButton.getSelection() && (fWorkingSet == null || fWorkingSet.getElements().length == 0))) {
setErrorMessage(StringSubstitutionMessages.RefreshTab_42);
return false;
}
return true;
}
/**
* Refreshes the resources as specified by the given launch configuration.
*
* @param configuration launch configuration
* @param monitor progress monitor which may be <code>null</code>
* @throws CoreException if an exception occurs while refreshing resources
*/
public static void refreshResources(ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
String scope = getRefreshScope(configuration);
IResource[] resources= null;
if (scope != null) {
resources = getRefreshResources(scope);
}
if (resources == null || resources.length == 0){
return;
}
int depth = IResource.DEPTH_ONE;
if (isRefreshRecursive(configuration))
depth = IResource.DEPTH_INFINITE;
if (monitor.isCanceled()) {
return;
}
monitor.beginTask(StringSubstitutionMessages.RefreshTab_7,
resources.length);
MultiStatus status = new MultiStatus(DebugUIPlugin.getUniqueIdentifier(), 0, StringSubstitutionMessages.RefreshTab_8, null);
for (int i = 0; i < resources.length; i++) {
if (monitor.isCanceled())
break;
if (resources[i] != null && resources[i].isAccessible()) {
try {
resources[i].refreshLocal(depth, null);
} catch (CoreException e) {
status.merge(e.getStatus());
}
}
monitor.worked(1);
}
monitor.done();
if (!status.isOK()) {
throw new CoreException(status);
}
}
/**
* Returns a collection of resources referred to by a refresh scope attribute.
*
* @param scope refresh scope attribute (<code>ATTR_REFRESH_SCOPE</code>)
* @return collection of resources referred to by the refresh scope attribute
* @throws CoreException if unable to resolve a set of resources
*/
public static IResource[] getRefreshResources(String scope) throws CoreException {
if (scope.startsWith("${resource:")) { //$NON-NLS-1$
// This is an old format that is replaced with 'working_set'
String pathString = scope.substring(11, scope.length() - 1);
Path path = new Path(pathString);
IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
if (resource == null) {
throw new CoreException(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), IDebugUIConstants.INTERNAL_ERROR, MessageFormat.format(StringSubstitutionMessages.RefreshTab_38, new String[]{pathString}), null));
}
return new IResource[]{resource};
} else if (scope.startsWith("${working_set:")) { //$NON-NLS-1$
IWorkingSet workingSet = getWorkingSet(scope);
if (workingSet == null) {
throw new CoreException(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), IDebugUIConstants.INTERNAL_ERROR, StringSubstitutionMessages.RefreshTab_39, null));
}
IAdaptable[] elements = workingSet.getElements();
IResource[] resources = new IResource[elements.length];
for (int i = 0; i < elements.length; i++) {
IAdaptable adaptable = elements[i];
if (adaptable instanceof IResource) {
resources[i] = (IResource) adaptable;
} else {
resources[i] = (IResource) adaptable.getAdapter(IResource.class);
}
}
return resources;
} else if(scope.equals("${workspace}")) { //$NON-NLS-1$
return new IResource[]{ResourcesPlugin.getWorkspace().getRoot()};
} else {
IResource resource = SelectedResourceManager.getDefault().getSelectedResource();
if (resource == null) {
// empty selection
return new IResource[]{};
}
if (scope.equals("${resource}")) { //$NON-NLS-1$
// resource = resource
} else if (scope.equals("${container}")) { //$NON-NLS-1$
resource = resource.getParent();
} else if (scope.equals("${project}")) { //$NON-NLS-1$
resource = resource.getProject();
}
return new IResource[]{resource};
}
}
/**
* Restores a working set based on the XMLMemento represented within
* the mementoString.
*
* @param mementoString The string memento of the working set
* @return the restored working set or <code>null</code> if problems occurred restoring the
* working set.
*/
private static IWorkingSet restoreWorkingSet(String mementoString) {
if (NO_WORKING_SET.equals(mementoString)) {
return null;
}
StringReader reader= new StringReader(mementoString);
XMLMemento memento= null;
try {
memento = XMLMemento.createReadRoot(reader);
} catch (WorkbenchException e) {
DebugUIPlugin.log(e);
return null;
}
IWorkingSetManager workingSetManager= PlatformUI.getWorkbench().getWorkingSetManager();
return workingSetManager.createWorkingSet(memento);
}
/**
* Returns the refresh scope attribute specified by the given launch configuration
* or <code>null</code> if none.
*
* @param configuration launch configuration
* @return refresh scope attribute (<code>ATTR_REFRESH_SCOPE</code>)
* @throws CoreException if unable to access the associated attribute
*/
public static String getRefreshScope(ILaunchConfiguration configuration) throws CoreException {
return configuration.getAttribute(ATTR_REFRESH_SCOPE, (String) null);
}
/**
* Returns whether the refresh scope specified by the given launch
* configuration is recursive.
*
* @param configuration
* @return whether the refresh scope is recursive
* @throws CoreException if unable to access the associated attribute
*/
public static boolean isRefreshRecursive(ILaunchConfiguration configuration) throws CoreException {
return configuration.getAttribute(ATTR_REFRESH_RECURSIVE, true);
}
/**
* Creates and returns a memento for the given working set, to be used as a
* refresh attribute.
*
* @param workingSet a working set, or <code>null</code>
* @return an equivalent refresh attribute
*/
public static String getRefreshAttribute(IWorkingSet workingSet) {
String set = null;
if (workingSet == null || workingSet.getElements().length == 0) {
set = NO_WORKING_SET;
} else {
XMLMemento workingSetMemento = XMLMemento.createWriteRoot(TAG_LAUNCH_CONFIGURATION_WORKING_SET);
workingSetMemento.putString(RefreshTab.TAG_FACTORY_ID, workingSet.getFactoryId());
workingSet.saveState(workingSetMemento);
StringWriter writer= new StringWriter();
try {
workingSetMemento.save(writer);
} catch (IOException e) {
DebugUIPlugin.log(e);
}
set = writer.toString();
}
if (set != null) {
StringBuffer memento = new StringBuffer();
memento.append("${working_set:"); //$NON-NLS-1$
memento.append(set);
memento.append("}"); //$NON-NLS-1$
return memento.toString();
}
return null;
}
/**
* Creates and returns a working set from the given refresh attribute created by
* the method <code>getRefreshAttribute(IWorkingSet)</code>, or <code>null</code>
* if none.
*
* @param refreshAttribute a refresh attribute that represents a working set
* @return equivalent working set, or <code>null</code>
*/
public static IWorkingSet getWorkingSet(String refreshAttribute) {
if (refreshAttribute.startsWith("${working_set:")) { //$NON-NLS-1$
String memento = refreshAttribute.substring(14, refreshAttribute.length() - 1);
return restoreWorkingSet(memento);
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#activated(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
*/
public void activated(ILaunchConfigurationWorkingCopy workingCopy) {
// do nothing on activation
}
/* (non-Javadoc)
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#deactivated(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
*/
public void deactivated(ILaunchConfigurationWorkingCopy workingCopy) {
// do nothing on deactivation
}
}