/******************************************************************************* * Copyright (c) 2015 Zend Technologies 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: * Zend Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.php.internal.debug.ui.launching; import java.util.HashMap; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.php.debug.core.debugger.parameters.IDebugParametersKeys; import org.eclipse.php.debug.ui.IDebugServerConnectionTest; import org.eclipse.php.internal.core.Logger; import org.eclipse.php.internal.debug.core.PHPDebugPlugin; import org.eclipse.php.internal.debug.core.preferences.PHPDebugCorePreferenceNames; import org.eclipse.php.internal.debug.core.preferences.PHPDebuggersRegistry; import org.eclipse.php.internal.debug.ui.PHPDebugUIImages; import org.eclipse.swt.SWT; 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.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.Label; /** * Abstract implementation of "Debugger" launch configuration tab. It handles * switching between dedicated settings sections and updates the corresponding * debugger type related data if it has been changed. * * @author Bartlomiej Laczkowski */ @SuppressWarnings("restriction") public abstract class AbstractPHPLaunchConfigurationDebuggerTab extends AbstractPHPLaunchConfigurationTab { /** * Widget listener that should be added to all controls that affects the * state of corresponding launch configuration. */ public final class WidgetListener extends SelectionAdapter implements ModifyListener { public void modifyText(ModifyEvent e) { setDirty(true); updateLaunchConfigurationDialog(); } public void widgetSelected(SelectionEvent e) { setDirty(true); updateLaunchConfigurationDialog(); } } /** * Status message that provides information about validation result in given * settings section. */ public final static class StatusMessage implements IMessageProvider { private int type; private String message; public StatusMessage(int type, String message) { this.type = type; this.message = message; } @Override public String getMessage() { return message; } @Override public int getMessageType() { return type; } } private final class NoneDebuggerSection extends DebuggerLaunchSettingsSectionAdapter { @Override public StatusMessage isValid(ILaunchConfiguration configuration) { return new StatusMessage(IMessageProvider.ERROR, getNoDebuggerMessage()); } } private final class UnsupportedDebuggerSection extends DebuggerLaunchSettingsSectionAdapter { @Override public void createSection(Composite parent, WidgetListener widgetListener) { Label info = new Label(parent, SWT.NONE); info.setText(Messages.AbstractPHPLaunchConfigurationDebuggerTab_Unsupported_debugger_type); } @Override public StatusMessage isValid(ILaunchConfiguration configuration) { return new StatusMessage(IMessageProvider.ERROR, Messages.AbstractPHPLaunchConfigurationDebuggerTab_Unsupported_debugger_type); } } protected Button validateDebuggerBtn; protected IDebugServerConnectionTest[] debugTesters; private Label debuggerName; private Button configureDebugger; private Composite mainComposite; private Composite settingsComposite; private Map<String, IDebuggerLaunchSettingsSection> currentSection = new HashMap<String, IDebuggerLaunchSettingsSection>(); /* * (non-Javadoc) * * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName() */ public String getName() { return Messages.AbstractPHPLaunchConfigurationDebuggerTab_Debugger_tab_name; } /* * (non-Javadoc) * * @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#getImage() */ @Override public Image getImage() { return PHPDebugUIImages.get(PHPDebugUIImages.IMG_OBJ_DEBUG_CONF); } /* * (non-Javadoc) * * @see * org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(org.eclipse * .swt.widgets.Composite) */ public void createControl(Composite parent) { // Create main composite mainComposite = new Composite(parent, SWT.NONE); GridLayout mainLayout = new GridLayout(); mainLayout.marginHeight = 0; mainLayout.marginWidth = 0; mainComposite.setLayout(mainLayout); createDebuggerSelectionControl(mainComposite); // Create composite for debugger dedicated settings settingsComposite = new Composite(mainComposite, SWT.NONE); Dialog.applyDialogFont(mainComposite); setControl(mainComposite); } /* * (non-Javadoc) * * @see org.eclipse.php.internal.debug.ui.launching. * AbstractPHPLaunchConfigurationTab#setDefaults(org.eclipse.debug.core. * ILaunchConfigurationWorkingCopy) */ @Override public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { super.setDefaults(configuration); try { if (!configuration.hasAttribute(IDebugParametersKeys.FIRST_LINE_BREAKPOINT)) { configuration.setAttribute(IDebugParametersKeys.FIRST_LINE_BREAKPOINT, PHPDebugPlugin.getStopAtFirstLine()); } } catch (CoreException e) { Logger.logException(e); } getSection().setDefaults(configuration); } /* * (non-Javadoc) * * @see * org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(org.eclipse. * debug.core.ILaunchConfigurationWorkingCopy) */ @Override public void performApply(ILaunchConfigurationWorkingCopy configuration) { configuration.setAttribute(PHPDebugCorePreferenceNames.PHP_DEBUGGER_ID, getCurrentDebuggerId()); getSection().performApply(configuration); } /* * (non-Javadoc) * * @see * org.eclipse.debug.ui.AbstractLaunchConfigurationTab#isValid(org.eclipse. * debug.core.ILaunchConfiguration) */ @Override public boolean isValid(ILaunchConfiguration launchConfig) { setMessage(null); setWarningMessage(null); setErrorMessage(null); StatusMessage status = getSection().isValid(launchConfig); switch (status.getMessageType()) { case IMessageProvider.ERROR: { setErrorMessage(status.getMessage()); return false; } case IMessageProvider.WARNING: { setWarningMessage(status.getMessage()); return true; } default: return true; } } /* * (non-Javadoc) * * @see org.eclipse.php.internal.debug.ui.launching. * AbstractPHPLaunchConfigurationTab#initialize(org.eclipse.debug.core. * ILaunchConfiguration) */ @Override protected void initialize(ILaunchConfiguration configuration) { getSection().initialize(configuration); } /** * Implementors should provide an action that handles triggering of * "Configure..." debugger settings button. */ protected abstract void handleConfigureDebugger(); /** * Implementors should provide the current debugger ID that corresponds to * debugger settings owner in related launch configuration. * * @return current debugger ID */ protected abstract String getCurrentDebuggerId(); /** * Implementors should provide the appropriate message in case when there is * no debugger attached to potential debugger settings owner. * * @return "No" debugger attached message. */ protected abstract String getNoDebuggerMessage(); /** * Implementors should update state of a "Test" button. */ protected abstract void updateDebugTest(); /** * Implementors should provide an action that handles triggering of "Test" * debugger connection button. */ protected abstract void performDebugTest(); private void createDebuggerSelectionControl(Composite parent) { Composite mainComposite = new Composite(parent, SWT.NONE); GridLayout mcLayout = new GridLayout(1, false); mcLayout.marginHeight = 0; mcLayout.marginWidth = 0; mainComposite.setLayout(mcLayout); mainComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Composite debuggerChoiceComposite = new Composite(mainComposite, SWT.NONE); GridLayout layout = new GridLayout(5, false); debuggerChoiceComposite.setLayout(layout); GridData data = new GridData(GridData.FILL_HORIZONTAL); debuggerChoiceComposite.setLayoutData(data); Font font = parent.getFont(); debuggerChoiceComposite.setFont(font); Label label = new Label(debuggerChoiceComposite, SWT.WRAP); data = new GridData(SWT.BEGINNING); label.setLayoutData(data); label.setFont(font); label.setText(Messages.AbstractPHPLaunchConfigurationDebuggerTab_Debugger_type); debuggerName = new Label(debuggerChoiceComposite, SWT.NONE); Label separator = new Label(debuggerChoiceComposite, SWT.NONE); data = new GridData(SWT.BEGINNING); data.widthHint = 20; separator.setLayoutData(data); configureDebugger = createPushButton(debuggerChoiceComposite, Messages.AbstractPHPLaunchConfigurationDebuggerTab_Configure, null); configureDebugger.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { handleConfigureDebugger(); } }); configureDebugger.addSelectionListener(new WidgetListener()); validateDebuggerBtn = createPushButton(debuggerChoiceComposite, Messages.AbstractPHPLaunchConfigurationDebuggerTab_Test, null); validateDebuggerBtn.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { performDebugTest(); } }); Label lineSeparator = new Label(mainComposite, SWT.SEPARATOR | SWT.HORIZONTAL); lineSeparator.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); } private IDebuggerLaunchSettingsSection getSection() { try { String launchTypeId = getConfiguration().getType().getIdentifier(); String debuggerId = getCurrentDebuggerId(); IDebuggerLaunchSettingsSection section = currentSection.get(debuggerId); if (section == null) { // Debugger type has been changed, rebuild section if (PHPDebuggersRegistry.NONE_DEBUGGER_ID.equals(debuggerId)) { section = new NoneDebuggerSection(); } else { section = DebuggerLaunchSettingsSectionRegistry.getSection(debuggerId, launchTypeId); if (section == null) { section = new UnsupportedDebuggerSection(); } } if (settingsComposite != null) { buildSection(debuggerId, section); } } return section; } catch (CoreException e) { Logger.logException(e); } // Should never return null return null; } private void buildSection(String debuggerId, IDebuggerLaunchSettingsSection section) { // Update debugger type data first updateDebugger(debuggerId); // Store as singular key map (most recent section by debugger ID) currentSection.clear(); currentSection.put(debuggerId, section); settingsComposite.dispose(); settingsComposite = new Composite(mainComposite, SWT.NONE); settingsComposite.setLayout(new GridLayout()); GridData dscData = new GridData(SWT.FILL, SWT.FILL, true, true); settingsComposite.setLayoutData(dscData); section.createSection(settingsComposite, new WidgetListener()); // Rebuild main composite mainComposite.layout(); section.initialize(getConfiguration()); } private void updateDebugger(String debuggerId) { debuggerName.setText(PHPDebuggersRegistry.getDebuggerName(debuggerId)); try { // Update debugger type in original configuration if (getOriginalConfiguration().contentsEqual(getConfiguration())) { // Only debugger might have been changed, update original configuration ILaunchConfigurationWorkingCopy wc = getOriginalConfiguration().getWorkingCopy(); wc.setAttribute(PHPDebugCorePreferenceNames.PHP_DEBUGGER_ID, debuggerId); wc.doSave(); } // Update in working copy if (getConfiguration() instanceof ILaunchConfigurationWorkingCopy) { ((ILaunchConfigurationWorkingCopy) getConfiguration()) .setAttribute(PHPDebugCorePreferenceNames.PHP_DEBUGGER_ID, debuggerId); } } catch (CoreException e) { Logger.logException(e); } updateDebugTest(); } }