blob: 5699252a90d3853aed8630ed42550cd81dcdc045 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* EclipseSource Corporation - ongoing enhancements
* Ian Bull <irbull@cs.uvic.ca> - bug 204404
*******************************************************************************/
package org.eclipse.pde.internal.ui.launcher;
import java.util.*;
import java.util.stream.Stream;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jdt.internal.junit.launcher.*;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.PluginRegistry;
import org.eclipse.pde.internal.launching.launcher.*;
import org.eclipse.pde.internal.ui.PDEPlugin;
import org.eclipse.pde.launching.IPDELauncherConstants;
import org.eclipse.pde.launching.JUnitLaunchConfigurationDelegate;
import org.eclipse.pde.ui.launcher.AbstractLauncherTab;
public class PluginBlock extends AbstractPluginBlock {
/**
* The configuration this block is currently displaying or <code>null</code> if none set
*/
protected ILaunchConfiguration fLaunchConfig;
/**
* Whether the controls have been initialized for fLaunchConfig
*/
protected boolean fIsEnabled = false;
/**
* Flag for when the combo changed. We improve the performance of the config by waiting until the combo changed
* to initialize the contents of the table.
*/
protected boolean fInitDefaultCheckState = false;
public PluginBlock(AbstractLauncherTab tab) {
super(tab);
}
@Override
public void initializeFrom(ILaunchConfiguration config, boolean enableTable) throws CoreException {
if (fLaunchConfig != null && fLaunchConfig.equals(config) && fIsEnabled == enableTable) {
// Do nothing
return;
}
fLaunchConfig = config;
fIsEnabled = enableTable;
super.initializeFrom(config, enableTable);
if (enableTable) {
initializePluginsState(config);
// If the workspace plug-in state has changed (project closed, etc.) the launch config needs to be updated without making the tab dirty
if (fLaunchConfig.isWorkingCopy()) {
savePluginState((ILaunchConfigurationWorkingCopy) fLaunchConfig);
}
}
enableViewer(enableTable);
updateCounter();
fTab.updateLaunchConfigurationDialog();
}
/**
* Refresh the enable state of this block using the current launch config
* @param enable
* @throws CoreException
*/
public void initialize(boolean enable) throws CoreException {
// To support lazy loading of the table we need to set some launch configuration attributes when the combo changes
if (fLaunchConfig != null) {
fInitDefaultCheckState = enable
&& !fLaunchConfig.hasAttribute(IPDELauncherConstants.SELECTED_WORKSPACE_BUNDLES)
&& !fLaunchConfig.hasAttribute(IPDELauncherConstants.SELECTED_TARGET_BUNDLES);
fTab.updateLaunchConfigurationDialog();
initializeFrom(fLaunchConfig, enable);
}
}
private void initializePluginsState(ILaunchConfiguration config) throws CoreException {
Map<IPluginModelBase, String> selected = BundleLauncherHelper.getAllSelectedPluginBundles(config);
initializePluginsState(selected);
}
@Override
protected boolean isEnabled() {
return fIsEnabled;
}
@Override
protected void savePluginState(ILaunchConfigurationWorkingCopy config) {
// If the table is populated, store what is checked. If we are lazy loading and need to init, store the default checkstate
if (isEnabled() || fInitDefaultCheckState) {
PluginModelNameBuffer wBuffer = new PluginModelNameBuffer();
PluginModelNameBuffer tBuffer = new PluginModelNameBuffer();
if (fInitDefaultCheckState) {
// If this is the first time the table is enabled, default the checkstate to all workspace plug-ins
TreeSet<String> checkedWorkspace = new TreeSet<>();
IPluginModelBase[] workspaceModels = getWorkspaceModels();
for (IPluginModelBase workspaceModel : workspaceModels) {
String id = workspaceModel.getPluginBase().getId();
if (id != null) {
wBuffer.add(workspaceModel);
checkedWorkspace.add(id);
}
}
IPluginModelBase[] externalModels = getExternalModels();
for (IPluginModelBase model : externalModels) {
// If there is a workspace bundle with the same id, don't check the external version
if (!checkedWorkspace.contains(model.getPluginBase().getId()) && model.isEnabled()) {
tBuffer.add(model);
}
}
fInitDefaultCheckState = false;
} else {
// If we have checked elements, save them to the config
Object[] selected = fPluginTreeViewer.getCheckedLeafElements();
for (Object selectedElement : selected) {
if (selectedElement instanceof IPluginModelBase) {
IPluginModelBase model = (IPluginModelBase) selectedElement;
if (model.getUnderlyingResource() == null) {
tBuffer.add(model);
} else {
wBuffer.add(model);
}
}
}
}
config.setAttribute(IPDELauncherConstants.SELECTED_WORKSPACE_BUNDLES, wBuffer.getNameSet());
config.setAttribute(IPDELauncherConstants.SELECTED_TARGET_BUNDLES, tBuffer.getNameSet());
PluginModelNameBuffer buffer = new PluginModelNameBuffer();
if (fAddWorkspaceButton.getSelection()) {
IPluginModelBase[] workspaceModels = getWorkspaceModels();
for (int i = 0; i < workspaceModels.length; i++) {
if (!fPluginTreeViewer.isCheckedLeafElement(workspaceModels[i])) {
buffer.add(workspaceModels[i]);
}
}
}
config.setAttribute(IPDELauncherConstants.DESELECTED_WORKSPACE_BUNDLES, buffer.getNameSet());
}
}
@Override
protected void addRequiredPlugins() {
// Check that the application or product we are launching has its requirements included
try {
List<String> requiredIds = RequirementHelper.getApplicationLaunchRequirements(fLaunchConfig);
ITestKind testKind = JUnitLaunchConfigurationConstants.getTestRunnerKind(fLaunchConfig);
if (TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKind.getId())
|| TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKind.getId())) {
requiredIds = Arrays.asList(addJunitPlugins(requiredIds.toArray(String[]::new), testKind));
}
for (String requiredId : requiredIds) {
// see if launcher plugin is already included
IPluginModelBase base = findPlugin(requiredId);
if (base == null) {
base = PluginRegistry.findModel(requiredId);
if (base != null) {
fPluginTreeViewer.setChecked(base, true);
}
}
}
} catch (CoreException e) {
PDEPlugin.log(e);
}
super.addRequiredPlugins();
}
private String[] addJunitPlugins(String[] requiredIds, ITestKind testKind) {
String[] requiredPlugins;
requiredPlugins = JUnitLaunchConfigurationDelegate.getRequiredPlugins(fLaunchConfig);
if (requiredIds != null) {
Object[] plugins = null;
if (TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKind.getId())) {
String[] additionJunit5 = { "org.junit.jupiter.api", "org.eclipse.jdt.junit5.runtime" }; //$NON-NLS-1$ //$NON-NLS-2$
plugins = Stream.of(requiredIds, requiredPlugins, additionJunit5).flatMap(Stream::of)
.toArray();
} else {
plugins = Stream.of(requiredIds, requiredPlugins).flatMap(Stream::of).toArray();
}
requiredIds = Arrays.copyOf(plugins, plugins.length, String[].class);
}
return requiredIds;
}
@Override
protected LaunchValidationOperation createValidationOperation() throws CoreException {
Set<IPluginModelBase> models = BundleLauncherHelper.getMergedBundleMap(fLaunchConfig, false).keySet();
return new EclipsePluginValidationOperation(fLaunchConfig, models);
}
}