/** * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ /* * Author: fabioz * Author: ldore * Created: Feb 20, 2008 */ package org.python.pydev.debug.ui; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; import org.eclipse.debug.ui.ILaunchConfigurationDialog; import org.eclipse.debug.ui.ILaunchConfigurationTab; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; 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.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.python.pydev.core.IInterpreterInfo; import org.python.pydev.core.IInterpreterManager; import org.python.pydev.core.MisconfigurationException; import org.python.pydev.core.log.Log; import org.python.pydev.debug.core.Constants; import org.python.pydev.debug.ui.launching.InvalidRunException; import org.python.pydev.debug.ui.launching.PythonRunnerConfig; import org.python.pydev.plugin.PydevPlugin; import org.python.pydev.plugin.nature.PythonNature; import org.python.pydev.shared_core.string.WrapAndCaseUtils; /** * The Python interpreter setup tab. * * The contents of this tab was formerly in the ArgumentsTab, until * controls took too much space to fit. * * As benefit of the split, this separates the program launch parameters * from the Interpreter configuration. * * <p>Interesting functionality: InterpreterEditor will try the verify the choice of an interpreter. * <p>Getting the ModifyListener to display the proper error message was tricky */ public class InterpreterTab extends AbstractLaunchConfigurationTab { // Widgets private Combo fInterpreterComboField; private Button fButtonSeeResultingCommandLine; private Text fCommandLineText; // View constant public static final String DEFAULT_INTERPRETER_NAME = "Default Interpreter"; private IInterpreterManager fInterpreterManager; public IInterpreterManager getInterpreterManager() { if (fInterpreterManager == null) { if (this.fWorkingCopyForCommandLineGeneration != null) { try { //could throw core exception if project does not exist. IProject project = PythonRunnerConfig .getProjectFromConfiguration(this.fWorkingCopyForCommandLineGeneration); PythonNature nature = PythonNature.getPythonNature(project); if (nature != null) { return PydevPlugin.getInterpreterManager(nature); } } catch (Exception e) { Log.log(e); } } } return fInterpreterManager; } private ILaunchConfigurationWorkingCopy fWorkingCopyForCommandLineGeneration; private SelectionListener fSelectionListener = new SelectionListener() { @Override public void widgetSelected(SelectionEvent e) { if (e.getSource() == fButtonSeeResultingCommandLine) { try { // ok, show the command-line to the user ILaunchConfigurationDialog launchConfigurationDialog = getLaunchConfigurationDialog(); for (ILaunchConfigurationTab launchConfigurationTab : launchConfigurationDialog.getTabs()) { launchConfigurationTab.performApply(fWorkingCopyForCommandLineGeneration); } PythonRunnerConfig config = getConfig(fWorkingCopyForCommandLineGeneration, launchConfigurationDialog); if (config == null) { fCommandLineText .setText("Unable to make the command-line. \n\nReason:Interpreter not available for current project."); } else { String commandLineAsString = config.getCommandLineAsString(); commandLineAsString = WrapAndCaseUtils.wrap(commandLineAsString, 80); commandLineAsString += "\n\nThe PYTHONPATH that will be used is:\n\n"; commandLineAsString += config.pythonpathUsed; fCommandLineText.setText(commandLineAsString); } } catch (Exception e1) { fCommandLineText.setText("Unable to make the command-line. \n\nReason:\n\n" + e1.getMessage()); } } } @Override public void widgetDefaultSelected(SelectionEvent e) { } }; /** * @param configuration the launch configuration to be used * @param launchConfigurationDialog the dialog for the launch configuration * @return a PythonRunnerConfig configured with the given launch configuration * @throws CoreException * @throws InvalidRunException * @throws MisconfigurationException */ private PythonRunnerConfig getConfig(ILaunchConfiguration configuration, ILaunchConfigurationDialog launchConfigurationDialog) throws CoreException, InvalidRunException, MisconfigurationException { String run; IInterpreterManager interpreterManager = getInterpreterManager(); if (interpreterManager == null) { return null; } switch (interpreterManager.getInterpreterType()) { case IInterpreterManager.INTERPRETER_TYPE_JYTHON: run = PythonRunnerConfig.RUN_JYTHON; break; case IInterpreterManager.INTERPRETER_TYPE_IRONPYTHON: run = PythonRunnerConfig.RUN_IRONPYTHON; break; case IInterpreterManager.INTERPRETER_TYPE_PYTHON: run = PythonRunnerConfig.RUN_REGULAR; break; default: throw new RuntimeException("Should be python or jython interpreter (found unknown)."); } boolean makeArgumentsVariableSubstitution = false; // we don't want to make the arguments substitution (because it could end opening up a // dialog for the user requesting something). PythonRunnerConfig config = new PythonRunnerConfig(configuration, launchConfigurationDialog.getMode(), run, makeArgumentsVariableSubstitution); return config; } public InterpreterTab(IInterpreterManager interpreterManager) { this.fInterpreterManager = interpreterManager; } public InterpreterTab() { } /* * (non-Javadoc) * @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(org.eclipse.swt.widgets.Composite) */ @Override public void createControl(Composite parent) { Composite comp = new Composite(parent, SWT.NONE); setControl(comp); GridLayout gridLayout = new GridLayout(); comp.setLayout(gridLayout); GridData data = new GridData(GridData.FILL_HORIZONTAL); Label label6 = new Label(comp, SWT.NONE); label6.setText("Interpreter:"); data = new GridData(GridData.FILL_HORIZONTAL); data.horizontalSpan = 2; label6.setLayoutData(data); fInterpreterComboField = new Combo(comp, SWT.DROP_DOWN); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.horizontalSpan = 2; fInterpreterComboField.setLayoutData(data); fInterpreterComboField.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { updateLaunchConfigurationDialog(); } }); fButtonSeeResultingCommandLine = new Button(comp, SWT.NONE); fButtonSeeResultingCommandLine.setText("See resulting command-line for the given parameters"); data = new GridData(); data.horizontalSpan = 2; data.horizontalAlignment = GridData.FILL; fButtonSeeResultingCommandLine.setLayoutData(data); fButtonSeeResultingCommandLine.addSelectionListener(this.fSelectionListener); fCommandLineText = new Text(comp, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); fCommandLineText.setText("In case you are in doubt how will the run happen, click the button to \n" + "see the command-line that will be executed with the current parameters\n" + "(and the PYTHONPATH / CLASSPATH / IRONPYTHONPATH used for the run)."); data = new GridData(); data.grabExcessVerticalSpace = true; data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.FILL; data.horizontalSpan = 1; data.verticalSpan = 5; fCommandLineText.setLayoutData(data); } /* * (non-Javadoc) * @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#isValid(org.eclipse.debug.core.ILaunchConfiguration) */ @Override public boolean isValid(ILaunchConfiguration launchConfig) { setErrorMessage(null); setMessage(null); String interpreter; try { interpreter = launchConfig.getAttribute(Constants.ATTR_INTERPRETER, Constants.ATTR_INTERPRETER_DEFAULT); } catch (CoreException e) { setErrorMessage("No interpreter? " + e.getMessage()); return false; } if (interpreter == null) { return false; } try { return checkIfInterpreterExists(interpreter); } catch (Exception e) { //we might have problems getting the configured interpreters setMessage(e.getMessage()); setErrorMessage(e.getMessage()); return false; } } /* * (non-Javadoc) * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName() */ @Override public String getName() { return "Interpreter"; } /* * (non-Javadoc) * @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#getImage() */ @Override public Image getImage() { return PydevPlugin.getImageCache().get(Constants.PYTHON_ORG_ICON); } /* * (non-Javadoc) * @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) */ @Override public void setDefaults(ILaunchConfigurationWorkingCopy arg0) { //no defaults to set } /* * (non-Javadoc) * @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration) */ @Override public void initializeFrom(ILaunchConfiguration configuration) { try { fWorkingCopyForCommandLineGeneration = configuration.getWorkingCopy(); } catch (CoreException e1) { throw new RuntimeException(e1); } IInterpreterManager interpreterManager = this.getInterpreterManager(); String[] interpreterNames = new String[0]; if (interpreterManager != null) { IInterpreterInfo[] interpreterInfos = interpreterManager.getInterpreterInfos(); if (interpreterInfos.length > 0) { // There is at least one interpreter defined, add the default interpreter option at the beginning. interpreterNames = new String[interpreterInfos.length + 1]; interpreterNames[0] = InterpreterTab.DEFAULT_INTERPRETER_NAME; for (int i = 0; i < interpreterInfos.length; i++) { interpreterNames[i + 1] = interpreterInfos[i].getName(); } } } fInterpreterComboField.setItems(interpreterNames); String interpreter = ""; try { interpreter = configuration.getAttribute(Constants.ATTR_INTERPRETER, Constants.ATTR_INTERPRETER_DEFAULT); } catch (CoreException e) { } if (fInterpreterComboField.getItems().length == 0) { setErrorMessage("No interpreter is configured, please, go to window > preferences > interpreters and add the interpreter you want to use."); } else { int selectThis = -1; if (interpreter.equals(Constants.ATTR_INTERPRETER_DEFAULT)) { selectThis = 0; } else { if (interpreterManager != null) { IInterpreterInfo[] interpreterInfos = interpreterManager.getInterpreterInfos(); for (int i = 0; i < interpreterInfos.length; i++) { if (interpreterInfos[i].matchNameBackwardCompatible(interpreter)) { selectThis = i + 1; //Internally, it's the index+1 (because the one at 0 is the default) break; } } } } if (selectThis == -1) { if (interpreter.startsWith("${")) { fInterpreterComboField.setText(interpreter); } else { setErrorMessage("Obsolete interpreter is selected. Choose a new one."); } } else { fInterpreterComboField.select(selectThis); } } } /* * (non-Javadoc) * @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) */ @Override public void performApply(ILaunchConfigurationWorkingCopy configuration) { String value; if (fInterpreterComboField.getSelectionIndex() == 0) { // The default was selected value = Constants.ATTR_INTERPRETER_DEFAULT; } else { value = fInterpreterComboField.getText(); } setAttribute(configuration, Constants.ATTR_INTERPRETER, value); } /** * @param interpreter the interpreter to validate * @return true if the interpreter is configured in pydev * @throws MisconfigurationException */ protected boolean checkIfInterpreterExists(String interpreter) throws MisconfigurationException { IInterpreterManager interpreterManager = this.getInterpreterManager(); if (interpreterManager == null) { return false; } if (interpreter.equals(Constants.ATTR_INTERPRETER_DEFAULT)) { if (interpreterManager.getDefaultInterpreterInfo(false) != null) { // The default interpreter is selected, and we have a default interpreter return true; } //otherwise, the default is selected, but we have no default return false; } IInterpreterInfo[] interpreters = interpreterManager.getInterpreterInfos(); for (int i = 0; i < interpreters.length; i++) { if (interpreters[i] != null && interpreters[i].matchNameBackwardCompatible(interpreter)) { return true; } } if (interpreter.startsWith("${")) { return true; } return false; } /** * sets attributes in the working copy */ private void setAttribute(ILaunchConfigurationWorkingCopy conf, String name, String value) { if (value == null || value.length() == 0) { conf.setAttribute(name, (String) null); } else { conf.setAttribute(name, value); } } /* * (non-Javadoc) * @see org.eclipse.debug.ui.AbstractLaunchConfigurationTab#setLaunchConfigurationDialog(org.eclipse.debug.ui.ILaunchConfigurationDialog) */ @Override public void setLaunchConfigurationDialog(ILaunchConfigurationDialog dialog) { super.setLaunchConfigurationDialog(dialog); } }