/******************************************************************************* * Copyright (c) 2000, 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.debug.internal.ui.launchConfigurations; import java.lang.reflect.InvocationTargetException; import java.util.HashSet; import java.util.List; import java.util.Set; 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.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchDelegate; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; import org.eclipse.debug.internal.core.LaunchConfigurationWorkingCopy; import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; import org.eclipse.debug.internal.ui.SWTFactory; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.debug.ui.ILaunchConfigurationDialog; import org.eclipse.debug.ui.ILaunchConfigurationTab; import org.eclipse.debug.ui.ILaunchConfigurationTabGroup; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.resource.ColorRegistry; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.custom.CTabItem; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.custom.ViewForm; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; 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.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbenchPreferenceConstants; import org.eclipse.ui.PlatformUI; import com.ibm.icu.text.MessageFormat; /** * A viewer that displays tabs for a launch configuration, with apply and revert * buttons. */ public class LaunchConfigurationTabGroupViewer { /** * Containing launch dialog */ private ILaunchConfigurationDialog fDialog; /** * The this viewer's input */ private Object fInput; /** * The launch configuration (original) being edited */ private ILaunchConfiguration fOriginal; /** * The working copy of the original */ private ILaunchConfigurationWorkingCopy fWorkingCopy; /** * This view's control, which contains a composite area of controls */ private Composite fViewerControl; /** * The composite which is hidden/displayed as tabs are required. */ private Composite fVisibleArea; /** * Name label widget */ private Label fNameLabel; /** * Name text widget */ private Text fNameWidget; /** * Composite containing the launch config tab widgets */ private Composite fTabComposite; /** * Tab folder */ private CTabFolder fTabFolder; /** * The current tab group being displayed */ private ILaunchConfigurationTabGroup fTabGroup; /** * The type of config tabs are currently displayed * for */ private ILaunchConfigurationType fTabType; /** * Index of the active tab */ private int fCurrentTabIndex = -1; /** * Apply & Revert buttons */ private Button fApplyButton; private Button fRevertButton; /** * Whether tabs are currently being disposed or initialized */ private boolean fDisposingTabs = false; private boolean fInitializingTabs = false; /** * The description of the currently selected launch configuration or * launch configuration type or null if none. */ private String fDescription = null; /** * A place holder for switching between the tabs for a config and the getting started tab * @since 3.2 */ private Composite fTabPlaceHolder = null; /** * A link to allow users to select a valid set of launch options for the specified mode * @since 3.3 */ private Link fOptionsLink = null; /** * A label to indicate that the user needs to select an a launcher. * @since 3.5 */ private Label fOptionsErrorLabel = null; /** * A new composite replacing the perspectives tab * @since 3.2 */ private Composite fGettingStarted = null; private ViewForm fViewform; /** * Constructs a viewer in the given composite, contained by the given * launch configuration dialog. * * @param parent composite containing this viewer * @param dialog containing launch configuration dialog */ public LaunchConfigurationTabGroupViewer(Composite parent, ILaunchConfigurationDialog dialog) { super(); fDialog = dialog; createControl(parent); } /** * Cleanup */ public void dispose() { disposeTabGroup(); } /** * Dispose the active tab group, if any. */ protected void disposeTabGroup() { if (fTabGroup != null) { fTabGroup.dispose(); fTabGroup = null; fTabType = null; } } /** * Creates this viewer's control This area displays the name of the launch * configuration currently being edited, as well as a tab folder of tabs * that are applicable to the launch configuration. * * @return the composite used for launch configuration editing */ private void createControl(Composite parent) { fViewerControl = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(); layout.numColumns = 1; layout.marginHeight = 0; layout.marginWidth = 0; layout.horizontalSpacing = 0; layout.verticalSpacing = 0; fViewerControl.setLayout(layout); GridData gd = new GridData(GridData.FILL_BOTH); fViewerControl.setLayoutData(gd); fViewform = new ViewForm(fViewerControl, SWT.FLAT | SWT.BORDER); layout = new GridLayout(1, false); layout.horizontalSpacing = 0; layout.verticalSpacing = 0; fViewform.setLayout(layout); gd = new GridData(GridData.FILL_BOTH); fViewform.setLayoutData(gd); fVisibleArea = fViewform; fViewform.setTopLeft(null); Composite mainComp = new Composite(fViewform, SWT.FLAT); layout = new GridLayout(1, false); layout.verticalSpacing = 0; layout.horizontalSpacing = 0; mainComp.setLayout(layout); fViewform.setContent(mainComp); fTabPlaceHolder = new Composite(mainComp, SWT.NONE); fTabPlaceHolder.setLayout(new StackLayout()); gd = new GridData(GridData.FILL_BOTH); fTabPlaceHolder.setLayoutData(gd); fGettingStarted = new Composite(fTabPlaceHolder, SWT.NONE); fGettingStarted.setLayout(new GridLayout()); gd = new GridData(GridData.FILL_BOTH); fGettingStarted.setLayoutData(gd); createGettingStarted(fGettingStarted); fTabComposite = new Composite(fTabPlaceHolder, SWT.NONE); layout = new GridLayout(2, false); layout.verticalSpacing = 10; layout.horizontalSpacing = 5; fTabComposite.setLayout(layout); gd = new GridData(GridData.FILL_BOTH); fTabComposite.setLayoutData(gd); fNameLabel = new Label(fTabComposite, SWT.HORIZONTAL | SWT.LEFT); fNameLabel.setText(LaunchConfigurationsMessages.LaunchConfigurationDialog__Name__16); fNameLabel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); fNameWidget = new Text(fTabComposite, SWT.SINGLE | SWT.BORDER); fNameWidget.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); fNameWidget.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { if(!fInitializingTabs) { handleNameModified(); } } } ); createTabFolder(fTabComposite); Composite blComp = SWTFactory.createComposite(mainComp, mainComp.getFont(), 2, 1, GridData.FILL_HORIZONTAL); Composite linkComp = SWTFactory.createComposite(blComp, blComp.getFont(), 2, 1, GridData.FILL_HORIZONTAL); //a link for launch options fOptionsErrorLabel = new Label(linkComp, SWT.NONE); gd = new GridData(); fOptionsErrorLabel.setLayoutData(gd); fOptionsLink = new Link(linkComp, SWT.WRAP); fOptionsLink.setFont(linkComp.getFont()); gd = new GridData(SWT.LEFT); gd.grabExcessHorizontalSpace = true; fOptionsLink.setLayoutData(gd); fOptionsLink.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { //collect the options available try { if(!canLaunchWithModes()) { SelectLaunchModesDialog sld = new SelectLaunchModesDialog(getShell(), getLaunchConfigurationDialog().getMode(), getWorkingCopy()); if(sld.open() == IDialogConstants.OK_ID) { //set the options to the config Object[] res = sld.getResult(); if(res != null) { Set modes = (Set) res[0]; modes.remove(getLaunchConfigurationDialog().getMode()); ILaunchConfigurationWorkingCopy wc = getWorkingCopy(); wc.setModes(modes); refreshStatus(); } } } else if(hasMultipleDelegates()) { SelectLaunchersDialog sldd = new SelectLaunchersDialog(getShell(), getWorkingCopy().getType().getDelegates(getCurrentModeSet()), getWorkingCopy(), getLaunchConfigurationDialog().getMode()); if(sldd.open() == IDialogConstants.OK_ID) { displayInstanceTabs(true); refreshStatus(); } } } catch (CoreException ex) {} } }); fOptionsLink.setVisible(false); Composite buttonComp = new Composite(blComp, SWT.NONE); GridLayout buttonCompLayout = new GridLayout(); buttonCompLayout.numColumns = 2; buttonComp.setLayout(buttonCompLayout); gd = new GridData(GridData.HORIZONTAL_ALIGN_END); buttonComp.setLayoutData(gd); fApplyButton = new Button(buttonComp, SWT.PUSH); fApplyButton.setText(LaunchConfigurationsMessages.LaunchConfigurationDialog__Apply_17); gd = new GridData(GridData.HORIZONTAL_ALIGN_END); fApplyButton.setLayoutData(gd); SWTFactory.setButtonDimensionHint(fApplyButton); fApplyButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent evt) { handleApplyPressed(); } }); fRevertButton = new Button(buttonComp, SWT.PUSH); fRevertButton.setText(LaunchConfigurationsMessages.LaunchConfigurationDialog_Revert_2); gd = new GridData(GridData.HORIZONTAL_ALIGN_END); fRevertButton.setLayoutData(gd); SWTFactory.setButtonDimensionHint(fRevertButton); fRevertButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent evt) { handleRevertPressed(); } }); Dialog.applyDialogFont(parent); } /** * Creates some help text for the tab group launch types * @param parent the parent composite * @since 3.2 */ private void createGettingStarted(Composite parent) { Font font = parent.getFont(); GridData gd = null; int width = parent.getBounds().width - 30; SWTFactory.createWrapLabel(parent, LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_1, 1, width); SWTFactory.createWrapCLabel(parent, LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_2, DebugUITools.getImage(IInternalDebugUIConstants.IMG_ELCL_NEW_CONFIG), 1, width); SWTFactory.createWrapCLabel(parent, LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_6, DebugUITools.getImage(IInternalDebugUIConstants.IMG_ELCL_DUPLICATE_CONFIG), 1, width); SWTFactory.createWrapCLabel(parent, LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_4, DebugUITools.getImage(IInternalDebugUIConstants.IMG_ELCL_DELETE_CONFIG), 1, width); SWTFactory.createWrapCLabel(parent, LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_8, DebugUITools.getImage(IInternalDebugUIConstants.IMG_ELCL_FILTER_CONFIGS), 1, width); SWTFactory.createWrapCLabel(parent, LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_3, DebugUITools.getImage(IInternalDebugUIConstants.IMG_OVR_TRANSPARENT), 1, width); SWTFactory.createHorizontalSpacer(parent, 2); Link link = new Link(parent, SWT.LEFT | SWT.WRAP); link.setText(LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_5); link.setFont(font); gd = new GridData(GridData.FILL_HORIZONTAL); gd.widthHint = width; link.setLayoutData(gd); link.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { SWTFactory.showPreferencePage("org.eclipse.debug.ui.PerspectivePreferencePage"); //$NON-NLS-1$ } }); } /** * Creates the tab folder for displaying config instances * @param parent */ private void createTabFolder(Composite parent) { if (fTabFolder == null) { ColorRegistry reg = JFaceResources.getColorRegistry(); Color c1 = reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_START"), //$NON-NLS-1$ c2 = reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_END"); //$NON-NLS-1$ fTabFolder = new CTabFolder(parent, SWT.NO_REDRAW_RESIZE | SWT.NO_TRIM | SWT.FLAT); GridData gd = new GridData(GridData.FILL_BOTH); gd.horizontalSpan = 2; fTabFolder.setSelectionBackground(new Color[] {c1, c2}, new int[] {100}, true); fTabFolder.setSelectionForeground(reg.get("org.eclipse.ui.workbench.ACTIVE_TAB_TEXT_COLOR")); //$NON-NLS-1$ fTabFolder.setSimple(PlatformUI.getPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS)); fTabFolder.setLayoutData(gd); fTabFolder.setBorderVisible(true); fTabFolder.setFont(parent.getFont()); fTabFolder.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { if (!fInitializingTabs) { handleTabSelected(); refresh(); } } }); } } /** * Returns the apply button */ protected Button getApplyButton() { return fApplyButton; } /** * Returns the revert button */ protected Button getRevertButton() { return fRevertButton; } /** * Sets the current name */ public void setName(String name) { if (getWorkingCopy() != null) { if (name == null) { fNameWidget.setText(IInternalDebugCoreConstants.EMPTY_STRING); } else { fNameWidget.setText(name.trim()); } refreshStatus(); } } /** * @see org.eclipse.jface.viewers.Viewer#getControl() */ public Control getControl() { return fViewerControl; } /** * Returns the shell this viewer is contained in. */ private Shell getShell() { return getControl().getShell(); } /** * Returns the current input to the viewer. Input will * be one of {@link ILaunchConfiguration} or {@link ILaunchConfigurationType} * * @return returns the current input */ public Object getInput() { return fInput; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.Viewer#refresh() */ public void refresh() { if (fInitializingTabs) { return; } if(fOriginal != null && fOriginal.isReadOnly()) { updateButtons(); return; } ILaunchConfigurationTab[] tabs = getTabs(); if (tabs != null) { // update the working copy from the active tab boolean newwc = !getWorkingCopy().isDirty(); ILaunchConfigurationTab tab = getActiveTab(); if (tab != null) { tab.performApply(getWorkingCopy()); } if((fOriginal instanceof ILaunchConfigurationWorkingCopy) && newwc) { try { ILaunchConfigurationWorkingCopy copy = getWorkingCopy(); if(copy != null) { copy.doSave(); } } catch (CoreException e) {DebugUIPlugin.log(e);} } updateButtons(); // update error ticks CTabItem item = null; boolean error = false; Image image = null; for (int i = 0; i < tabs.length; i++) { item = fTabFolder.getItem(i); image = tabs[i].getImage(); item.setImage(image); if(!tabs[i].isValid(getWorkingCopy())) { error = tabs[i].getErrorMessage() != null; if(error) { item.setImage(DebugUIPlugin.getDefault().getLaunchConfigurationManager().getErrorTabImage(tabs[i])); } } } showLink(); getLaunchConfigurationDialog().updateMessage(); } } /** * Shows the link for either multiple launch delegates or bad launch mode combinations * * @since 3.3 */ private void showLink() { String text = null; if(!canLaunchWithModes()) { text = LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_13; } else if(hasMultipleDelegates()) { ILaunchDelegate delegate = getPreferredDelegate(); if(delegate != null) { String name = delegate.getName(); if(name == null) { text = LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_15; } else { text = MessageFormat.format(LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_16, new String[] {name}); } } else { text = LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_17; } } if(text != null) { fOptionsLink.setText(text); } fOptionsLink.setVisible(!canLaunchWithModes() || hasMultipleDelegates()); if (hasDuplicateDelegates()) { fOptionsErrorLabel.setImage(JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_ERROR)); } else { fOptionsErrorLabel.setImage(null); } fViewform.layout(true, true); } /** * Returns the preferred launch delegate for the current launch configuration and mode set * @return the preferred launch delegate * * @since 3.3 */ protected ILaunchDelegate getPreferredDelegate() { ILaunchDelegate preferred = null; ILaunchConfigurationWorkingCopy config = getWorkingCopy(); if(config != null) { try { Set modes = getCurrentModeSet(); preferred = config.getPreferredDelegate(modes); if(preferred == null) { preferred = config.getType().getPreferredDelegate(modes); } } catch(CoreException ce) {DebugUIPlugin.log(ce);} } return preferred; } /** * Returns the listing of modes for the current config * @return the listing of modes for the current config * @since 3.3 */ private Set getCurrentModeSet() { Set set = new HashSet(); ILaunchConfigurationWorkingCopy config = getWorkingCopy(); if(config != null) { try { set.addAll(config.getModes()); set.add(getLaunchConfigurationDialog().getMode()); } catch(CoreException ce) {DebugUIPlugin.log(ce);} } return set; } /** * updates the button states */ private void updateButtons() { boolean dirty = isDirty() && canSave(); fApplyButton.setEnabled(dirty); fRevertButton.setEnabled(dirty); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.Viewer#setInput(java.lang.Object) */ public void setInput(final Object input) { if(DebugUIPlugin.getStandardDisplay().getThread().equals(Thread.currentThread())) { setInput0(input); } else { DebugUIPlugin.getStandardDisplay().syncExec(new Runnable() { public void run() { setInput0(input); } }); } } /** * Sets the input to the tab group viewer * @param input the new input * @since 3.3 */ private void setInput0(Object input) { if (input == null) { if (fInput == null) { return; } inputChanged(input); } else { if (!input.equals(fInput)) { inputChanged(input); } } } /** * The input has changed to the given object, possibly null. * * @param input the new input, possibly null */ protected void inputChanged(Object input) { fInput = input; Runnable r = new Runnable() { public void run() { try { fVisibleArea.setRedraw(false); if (fInput instanceof ILaunchConfiguration) { ILaunchConfiguration configuration = (ILaunchConfiguration)fInput; boolean refreshtabs = !delegatesEqual(fWorkingCopy, configuration); fOriginal = configuration; fWorkingCopy = configuration.getWorkingCopy(); displayInstanceTabs(refreshtabs); } else if (fInput instanceof ILaunchConfigurationType) { fDescription = getDescription((ILaunchConfigurationType)fInput); setNoInput(); } else { setNoInput(); } } catch (CoreException ce) { errorDialog(ce); setNoInput(); } finally { refreshStatus(); fVisibleArea.setRedraw(true); } } }; BusyIndicator.showWhile(getShell().getDisplay(), r); } /** * Sets the tab group viewer to have no input, this is the case when null is passed as an input type * Setting no input is equivalent to resetting all items, clearing any messages and showing the 'getting started' pane * @since 3.2 */ private void setNoInput() { fOriginal = null; fWorkingCopy = null; disposeExistingTabs(); updateButtons(); updateVisibleControls(false); ILaunchConfigurationDialog lcd = getLaunchConfigurationDialog(); if(lcd instanceof LaunchConfigurationsDialog) { if(((LaunchConfigurationsDialog)lcd).isTreeSelectionEmpty()) { fDescription = IInternalDebugCoreConstants.EMPTY_STRING; } } } /** * Returns if the two configurations are using the same ILaunchDelegate or not * @param config1 * @param config2 * @return true if the configurations are using the same ILaunchDelegate or false if they are not * @since 3.3 */ protected boolean delegatesEqual(ILaunchConfiguration config1, ILaunchConfiguration config2) { try { if(config1 == null || config2 == null) { return false; } Set modes = getCurrentModeSet(); ILaunchDelegate d1 = config1.getPreferredDelegate(modes); if(d1 == null) { d1 = config1.getType().getPreferredDelegate(modes); } ILaunchDelegate d2 = config2.getPreferredDelegate(modes); if(d2 == null) { d2 = config2.getType().getPreferredDelegate(modes); } if(d1 != null) { return d1.equals(d2); } } catch(CoreException ce) {DebugUIPlugin.log(ce);} return false; } /** * Updates the visibility of controls based on the status provided * @param visible the visibility status to be applied to the controls */ private void updateVisibleControls(boolean visible) { fApplyButton.setVisible(visible); fRevertButton.setVisible(visible); fOptionsLink.setVisible(visible); if(visible) { ((StackLayout)fTabPlaceHolder.getLayout()).topControl = fTabComposite; } else { ((StackLayout)fTabPlaceHolder.getLayout()).topControl = fGettingStarted; } fTabPlaceHolder.layout(true, true); } /** * sets the current widget focus to the 'Name' widget */ protected void setFocusOnName() { fNameWidget.setFocus(); } /** * Displays tabs for the current working copy */ protected void displayInstanceTabs(boolean redrawTabs) { // Turn on initializing flag to ignore message updates fInitializingTabs = true; ILaunchConfigurationType type = null; try { type = getWorkingCopy().getType(); } catch (CoreException e) { errorDialog(e); fInitializingTabs = false; return; } if(redrawTabs) { showInstanceTabsFor(type); } // show the name area updateVisibleControls(true); // Retrieve the current tab group. If there is none, clean up and leave ILaunchConfigurationTabGroup tabGroup = getTabGroup(); if (tabGroup == null) { IStatus status = new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), 0, MessageFormat.format(LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_No_tabs_defined_for_launch_configuration_type__0__1, new String[]{type.getName()}), null); CoreException e = new CoreException(status); errorDialog(e); fInitializingTabs = false; return; } // Update the tabs with the new working copy tabGroup.initializeFrom(getWorkingCopy()); // Update the name field fNameWidget.setText(getWorkingCopy().getName()); fCurrentTabIndex = fTabFolder.getSelectionIndex(); // Turn off initializing flag to update message fInitializingTabs = false; if (!fVisibleArea.isVisible()) { fVisibleArea.setVisible(true); } } /** * Populate the tabs in the configuration edit area to be appropriate to the current * launch configuration type. */ private void showInstanceTabsFor(ILaunchConfigurationType configType) { // try to keep on same tab Class tabKind = null; if (getActiveTab() != null) { tabKind = getActiveTab().getClass(); } // Build the new tabs ILaunchConfigurationTabGroup group = null; try { group = createGroup(); } catch (CoreException ce) { DebugUIPlugin.errorDialog(getShell(), LaunchConfigurationsMessages.LaunchConfigurationDialog_Error_19, LaunchConfigurationsMessages.LaunchConfigurationDialog_Exception_occurred_creating_launch_configuration_tabs_27,ce); // return; } disposeExistingTabs(); fTabGroup = group; fTabType = configType; ILaunchConfigurationTab[] tabs = getTabs(); CTabItem tab = null; String name = IInternalDebugCoreConstants.EMPTY_STRING; Control control = null; for (int i = 0; i < tabs.length; i++) { tab = new CTabItem(fTabFolder, SWT.BORDER); name = tabs[i].getName(); if (name == null) { name = LaunchConfigurationsMessages.LaunchConfigurationDialog_unspecified_28; } tab.setText(name); tab.setImage(tabs[i].getImage()); tabs[i].createControl(tab.getParent()); control = tabs[i].getControl(); if (control != null) { tab.setControl(control); } } //set the default tab as the first one if (tabs.length > 0) { setActiveTab(tabs[0]); } // select same tab as before, if possible for (int i = 0; i < tabs.length; i++) { if (tabs[i].getClass().equals(tabKind)) { setActiveTab(tabs[i]); break; } } fDescription = getDescription(configType); } /** * Returns the description of the given configuration type * in the current mode or null if none. * * @param configType the config type * @return the description of the given configuration type or null */ private String getDescription(ILaunchConfigurationType configType) { String description = null; if(configType != null) { String mode = fDialog.getMode(); description = LaunchConfigurationPresentationManager.getDefault().getDescription(configType, mode); } if (description == null) { description = IInternalDebugCoreConstants.EMPTY_STRING; } return description; } /** * Returns tab group for the given type of launch configuration. * Tabs are initialized to be contained in this dialog. * * @exception CoreException if unable to instantiate a tab group */ protected ILaunchConfigurationTabGroup createGroup() throws CoreException { // Use a final Object array to store the tab group and any exception that // results from the Runnable final Object[] finalArray = new Object[2]; Runnable runnable = new Runnable() { public void run() { ILaunchConfigurationTabGroup tabGroup = null; try { tabGroup = LaunchConfigurationPresentationManager.getDefault().getTabGroup(getWorkingCopy(), getLaunchConfigurationDialog().getMode()); finalArray[0] = tabGroup; } catch (CoreException ce) { finalArray[1] = ce; return; } tabGroup.createTabs(getLaunchConfigurationDialog(), getLaunchConfigurationDialog().getMode()); ILaunchConfigurationTab[] tabs = tabGroup.getTabs(); for (int i = 0; i < tabs.length; i++) { tabs[i].setLaunchConfigurationDialog(getLaunchConfigurationDialog()); } } }; // Creating the tabs can result in plug-in loading, so we show the busy cursor BusyIndicator.showWhile(getControl().getDisplay(), runnable); // Re-throw any CoreException if there was one if (finalArray[1] != null) { throw (CoreException)finalArray[1]; } // Otherwise return the tab group return (ILaunchConfigurationTabGroup)finalArray[0]; } /** * Returns the tabs currently being displayed, or * null if none. * * @return currently displayed tabs, or null */ public ILaunchConfigurationTab[] getTabs() { if (getTabGroup() != null) { return getTabGroup().getTabs(); } return null; } /** * Returns the currently active ILaunchConfigurationTab * being displayed, or null if there is none. * * @return currently active ILaunchConfigurationTab, or null. */ public ILaunchConfigurationTab getActiveTab() { ILaunchConfigurationTab[] tabs = getTabs(); if (fTabFolder != null && tabs != null) { int pageIndex = fTabFolder.getSelectionIndex(); if (pageIndex >= 0) { return tabs[pageIndex]; } } return null; } /** * Returns whether the launch configuration being edited is dirty (i.e. * needs saving) * * @return whether the launch configuration being edited needs saving */ public boolean isDirty() { ILaunchConfigurationWorkingCopy workingCopy = getWorkingCopy(); if (workingCopy == null) { return false; } if(workingCopy.getParent() != null) { return !workingCopy.getParent().contentsEqual(workingCopy); } // Working copy hasn't been saved if (workingCopy.getOriginal() == null) { return true; } return fOriginal != null && !fOriginal.contentsEqual(workingCopy); } /** * Update apply & revert buttons, as well as buttons and message on the * launch config dialog. */ protected void refreshStatus() { if (!fInitializingTabs) { LaunchConfigurationsDialog lcd = (LaunchConfigurationsDialog) getLaunchConfigurationDialog(); lcd.refreshStatus(); } } /** * Returns the containing launch dialog */ protected ILaunchConfigurationDialog getLaunchConfigurationDialog() { return fDialog; } /** * Returns the original launch configuration being edited, possibly * null. * * @return ILaunchConfiguration */ protected ILaunchConfiguration getOriginal() { return fOriginal; } /** * Returns the working copy used to edit the original, possibly * null. */ protected ILaunchConfigurationWorkingCopy getWorkingCopy() { return fWorkingCopy; } /** * Return whether the current configuration can be saved. *

* Note this is NOT the same thing as the config simply being valid. It * is possible to save a config that does not validate. This method * determines whether the config can be saved without causing a serious * error. For example, a shared config that has no specified location would * cause this method to return false. *

*/ public boolean canSave() { if (fInitializingTabs) { return false; } // First make sure that name doesn't prevent saving the config try { verifyName(); } catch (CoreException ce) { return false; } // Next, make sure none of the tabs object to saving the config ILaunchConfigurationTab[] tabs = getTabs(); if (tabs == null) { return false; } for (int i = 0; i < tabs.length; i++) { if (!tabs[i].canSave()) { return false; } } if(getWorkingCopy() != null) { return !getWorkingCopy().isReadOnly(); } return true; } /** * @see ILaunchConfigurationDialog#canLaunch() */ public boolean canLaunch() { if(fInitializingTabs) { return false; } if (getWorkingCopy() == null) { return false; } try { verifyName(); } catch (CoreException e) { return false; } ILaunchConfigurationTab[] tabs = getTabs(); if (tabs == null) { return false; } for (int i = 0; i < tabs.length; i++) { if (!tabs[i].isValid(getWorkingCopy())) { return false; } } return true; } /** * Determines if the tab groups that is currently visible can launch with the currently selected * set of options. * * @return true if the dialog can launch with the given set of modes, false otherwise * * @since 3.3 */ public boolean canLaunchWithModes() { if(fInitializingTabs) { return false; } //check if selected options exist and that the selected combination can be launched try { ILaunchConfigurationWorkingCopy wc = getWorkingCopy(); if(wc != null) { return wc.getType().supportsModeCombination(getCurrentModeSet()); } } catch (CoreException e) { } return true; } /** * Returns if the type currently showing in the tab group viewer has duplicate launch delegates for the given set of modes. * * The given set of modes comprises the current mode that the launch dialog was opened in as well as any modes that have been set on the launch * configuration. * @return the true if there are duplicates, false otherwise * * @since 3.3 */ public boolean hasDuplicateDelegates() { if(fInitializingTabs) { return false; } ILaunchConfiguration config = getWorkingCopy(); if(config != null) { if(hasMultipleDelegates()) { return getPreferredDelegate() == null; } } return false; } /** * Determines if the currently showing launch configuration has multiple launch delegates for the same mode set, but does not care * if there has been a default selected yet or not * @return true if the current launch configuration has multiple launch delegates, false otherwise */ private boolean hasMultipleDelegates() { ILaunchConfiguration config = getWorkingCopy(); if(config != null) { try { Set modes = getCurrentModeSet(); ILaunchDelegate[] delegates = LaunchConfigurationManager.filterLaunchDelegates(fTabType, modes); return delegates.length > 1; } catch (CoreException ce) {DebugUIPlugin.log(ce);} } return false; } /** * Returns the current error message or null if none. */ public String getErrorMesssage() { if (fInitializingTabs) { return null; } if (getWorkingCopy() == null) { return null; } try { verifyName(); } catch (CoreException ce) { return ce.getStatus().getMessage(); } if(hasDuplicateDelegates()) { return LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_18; } String message = null; ILaunchConfigurationTab activeTab = getActiveTab(); if (activeTab == null) { return null; } message = activeTab.getErrorMessage(); if (message != null) { return message; } ILaunchConfigurationTab[] allTabs = getTabs(); for (int i = 0; i < allTabs.length; i++) { ILaunchConfigurationTab tab = allTabs[i]; if (tab == activeTab) { continue; } message = tab.getErrorMessage(); if (message != null) { StringBuffer temp= new StringBuffer(); temp.append('['); temp.append(DebugUIPlugin.removeAccelerators(tab.getName())); temp.append("]: "); //$NON-NLS-1$ temp.append(message); return temp.toString(); } } if(getWorkingCopy().isReadOnly()) { return LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_9; } if(!canLaunchWithModes()) { Set modes = getCurrentModeSet(); List names = LaunchConfigurationPresentationManager.getDefault().getLaunchModeNames(modes); return MessageFormat.format(LaunchConfigurationsMessages.LaunchConfigurationTabGroupViewer_14, new String[]{names.toString()}); } return null; } /** * Returns the current message or null if none. * @return Returns an appropriate message for display to user. The message returned will be: * The message defined by the visible tab, * or The tab group description for the particular launch mode, * or The generic tab group description, * or null if no message is defined */ public String getMessage() { if (fInitializingTabs) { return null; } String message = fDescription; ILaunchConfigurationTab tab = getActiveTab(); if (tab != null) { String tabMessage = tab.getMessage(); if (tabMessage != null) { message = tabMessage; } } return message; } /** * Verify that the launch configuration name is valid. */ protected void verifyName() throws CoreException { if (fNameWidget.isVisible()) { ILaunchManager mgr = DebugPlugin.getDefault().getLaunchManager(); String currentName = fNameWidget.getText().trim(); // If there is no name, complain if (currentName.length() < 1) { throw new CoreException(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), 0, LaunchConfigurationsMessages.LaunchConfigurationDialog_Name_required_for_launch_configuration_11, null)); } try { mgr.isValidLaunchConfigurationName(currentName); } catch(IllegalArgumentException iae) { throw new CoreException(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), 0, iae.getMessage(), null)); } // Otherwise, if there's already a config with the same name, complain if (fOriginal != null && !fOriginal.getName().equals(currentName)) { Set reservednames = ((LaunchConfigurationsDialog)getLaunchConfigurationDialog()).getReservedNameSet(); if (mgr.isExistingLaunchConfigurationName(currentName) || (reservednames != null ? reservednames.contains(currentName) : false)) { throw new CoreException(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), 0, LaunchConfigurationsMessages.LaunchConfigurationDialog_Launch_configuration_already_exists_with_this_name_12, null)); } } } } /** * Remove the existing tabs that are showing */ private void disposeExistingTabs() { fDisposingTabs = true; fTabFolder.dispose(); fTabFolder = null; createTabFolder(fTabComposite); disposeTabGroup(); fDisposingTabs = false; } /** * Returns the current tab group * * @return the current tab group, or null if none */ public ILaunchConfigurationTabGroup getTabGroup() { return fTabGroup; } /** * Notification that a tab has been selected * * Disallow tab changing when the current tab is invalid. * Update the config from the tab being left, and refresh * the tab being entered. */ protected void handleTabSelected() { if (fDisposingTabs || fInitializingTabs) { return; } ILaunchConfigurationTab[] tabs = getTabs(); if (fCurrentTabIndex == fTabFolder.getSelectionIndex() || tabs == null || tabs.length == 0 || fCurrentTabIndex > (tabs.length - 1)) { return; } if (fCurrentTabIndex != -1) { ILaunchConfigurationTab tab = tabs[fCurrentTabIndex]; ILaunchConfigurationWorkingCopy wc = getWorkingCopy(); if (wc != null) { tab.deactivated(wc); getActiveTab().activated(wc); } } fCurrentTabIndex = fTabFolder.getSelectionIndex(); } /** * Notification the name field has been modified */ protected void handleNameModified() { getWorkingCopy().rename(fNameWidget.getText().trim()); refreshStatus(); } /** * Notification that the 'Apply' button has been pressed */ protected void handleApplyPressed() { Exception exception = null; try { // update launch config fInitializingTabs = true; // trim name String trimmed = fNameWidget.getText().trim(); fNameWidget.setText(trimmed); if(fWorkingCopy == null) { fWorkingCopy = fOriginal.getWorkingCopy(); } fWorkingCopy.rename(trimmed); getTabGroup().performApply(fWorkingCopy); if (isDirty()) { if(!fWorkingCopy.isLocal()) { IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { fOriginal = ((LaunchConfigurationWorkingCopy)fWorkingCopy).doSave(monitor); } catch (CoreException e) {DebugUIPlugin.log(e);} } }; getLaunchConfigurationDialog().run(true, false, runnable); } else { fOriginal = fWorkingCopy.doSave(); } } updateButtons(); fInitializingTabs = false; } catch (CoreException e) {exception = e;} catch (InvocationTargetException e) {exception = e;} catch (InterruptedException e) {exception = e;} if(exception != null) { DebugUIPlugin.errorDialog(getShell(), LaunchConfigurationsMessages.LaunchConfigurationDialog_Launch_Configuration_Error_46, LaunchConfigurationsMessages.LaunchConfigurationDialog_Exception_occurred_while_saving_launch_configuration_47, exception); // return; } } /** * Notification that the 'Revert' button has been pressed */ protected void handleRevertPressed() { try { if(fTabGroup != null) { fTabGroup.initializeFrom(fOriginal); fNameWidget.setText(fOriginal.getName()); fWorkingCopy = fOriginal.getWorkingCopy(); refreshStatus(); } } catch (CoreException e) {DebugUIPlugin.log(e);} } /** * Show an error dialog on the given exception. * * @param exception */ protected void errorDialog(CoreException exception) { ErrorDialog.openError(getShell(), null, null, exception.getStatus()); } /** * Sets the displayed tab to the given tab. Has no effect if the specified * tab is not one of the tabs being displayed in the dialog currently. * * @param tab the tab to display/activate */ public void setActiveTab(ILaunchConfigurationTab tab) { ILaunchConfigurationTab[] tabs = getTabs(); if(tabs != null) { for (int i = 0; i < tabs.length; i++) { if (tabs[i].getClass().equals(tab.getClass())) { setActiveTab(i); return; } } } } /** * Sets the displayed tab to the tab with the given index. Has no effect if * the specified index is not within the limits of the tabs returned by * getTabs(). * * @param index the index of the tab to display */ public void setActiveTab(int index) { ILaunchConfigurationTab[] tabs = getTabs(); if (index >= 0 && index < tabs.length) { fTabFolder.setSelection(index); handleTabSelected(); } } }