/******************************************************************************* * Copyright (c) 2008, 2016 xored software, Inc. * * 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: * xored software, Inc. - initial API and Implementation (Alex Panchenko) *******************************************************************************/ package org.eclipse.dltk.ruby.testing.internal; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.IProjectFragment; import org.eclipse.dltk.core.IScriptFolder; import org.eclipse.dltk.core.IScriptModel; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.debug.ui.messages.DLTKLaunchConfigurationsMessages; import org.eclipse.dltk.internal.testing.launcher.DLTKTestingMigrationDelegate; import org.eclipse.dltk.internal.ui.ModelElementComparator; import org.eclipse.dltk.internal.ui.StandardModelElementContentProvider; import org.eclipse.dltk.internal.ui.wizards.TypedElementSelectionValidator; import org.eclipse.dltk.internal.ui.wizards.TypedViewerFilter; import org.eclipse.dltk.launching.ScriptLaunchConfigurationConstants; import org.eclipse.dltk.ruby.internal.debug.ui.launchConfigurations.RubyMainLaunchConfigurationTab; import org.eclipse.dltk.testing.DLTKTestingConstants; import org.eclipse.dltk.testing.DLTKTestingMessages; import org.eclipse.dltk.testing.ITestingEngine; import org.eclipse.dltk.testing.TestingEngineDetectResult; import org.eclipse.dltk.testing.TestingEngineManager; import org.eclipse.dltk.ui.ModelElementLabelProvider; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.Window; 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.layout.RowLayout; 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.eclipse.ui.dialogs.ElementTreeSelectionDialog; public class RubyTestingMainLaunchConfigurationTab extends RubyMainLaunchConfigurationTab { private Button detect; private Combo engineType; private Map<String, String> nameToId = new HashMap<String, String>(); private Label engineMessageLabel; private Label engineMessageImageLabel; private Button fTestRadioButton; private Button fTestContainerRadioButton; public RubyTestingMainLaunchConfigurationTab(String mode) { super(mode); } private Label fProjectLabel; private Label fScriptLabel; private Text fContainerText; private Button fContainerSearchButton; private IModelElement fContainerElement; private final ILabelProvider fModelElementLabelProvider = new ModelElementLabelProvider(); @Override public void createControl(Composite parent) { Composite comp = new Composite(parent, SWT.NONE); setControl(comp); GridLayout topLayout = new GridLayout(); topLayout.numColumns = 3; // // one test // fTestRadioButton = new Button(comp, SWT.RADIO); fTestRadioButton .setText(DLTKTestingMessages.JUnitLaunchConfigurationTab_label_oneTest); fTestRadioButton.setLayoutData(createModeGridData()); fTestRadioButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (fTestRadioButton.getSelection()) { testModeChanged(); } } }); comp.setLayout(topLayout); createProjectEditor(comp); createMainModuleEditor(comp, DLTKLaunchConfigurationsMessages.mainTab_mainModule); createVerticalSpacer(comp, 1); // // container tests // fTestContainerRadioButton = new Button(comp, SWT.RADIO); fTestContainerRadioButton .setText(DLTKTestingMessages.JUnitLaunchConfigurationTab_label_containerTest); fTestContainerRadioButton.setLayoutData(createModeGridData()); fTestContainerRadioButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (fTestContainerRadioButton.getSelection()) testModeChanged(); } }); fContainerText = new Text(comp, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalIndent = 25; gd.horizontalSpan = 2; fContainerText.setLayoutData(gd); fContainerText.addModifyListener(getWidgetListener()); fContainerSearchButton = createPushButton(comp, DLTKTestingMessages.JUnitLaunchConfigurationTab_label_search, null); fContainerSearchButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent evt) { handleContainerSearchButtonSelected(); } }); createVerticalSpacer(comp, 1); // // Testing engine // createTestEngineEditor( comp, Messages.RubyTestingMainLaunchConfigurationTab_rubyTestingEngine); createVerticalSpacer(comp, 1); createDebugOptionsGroup(comp); createCustomSections(comp); // Dialog.applyDialogFont(comp); } /** * */ protected void handleContainerSearchButtonSelected() { IModelElement element = chooseContainer(fContainerElement); if (element != null) { setContainerElement(element); setProjectName(element.getScriptProject().getElementName()); } } private void setContainerElement(IModelElement javaElement) { fContainerElement = javaElement; fContainerText.setText(getPresentationName(javaElement)); validatePage(); updateLaunchConfigurationDialog(); } @Override protected boolean validate() { updateEngineStatus(); final boolean result; if (fTestContainerRadioButton.getSelection()) { if (fContainerElement == null) { setErrorMessage(DLTKTestingMessages.JUnitLaunchConfigurationTab_error_noContainer); return false; } result = validateProject(fContainerElement.getScriptProject()); } else { result = super.validate(); } return result && validateEngine(); } private String getPresentationName(IModelElement element) { return fModelElementLabelProvider.getText(element); } private IModelElement chooseContainer(IModelElement initElement) { Class<?>[] acceptedClasses = new Class[] { IProjectFragment.class, IScriptProject.class, IScriptFolder.class }; TypedElementSelectionValidator validator = new TypedElementSelectionValidator( acceptedClasses, false) { @Override public boolean isSelectedValid(Object element) { return true; } }; acceptedClasses = new Class[] { IScriptModel.class, IProjectFragment.class, IScriptProject.class, IScriptFolder.class }; ViewerFilter filter = new TypedViewerFilter(acceptedClasses) { @Override public boolean select(Viewer viewer, Object parent, Object element) { if (element instanceof IScriptProject) { if (!getNatureID().equals( ((IScriptProject) element).getLanguageToolkit() .getNatureId())) { return false; } } if (element instanceof IProjectFragment) { IProjectFragment fragment = (IProjectFragment) element; if (fragment.isExternal() || fragment.isArchive()) { return false; } } try { if (element instanceof IScriptFolder && !((IScriptFolder) element).hasChildren()) { return false; } } catch (ModelException e) { return false; } return super.select(viewer, parent, element); } }; StandardModelElementContentProvider provider = new StandardModelElementContentProvider(); ILabelProvider labelProvider = new ModelElementLabelProvider( ModelElementLabelProvider.SHOW_DEFAULT); ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog( getShell(), labelProvider, provider); dialog.setValidator(validator); dialog.setComparator(new ModelElementComparator()); dialog .setTitle(DLTKTestingMessages.JUnitLaunchConfigurationTab_folderdialog_title); dialog .setMessage(DLTKTestingMessages.JUnitLaunchConfigurationTab_folderdialog_message); dialog.addFilter(filter); dialog.setInput(DLTKCore.create(getWorkspaceRoot())); dialog.setInitialSelection(initElement); dialog.setAllowMultiple(false); if (dialog.open() == Window.OK) { Object element = dialog.getFirstResult(); return (IModelElement) element; } return null; } /** * @return */ private GridData createModeGridData() { GridData gd = new GridData(); gd.horizontalSpan = 3; return gd; } @Override protected boolean needGroupForField(String fieldName) { return !FIELD_PROJECT.equals(fieldName) && !FIELD_SCRIPT.equals(fieldName); } @Override protected Label createLabelForField(Composite parent, String fieldName, String text) { final Label label = super.createLabelForField(parent, fieldName, text); if (FIELD_PROJECT.equals(fieldName) || FIELD_SCRIPT.equals(fieldName)) { label.setLayoutData(createIndentedGridData()); } if (FIELD_PROJECT.equals(fieldName)) { fProjectLabel = label; } else if (FIELD_SCRIPT.equals(fieldName)) { fScriptLabel = label; } return label; } private GridData createIndentedGridData() { GridData gd = new GridData(); gd.horizontalIndent = 25; return gd; } @Override protected final void doCreateControl(Composite composite) { // NOP } private void testModeChanged() { boolean isSingleTestMode = fTestRadioButton.getSelection(); setEnableSingleTestGroup(isSingleTestMode); setEnableContainerTestGroup(!isSingleTestMode); if (!isSingleTestMode && fContainerText.getText().length() == 0) { String projText = getProjectName(); if (Path.EMPTY.isValidSegment(projText)) { IScriptProject project = getScriptModel().getScriptProject( projText); if (project != null && project.exists()) { setContainerElement(project); } } } validatePage(); updateLaunchConfigurationDialog(); } private void setEnableSingleTestGroup(boolean enabled) { fProjectLabel.setEnabled(enabled); setEnableProjectField(enabled); fScriptLabel.setEnabled(enabled); setEnableScriptField(enabled); } @Override protected void projectChanged() { testModeChanged(); } private void setEnableContainerTestGroup(boolean enabled) { fContainerSearchButton.setEnabled(enabled); fContainerText.setEnabled(enabled); } protected void createTestEngineEditor(Composite parent, String text) { Label fTestEngine = new Label(parent, SWT.NONE); fTestEngine.setText(text); engineType = new Combo(parent, SWT.SINGLE | SWT.BORDER | SWT.DROP_DOWN); GridData gd = new GridData(GridData.FILL_HORIZONTAL); engineType.setLayoutData(gd); engineType.addModifyListener(getWidgetListener()); detect = createPushButton(parent, DLTKTestingMessages.MainLaunchConfigurationTab_detectEngine, null); ITestingEngine[] engines = TestingEngineManager .getEngines(getNatureID()); for (int i = 0; i < engines.length; i++) { String name = engines[i].getName(); this.engineType.add(name); nameToId.put(name, engines[i].getId()); } detect.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { handleDetectButtonSelected(); } }); new Label(parent, SWT.NONE); // place holder Composite engineStatusComposite = new Composite(parent, SWT.NONE); gd = new GridData(); gd.horizontalSpan = ((GridLayout) parent.getLayout()).numColumns - 1; engineStatusComposite.setLayoutData(gd); engineStatusComposite.setLayout(new RowLayout()); engineMessageImageLabel = new Label(engineStatusComposite, SWT.NONE); engineMessageLabel = new Label(engineStatusComposite, SWT.NONE); } private void handleDetectButtonSelected() { ISourceModule module = getSourceModule(); if (module != null && module.exists()) { final ITestingEngine[] engines = TestingEngineManager .getEngines(getNatureID()); final TestingEngineDetectResult result = TestingEngineManager .detect(engines, module); if (result != null) { engineType.select(Arrays.asList(engines).indexOf( result.getEngine())); updateEngineStatus(result.getStatus()); } } } /** * @param status */ private void updateEngineStatus(IStatus status) { Image newImage = null; String newMessage = status.getMessage(); switch (status.getSeverity()) { case IStatus.OK: newMessage = EMPTY_STRING; break; case IStatus.INFO: newImage = JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_INFO); break; case IStatus.WARNING: newImage = JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_WARNING); break; case IStatus.ERROR: newImage = JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_ERROR); break; } showMessage(newMessage, newImage); } private String message = EMPTY_STRING; private Image messageImage; /** * Show the new message and image. * * @param newMessage * @param newImage */ private void showMessage(String newMessage, Image newImage) { // Any change? if (message.equals(newMessage) && messageImage == newImage) { return; } message = newMessage; if (message == null) message = EMPTY_STRING; messageImage = newImage; engineMessageImageLabel.setImage(newImage); engineMessageLabel.setText(message); } private void updateEngineStatus() { updateEngineStatus(TestingEngineManager.getEngine(getEngineId())); } private void updateEngineStatus(final ITestingEngine engine) { IStatus status = Status.OK_STATUS; if (engine != null) { if (fTestRadioButton.getSelection()) { final ISourceModule module = getSourceModule(); if (module != null) { status = engine.validateSourceModule(module); } } else { // TODO validate container } } if (status != null) { updateEngineStatus(status); } } @Override protected ISourceModule getSourceModule() { if (!fTestRadioButton.getSelection()) { return null; } return super.getSourceModule(); } private boolean validateEngine() { if (TestingEngineManager.getEngine(getEngineId()) == null) { setErrorMessage(DLTKTestingMessages.MainLaunchConfigurationTab_ErrorEngineNotSelected); return false; } return true; } @Override protected void setDefaults(ILaunchConfigurationWorkingCopy configuration, IModelElement element) { element = ensureValid(element); if (element != null) { if (element.getElementType() >= IModelElement.SOURCE_MODULE) { element = element.getAncestor(IModelElement.SOURCE_MODULE); if (element != null) { super.setDefaults(configuration, element); TestingEngineDetectResult detection = TestingEngineManager .detect(TestingEngineManager .getEngines(getNatureID()), (ISourceModule) element); if (detection != null) { configuration.setAttribute( DLTKTestingConstants.ATTR_ENGINE_ID, detection .getEngine().getId()); } } } else { configuration.setAttribute( ScriptLaunchConfigurationConstants.ATTR_PROJECT_NAME, element.getScriptProject().getElementName()); configuration.setAttribute( DLTKTestingConstants.ATTR_TEST_CONTAINER, element .getHandleIdentifier()); } } } @Override protected void doPerformApply(ILaunchConfigurationWorkingCopy config) { if (fTestContainerRadioButton.getSelection() && fContainerElement != null) { config.setAttribute( ScriptLaunchConfigurationConstants.ATTR_PROJECT_NAME, fContainerElement.getScriptProject().getElementName()); config.setAttribute(DLTKTestingConstants.ATTR_TEST_CONTAINER, fContainerElement.getHandleIdentifier()); config.setAttribute( ScriptLaunchConfigurationConstants.ATTR_MAIN_SCRIPT_NAME, EMPTY_STRING); } else { config.setAttribute( ScriptLaunchConfigurationConstants.ATTR_PROJECT_NAME, getProjectName()); config.setAttribute( ScriptLaunchConfigurationConstants.ATTR_MAIN_SCRIPT_NAME, getScriptName()); config.setAttribute(DLTKTestingConstants.ATTR_TEST_CONTAINER, EMPTY_STRING); } performApplyInteractiveConsole(config); config.setAttribute(DLTKTestingConstants.ATTR_ENGINE_ID, getEngineId()); } @Override protected void mapResources(ILaunchConfigurationWorkingCopy config) throws CoreException { DLTKTestingMigrationDelegate.mapResources(config); } private String getEngineId() { return this.nameToId.get(this.engineType.getText()); } @Override protected void doInitializeForm(ILaunchConfiguration config) { initializeInteractiveConsoleFrom(config); // update test type String containerHandle = EMPTY_STRING; try { containerHandle = config.getAttribute( DLTKTestingConstants.ATTR_TEST_CONTAINER, EMPTY_STRING); } catch (CoreException ce) { } if (containerHandle.length() > 0) { updateTestContainerFromConfig(config); } else { updateTestScriptFromConfig(config); } // update engine String id = null; try { id = config.getAttribute(DLTKTestingConstants.ATTR_ENGINE_ID, EMPTY_STRING); } catch (CoreException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } if (id == null || id.length() == 0) { handleDetectButtonSelected(); } else { final ITestingEngine[] engines = TestingEngineManager .getEngines(getNatureID()); for (int i = 0; i < engines.length; i++) { final ITestingEngine engine = engines[i]; if (engine.getId().equals(id)) { this.engineType.select(i); updateEngineStatus(engine); break; } } } } /** * @param config */ private void updateTestScriptFromConfig(ILaunchConfiguration config) { updateMainModuleFromConfig(config); fTestRadioButton.setSelection(true); setEnableSingleTestGroup(true); setEnableContainerTestGroup(false); fTestContainerRadioButton.setSelection(false); fContainerText.setText(EMPTY_STRING); } /** * @param config */ private void updateTestContainerFromConfig(ILaunchConfiguration config) { String containerHandle = EMPTY_STRING; IModelElement containerElement = null; try { containerHandle = config.getAttribute( DLTKTestingConstants.ATTR_TEST_CONTAINER, EMPTY_STRING); if (containerHandle.length() > 0) { containerElement = DLTKCore.create(containerHandle); } } catch (CoreException ce) { } if (containerElement != null) fContainerElement = containerElement; fTestContainerRadioButton.setSelection(true); setEnableSingleTestGroup(false); setEnableContainerTestGroup(true); fTestRadioButton.setSelection(false); if (fContainerElement != null) fContainerText.setText(getPresentationName(fContainerElement)); setScriptName(EMPTY_STRING); } }