diff --git a/launchbar/org.eclipse.launchbar.core.tests/src/org/eclipse/launchbar/core/internal/LaunchBarManagerTest.java b/launchbar/org.eclipse.launchbar.core.tests/src/org/eclipse/launchbar/core/internal/LaunchBarManagerTest.java index 175a7353814..799e2f82a44 100644 --- a/launchbar/org.eclipse.launchbar.core.tests/src/org/eclipse/launchbar/core/internal/LaunchBarManagerTest.java +++ b/launchbar/org.eclipse.launchbar.core.tests/src/org/eclipse/launchbar/core/internal/LaunchBarManagerTest.java @@ -24,7 +24,9 @@ import static org.mockito.Mockito.mock; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; @@ -40,9 +42,89 @@ import org.eclipse.launchbar.core.ILaunchDescriptorType; import org.eclipse.launchbar.core.target.ILaunchTarget; import org.eclipse.launchbar.core.target.ILaunchTargetManager; +import org.junit.After; +import org.junit.Before; import org.junit.Test; public class LaunchBarManagerTest { + + /** + *

This is a dummy launch object

+ * + * Object's data: launchObject_no1 + * + */ + private static final String launchObject_no1 = "launchObject_no1"; + private static final String launchConfigTypeId_no1 = "fakeLaunchConfigType_no1"; //$NON-NLS-1$ + private static final String launchDescTypeId_no1 = "fakeDescriptorType_no1"; //$NON-NLS-1$ + private static final String preferredMode_no1 = "preferredMode_no1"; //$NON-NLS-1$ + /** + *

This is a dummy launch object

+ * + * Object's data: launchObject_no2 + * + */ + private static final String launchObject_no2 = "launchObject_no2"; + private static final String launchConfigTypeId_no2 = "fakeLaunchConfigType_no2"; //$NON-NLS-1$ + private static final String launchDescTypeId_no2 = "fakeDescriptorType_no2"; //$NON-NLS-1$ + private static final String preferredMode_no2 = "preferredMode_no2"; //$NON-NLS-1$ + + private static final String runMode = "run"; //$NON-NLS-1$ + private static final String debugMode = "debug"; //$NON-NLS-1$ + + private LaunchBarManager launchBarManagerMock = null; + + @Before + public void before() throws CoreException { + Map launchConfigTypes = new HashMap<>(); + // Create mocked Object no1 + ILaunchDescriptor descriptor_no1 = createLaunchDescriptorMock(launchObject_no1); + ILaunchConfigurationType launchConfigType_no1 = createLaunchConfigType(launchConfigTypeId_no1, + preferredMode_no1, runMode, debugMode); + ILaunchConfigurationProvider launchConfigProvider_no1 = creatLaunchConfigProvier(launchConfigType_no1, + descriptor_no1, preferredMode_no1); + launchConfigTypes.put(launchConfigTypeId_no1, launchConfigType_no1); + // Create mocked Object no2 + ILaunchDescriptor descriptor_no2 = createLaunchDescriptorMock(launchObject_no2); + ILaunchConfigurationType launchConfigType_no2 = createLaunchConfigType(launchConfigTypeId_no2, runMode, + debugMode); + // preferredMode_no2 not supported + doReturn(false).when(launchConfigType_no2).supportsMode(preferredMode_no2); + ILaunchConfigurationProvider launchConfigProvider_no2 = creatLaunchConfigProvier(launchConfigType_no2, + descriptor_no2, preferredMode_no2); + launchConfigTypes.put(launchConfigTypeId_no2, launchConfigType_no2); + // Mock Launch bar manager + List elements = new ArrayList<>(); + final IExtensionPoint extensionPoint = mock(IExtensionPoint.class); + IExtension extension = mock(IExtension.class); + doReturn(new IExtension[] { extension }).when(extensionPoint).getExtensions(); + elements.add(createConfigElementMockForDescriptorType(launchDescTypeId_no1, descriptor_no1)); + elements.add(createConfigElementMockForConfigProvider(launchDescTypeId_no1, launchConfigProvider_no1)); + elements.add(createConfigElementMockForDescriptorType(launchDescTypeId_no2, descriptor_no2)); + elements.add(createConfigElementMockForConfigProvider(launchDescTypeId_no2, launchConfigProvider_no2)); + ILaunchManager launchManager = createLaunchManagerMock(launchConfigTypes, preferredMode_no1, preferredMode_no2, + runMode, debugMode); + ILaunchTargetManager targetManager = createLaunchTargetManagerMock(); + doReturn(elements.toArray(IConfigurationElement[]::new)).when(extension).getConfigurationElements(); + // Mock Launch bar manager + launchBarManagerMock = createLaunchBarManagerMock(extensionPoint, launchManager, targetManager); + // Initial LaunchBarManager + launchBarManagerMock.init(); + } + + @After + public void after() { + launchBarManagerMock.dispose(); + } + @Test public void startupTest() throws Exception { // Make sure the manager starts up and defaults everything to null @@ -310,6 +392,207 @@ ILaunchTargetManager getLaunchTargetManager() { assertEquals(launchConfig, manager.getActiveLaunchConfiguration()); } + /** + *

+ * Test that preferred launch mode is taken into consideration in + * {@link LaunchBarManager#syncActiveMode()}. + *

+ * Verifies that when stored mode and last active mode is NULL, preferred mode is selected + * as active mode.

+ * + * Order when choosing active mode for active launch descriptor is: + * + * + * @throws CoreException + */ + @Test + public void preferredLaunchModeTest_StoredModeAndLastActiveModeIsNull() throws CoreException { + launchBarManagerMock.launchObjectAdded(launchObject_no1); + // "preferredMode_no1" will be selected as active mode. + ILaunchMode activeMode = launchBarManagerMock.getActiveLaunchMode(); + assertEquals(preferredMode_no1, activeMode.getIdentifier()); + } + + /** + *

+ * Test that preferred launch mode is taken into consideration in + * {@link LaunchBarManager#syncActiveMode()}. + *

+ * Verifies that when stored mode and last active mode is NULL, and preferred mode is not + * supported, "run" mode (fall back mode) is selected as active mode.

+ * + * Order when choosing active mode for active launch descriptor is: + * + * + * @throws CoreException + */ + @Test + public void preferredLaunchModeTest_preferredModeNotSupported() throws CoreException { + launchBarManagerMock.launchObjectAdded(launchObject_no2); + // When preferred mode not supported, launch bar manager fall back to other hard-coded mode. + // In this case, "run" comes after preferred mode, so "run" is selected as active mode. + ILaunchMode activeMode = launchBarManagerMock.getActiveLaunchMode(); + assertEquals(runMode, activeMode.getIdentifier()); + } + + /** + *

+ * Test that preferred launch mode is taken into consideration in + * {@link LaunchBarManager#syncActiveMode()}. + *

+ * Verifies that when stored mode is NULL and last active mode is Not NULL, last active + * mode will be selected as active mode.

+ * + * Order when choosing active mode for active launch descriptor is: + * + * + * @throws CoreException + */ + @Test + public void preferredLaunchModeTest_lastActiveModeNotNull() throws CoreException { + // After launch object no2 is added and activated, active mode now is "run" mode. + launchBarManagerMock.launchObjectAdded(launchObject_no2); + launchBarManagerMock.launchObjectAdded(launchObject_no1); + // When launchObject_no1 is added, last active mode now will be "run." + // Since preferred mode comes after last active mode, "run" mode is selected for launchObject_no1. + ILaunchMode activeMode = launchBarManagerMock.getActiveLaunchMode(); + assertEquals(runMode, activeMode.getIdentifier()); + } + + /** + *

+ * Test that preferred launch mode is taken into consideration in + * {@link LaunchBarManager#syncActiveMode()}. + *

+ * Verifies that when stored mode is not NULL, stored mode is selected as active mode.

+ * + * Order when choosing active mode for active launch descriptor is: + * + * + * @throws CoreException + */ + @Test + public void preferredLaunchModeTest_storedModeNotNull() throws CoreException { + // Stored mode is saved as "preferredMode_no1" for launchObject_no1 + launchBarManagerMock.launchObjectAdded(launchObject_no1); + launchBarManagerMock.launchObjectRemoved(launchObject_no1); + // After launch object no2 is added and activated, active mode now is "run" mode. + launchBarManagerMock.launchObjectAdded(launchObject_no2); + launchBarManagerMock.launchObjectAdded(launchObject_no1); + // After launch object no1 is added and activated, stored mode now is "preferredMode_no1". + // Since stored mode comes first, "preferredMode_no1" mode is selected for launchObject_no1 + // when it is re-activated. + ILaunchMode activeMode = launchBarManagerMock.getActiveLaunchMode(); + assertEquals(preferredMode_no1, activeMode.getIdentifier()); + } + + private ILaunchDescriptor createLaunchDescriptorMock(Object launchObject) throws CoreException { + ILaunchDescriptorType descriptorType = mock(ILaunchDescriptorType.class); + ILaunchDescriptor descriptor = mock(ILaunchDescriptor.class); + doReturn(true).when(descriptorType).supportsTargets(); + doReturn(descriptor).when(descriptorType).getDescriptor(launchObject); + doReturn(descriptorType).when(descriptor).getType(); + doReturn(launchObject).when(descriptor).getName(); + return descriptor; + } + + private ILaunchConfigurationType createLaunchConfigType(String launchConfigTypeId, String... supportModes) { + ILaunchConfigurationType launchConfigType = mock(ILaunchConfigurationType.class); + doReturn(launchConfigTypeId).when(launchConfigType).getIdentifier(); + for (String mode : supportModes) { + doReturn(true).when(launchConfigType).supportsMode(mode); + } + return launchConfigType; + } + + private ILaunchConfigurationProvider creatLaunchConfigProvier(ILaunchConfigurationType launchConfigType, + ILaunchDescriptor desc, String preferredMode) throws CoreException { + ILaunchConfigurationProvider configProvider = mock(ILaunchConfigurationProvider.class); + ILaunchConfiguration launchConfig = mock(ILaunchConfiguration.class); + doReturn(launchConfig).when(configProvider).getLaunchConfiguration(eq(desc), any(ILaunchTarget.class)); + doReturn(launchConfigType).when(configProvider).getLaunchConfigurationType(any(ILaunchDescriptor.class), + any(ILaunchTarget.class)); + doReturn(launchConfig).when(desc).getAdapter(ILaunchConfiguration.class); + doAnswer(invocation -> { + ILaunchTarget target = (ILaunchTarget) invocation.getArguments()[1]; + return target.getTypeId().equals(ILaunchTargetManager.localLaunchTargetTypeId); + }).when(configProvider).supports(eq(desc), any(ILaunchTarget.class)); + doReturn(preferredMode).when(configProvider).getPreferredLaunchModeId(eq(desc), any(ILaunchTarget.class)); + return configProvider; + } + + private IConfigurationElement createConfigElementMockForDescriptorType(String descriptorTypeId, + ILaunchDescriptor desc) throws CoreException { + IConfigurationElement element = mock(IConfigurationElement.class); + doReturn("descriptorType").when(element).getName(); //$NON-NLS-1$ + doReturn(descriptorTypeId).when(element).getAttribute("id"); //$NON-NLS-1$ + doReturn(desc.getType()).when(element).createExecutableExtension("class"); //$NON-NLS-1$ + return element; + } + + private IConfigurationElement createConfigElementMockForConfigProvider(String descriptorTypeId, + ILaunchConfigurationProvider configProvider) throws CoreException { + IConfigurationElement element = mock(IConfigurationElement.class); + doReturn("configProvider").when(element).getName(); //$NON-NLS-1$ + doReturn(descriptorTypeId).when(element).getAttribute("descriptorType"); //$NON-NLS-1$ + doReturn("10").when(element).getAttribute("priority"); //$NON-NLS-1$ $NON-NLS-2$ + doReturn(configProvider).when(element).createExecutableExtension("class"); //$NON-NLS-1$ + return element; + } + + private ILaunchTargetManager createLaunchTargetManagerMock() { + ILaunchTargetManager targetManager = mock(ILaunchTargetManager.class); + ILaunchTarget localTarget = mock(ILaunchTarget.class); + doReturn(ILaunchTargetManager.localLaunchTargetTypeId).when(localTarget).getTypeId(); + doReturn("Local").when(localTarget).getId(); //$NON-NLS-1$ + doReturn(new ILaunchTarget[] { localTarget }).when(targetManager).getLaunchTargets(); + return targetManager; + } + + private ILaunchManager createLaunchManagerMock(Map launchConfigTypes, + String... supportModes) throws CoreException { + ILaunchManager launchManager = mock(ILaunchManager.class); + List modes = new ArrayList<>(); + for (String supportMode : supportModes) { + ILaunchMode mode = createLaunchModeMock(supportMode); + doReturn(mode).when(launchManager).getLaunchMode(supportMode); + modes.add(mode); + } + doReturn(modes.toArray(ILaunchMode[]::new)).when(launchManager).getLaunchModes(); + + launchConfigTypes.forEach((typeId, type) -> { + doReturn(type).when(launchManager).getLaunchConfigurationType(typeId); + }); + doReturn(new ILaunchConfiguration[0]).when(launchManager).getLaunchConfigurations(); + return launchManager; + } + + private LaunchBarManager createLaunchBarManagerMock(IExtensionPoint extensionPoint, ILaunchManager launchManager, + ILaunchTargetManager targetManager) { + return new LaunchBarManager(false) { + @Override + IExtensionPoint getExtensionPoint() throws CoreException { + return extensionPoint; + } + + @Override + ILaunchManager getLaunchManager() { + return launchManager; + } + + @Override + ILaunchTargetManager getLaunchTargetManager() { + return targetManager; + } + }; + } + + private ILaunchMode createLaunchModeMock(String identifier) { + ILaunchMode mode = mock(ILaunchMode.class); + doReturn(identifier).when(mode).getIdentifier(); + return mode; + } + // TODO - test that changing active target type produces a different launch // config type // TODO - test that settings are maintained after a restart diff --git a/launchbar/org.eclipse.launchbar.core/.settings/.api_filters b/launchbar/org.eclipse.launchbar.core/.settings/.api_filters new file mode 100644 index 00000000000..99a755ba333 --- /dev/null +++ b/launchbar/org.eclipse.launchbar.core/.settings/.api_filters @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/launchbar/org.eclipse.launchbar.core/META-INF/MANIFEST.MF b/launchbar/org.eclipse.launchbar.core/META-INF/MANIFEST.MF index 751b3444b41..5f4935e223e 100644 --- a/launchbar/org.eclipse.launchbar.core/META-INF/MANIFEST.MF +++ b/launchbar/org.eclipse.launchbar.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.launchbar.core;singleton:=true -Bundle-Version: 3.1.0.qualifier +Bundle-Version: 3.2.0.qualifier Bundle-Activator: org.eclipse.launchbar.core.internal.Activator Bundle-Vendor: %providerName Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.34.0,4.0.0)", diff --git a/launchbar/org.eclipse.launchbar.core/src/org/eclipse/launchbar/core/ILaunchConfigurationProvider.java b/launchbar/org.eclipse.launchbar.core/src/org/eclipse/launchbar/core/ILaunchConfigurationProvider.java index 5cabc260af5..a0ab638b8d2 100644 --- a/launchbar/org.eclipse.launchbar.core/src/org/eclipse/launchbar/core/ILaunchConfigurationProvider.java +++ b/launchbar/org.eclipse.launchbar.core/src/org/eclipse/launchbar/core/ILaunchConfigurationProvider.java @@ -131,4 +131,26 @@ boolean launchDescriptorMatches(ILaunchDescriptor descriptor, ILaunchConfigurati */ void launchTargetRemoved(ILaunchTarget target) throws CoreException; + /** + * Returns the preferred launch mode id for the given launch descriptor and target. + *

+ * Returning {@code null} indicates that this provider has no preferred mode for + * the given descriptor/target combination. + *

+ *

+ * The returned id is treated as a preference only. If it does not resolve to a + * known launch mode, or if that mode is not supported for the active descriptor + * and target, Launch Bar continues normal fallback resolution. + *

+ * + * @param descriptor the launch descriptor + * @param target the launch target + * @return the preferred launch mode id, or {@code null} if none + * @throws CoreException if the preferred mode cannot be determined + * @since 3.2 + */ + default String getPreferredLaunchModeId(ILaunchDescriptor descriptor, ILaunchTarget target) throws CoreException { + return null; + } + } diff --git a/launchbar/org.eclipse.launchbar.core/src/org/eclipse/launchbar/core/internal/LaunchBarManager.java b/launchbar/org.eclipse.launchbar.core/src/org/eclipse/launchbar/core/internal/LaunchBarManager.java index 06f185cfe62..e17b9c63881 100644 --- a/launchbar/org.eclipse.launchbar.core/src/org/eclipse/launchbar/core/internal/LaunchBarManager.java +++ b/launchbar/org.eclipse.launchbar.core/src/org/eclipse/launchbar/core/internal/LaunchBarManager.java @@ -569,10 +569,11 @@ private void syncActiveMode() throws CoreException { // last desc mode id String storedModeId = getPerDescriptorStore().get(PREF_ACTIVE_LAUNCH_MODE, null); String lastActiveModeId = activeLaunchMode == null ? null : activeLaunchMode.getIdentifier(); + String preferredModeId = getPreferredLaunchModeId(activeLaunchDesc, activeLaunchTarget); // this is based on active desc and target which are already set ILaunchMode[] supportedModes = getLaunchModes(); if (supportedModes.length > 0) { // mna, what if no modes are supported? - String modeNames[] = new String[] { storedModeId, lastActiveModeId, "run", //$NON-NLS-1$ + String modeNames[] = new String[] { storedModeId, lastActiveModeId, preferredModeId, "run", //$NON-NLS-1$ "debug", //$NON-NLS-1$ supportedModes[0].getIdentifier() }; for (int i = 0; i < modeNames.length; i++) { @@ -1050,4 +1051,24 @@ private boolean launchDescriptorMatches(ILaunchDescriptor desc, ILaunchConfigura } return false; } + + private String getPreferredLaunchModeId(ILaunchDescriptor descriptor, ILaunchTarget target) throws CoreException { + if (descriptor == null) { + return null; + } + List providerInfos = configProviders.get(getDescriptorTypeId(descriptor.getType())); + if (providerInfos == null) { + return null; + } + for (LaunchConfigProviderInfo providerInfo : providerInfos) { + if (providerInfo.enabled(descriptor) && providerInfo.enabled(target)) { + ILaunchConfigurationProvider provider = providerInfo.getProvider(); + if (provider != null && provider.supports(descriptor, target)) { + return provider.getPreferredLaunchModeId(descriptor, target); + } + } + } + // not found + return null; + } }