diff options
author | Brian de Alwis | 2015-03-20 20:56:21 +0000 |
---|---|---|
committer | Benjamin Cabé | 2015-04-24 14:21:37 +0000 |
commit | 7948528a6cb8f45972e0c8314f7fe91993d659e2 (patch) | |
tree | 96543b18af78b28c76ab595a62b734cf41f1fb99 | |
parent | c1c7f1a04010ec16ca85be01faf31bf029b63bf1 (diff) | |
download | eclipse.pde.ui-7948528a6cb8f45972e0c8314f7fe91993d659e2.tar.gz eclipse.pde.ui-7948528a6cb8f45972e0c8314f7fe91993d659e2.tar.xz eclipse.pde.ui-7948528a6cb8f45972e0c8314f7fe91993d659e2.zip |
Bug 324310 - Load API baseline from target definition
Allow defining, saving, and restoring API baselines
based on target definitions.
Signed-Off-By: Brian de Alwis <bsd@mt.ca>
Change-Id: I236b1afdaf49d71daf17f10b218935a65f126e0a
14 files changed, 1164 insertions, 371 deletions
diff --git a/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/tests/ApiToolsPluginTestSuite.java b/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/tests/ApiToolsPluginTestSuite.java index 4e686db179..4b8401ba49 100644 --- a/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/tests/ApiToolsPluginTestSuite.java +++ b/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/tests/ApiToolsPluginTestSuite.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2014 IBM Corporation and others. + * Copyright (c) 2007, 2015 IBM Corporation 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 @@ -7,12 +7,10 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Manumitting Technologies Inc - bug 324310 *******************************************************************************/ package org.eclipse.pde.api.tools.tests; -import junit.framework.Test; -import junit.framework.TestSuite; - import org.eclipse.pde.api.tools.anttasks.tests.ApiToolsAntTasksTestSuite; import org.eclipse.pde.api.tools.builder.tests.ApiBuilderTest; import org.eclipse.pde.api.tools.model.tests.ApiFilterStoreTests; @@ -22,6 +20,10 @@ import org.eclipse.pde.api.tools.util.tests.ApiBaselineManagerTests; import org.eclipse.pde.api.tools.util.tests.ApiDescriptionProcessorTests; import org.eclipse.pde.api.tools.util.tests.PreferencesTests; import org.eclipse.pde.api.tools.util.tests.ProjectCreationTests; +import org.eclipse.pde.api.tools.util.tests.TargetAsBaselineTests; + +import junit.framework.Test; +import junit.framework.TestSuite; /** @@ -51,6 +53,7 @@ public class ApiToolsPluginTestSuite extends TestSuite { addTest(new TestSuite(ApiFilterStoreTests.class)); addTest(new TestSuite(FilterStoreTests.class)); addTest(new TestSuite(ApiProblemTests.class)); + addTest(new TestSuite(TargetAsBaselineTests.class)); addTest(ApiBuilderTest.suite()); addTest(ApiToolsAntTasksTestSuite.suite()); //addTest(ExternalDependencyTestSuite.suite()); diff --git a/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/util/tests/TargetAsBaselineTests.java b/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/util/tests/TargetAsBaselineTests.java new file mode 100644 index 0000000000..c54ff941d6 --- /dev/null +++ b/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/util/tests/TargetAsBaselineTests.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2015 Manumitting Technologies Inc 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: + * Manumitting Technologies Inc - initial API and implementation + *******************************************************************************/ +package org.eclipse.pde.api.tools.util.tests; + +import java.io.File; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.pde.api.tools.internal.model.ApiModelFactory; +import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; +import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline; +import org.eclipse.pde.api.tools.model.tests.TestSuiteHelper; +import org.eclipse.pde.api.tools.tests.AbstractApiTest; +import org.eclipse.pde.core.target.ITargetDefinition; +import org.eclipse.pde.core.target.ITargetLocation; +import org.eclipse.pde.core.target.ITargetPlatformService; + +public class TargetAsBaselineTests extends AbstractApiTest { + ITargetDefinition definition; + + @Override + public void setUp() { + IPath path = TestSuiteHelper.getPluginDirectoryPath(); + path = path.append("test-plugins"); //$NON-NLS-1$ + File file = path.toFile(); + assertTrue(file.exists()); + + ITargetPlatformService service = (ITargetPlatformService) ApiPlugin.getDefault().acquireService(ITargetPlatformService.class.getName()); + definition = service.newTarget(); + definition.setName("Test Definition"); //$NON-NLS-1$ + ITargetLocation location = service.newDirectoryLocation(file.getAbsolutePath()); + definition.setTargetLocations(new ITargetLocation[] { location }); + } + + /** + * Test that an API baseline can be loaded from a target + * + * @throws CoreException + */ + public void testLoadTarget() throws CoreException { + IApiBaseline baseline = ApiModelFactory.newApiBaselineFromTarget(getClass().getName(), definition, null); + assertTrue("This baseline should appear to be from a target definition", ApiModelFactory.isDerivedFromTarget(baseline)); //$NON-NLS-1$ + assertTrue("This baseline should be from this particular target definition", ApiModelFactory.isDerivedFromTarget(baseline, definition)); //$NON-NLS-1$ + assertTrue(baseline.getApiComponents().length >= 3); // includes EEs + } + + /** + * Test that an API baseline loaded from a target can be detected as stale + * + * @throws CoreException + */ + public void testCheckStale() throws CoreException { + IApiBaseline baseline = ApiModelFactory.newApiBaselineFromTarget(getClass().getName(), definition, null); + assertTrue(ApiModelFactory.isDerivedFromTarget(baseline)); + + // Assumes definition is a TargetDefinition and setOS() increments the + // sequence number + assertTrue(ApiModelFactory.isUpToDateWithTarget(baseline, definition)); + definition.setOS("next"); //$NON-NLS-1$ + assertFalse(ApiModelFactory.isUpToDateWithTarget(baseline, definition)); + assertTrue("This baseline should still be from this particular target definition", ApiModelFactory.isDerivedFromTarget(baseline, definition)); //$NON-NLS-1$ + } +} diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/IApiToolsHelpContextIds.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/IApiToolsHelpContextIds.java index 5fcdce5d9b..c21a689225 100644 --- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/IApiToolsHelpContextIds.java +++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/IApiToolsHelpContextIds.java @@ -22,7 +22,7 @@ import org.eclipse.pde.api.tools.ui.internal.use.DescriptionPatternPage; import org.eclipse.pde.api.tools.ui.internal.use.PatternSelectionPage; import org.eclipse.pde.api.tools.ui.internal.use.ReportPatternPage; import org.eclipse.pde.api.tools.ui.internal.views.APIToolingView; -import org.eclipse.pde.api.tools.ui.internal.wizards.ApiBaselineWizardPage; +import org.eclipse.pde.api.tools.ui.internal.wizards.DirectoryBasedApiBaselineWizardPage; import org.eclipse.pde.api.tools.ui.internal.wizards.ApiToolingSetupWizardPage; import org.eclipse.pde.api.tools.ui.internal.wizards.CompareToBaselineWizard; import org.eclipse.pde.api.tools.ui.internal.wizards.JavadocConversionPage; @@ -41,7 +41,7 @@ public interface IApiToolsHelpContextIds { */ public static final String APIBASELINE_PREF_PAGE = PREFIX + "apiprofiles_preference_page"; //$NON-NLS-1$ /** - * Constant representing the help id for the {@link ApiBaselineWizardPage} + * Constant representing the help id for the {@link DirectoryBasedApiBaselineWizardPage} */ public static final String APIPROFILES_WIZARD_PAGE = PREFIX + "apiprofiles_wizard_page"; //$NON-NLS-1$ /** diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/preferences/ApiBaselinePreferencePage.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/preferences/ApiBaselinePreferencePage.java index b297a4d25d..0734454265 100644 --- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/preferences/ApiBaselinePreferencePage.java +++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/preferences/ApiBaselinePreferencePage.java @@ -275,7 +275,7 @@ public class ApiBaselinePreferencePage extends PreferencePage implements IWorkbe */ protected void doEdit(final IApiBaseline baseline) { ApiBaselineWizard wizard = new ApiBaselineWizard(baseline); - WizardDialog dialog = new WizardDialog(ApiUIPlugin.getShell(), wizard); + WizardDialog dialog = new WizardDialog(getShell(), wizard); if (dialog.open() == IDialogConstants.OK_ID) { IApiBaseline newbaseline = wizard.getProfile(); if (newbaseline != null) { diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/ApiBaselineWizard.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/ApiBaselineWizard.java index afd151d473..1353fa9342 100644 --- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/ApiBaselineWizard.java +++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/ApiBaselineWizard.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2013 IBM Corporation and others. + * Copyright (c) 2007, 2015 IBM Corporation 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 @@ -7,12 +7,14 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Manumitting Technologies Inc - bug 324310 *******************************************************************************/ package org.eclipse.pde.api.tools.ui.internal.wizards; import java.io.IOException; import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.Wizard; import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline; import org.eclipse.pde.api.tools.ui.internal.ApiUIPlugin; @@ -65,7 +67,32 @@ public class ApiBaselineWizard extends Wizard { */ @Override public void addPages() { - addPage(new ApiBaselineWizardPage(profile)); + if (profile != null) { + profile.getApiComponents(); // XXX: necc to load baseline cache + if (TargetBasedApiBaselineWizardPage.isApplicable(profile)) { + addPage(new TargetBasedApiBaselineWizardPage(profile)); + } else /* if(ApiBaselineWizardPage.isApplicable(profile)) */ { + addPage(new DirectoryBasedApiBaselineWizardPage(profile)); + } + } else { + setForcePreviousAndNextButtons(true); + addPage(new SelectApiBaselineTypeWizardPage()); + } + } + + @Override + public boolean canFinish() { + return super.canFinish() && getApiBaselineWizardPage() != null; + } + + private ApiBaselineWizardPage getApiBaselineWizardPage() { + // Assumes that the AbstractApiBaselineWizardPage page + // is the current page + IWizardPage page = getContainer().getCurrentPage(); + if (page instanceof ApiBaselineWizardPage) { + return (ApiBaselineWizardPage) page; + } + return null; } /* @@ -75,10 +102,13 @@ public class ApiBaselineWizard extends Wizard { @Override public boolean performFinish() { try { - ApiBaselineWizardPage page = (ApiBaselineWizardPage) getContainer().getCurrentPage(); - profile = page.finish(); - content = page.contentChanged(); - return profile != null; + ApiBaselineWizardPage page = getApiBaselineWizardPage(); + if (page != null) { + profile = page.finish(); + content = page.contentChanged(); + return profile != null; + } + return true; } catch (IOException e) { ApiUIPlugin.log(e); } catch (CoreException e) { @@ -92,8 +122,10 @@ public class ApiBaselineWizard extends Wizard { */ @Override public boolean performCancel() { - ApiBaselineWizardPage page = (ApiBaselineWizardPage) getContainer().getCurrentPage(); - page.cancel(); + ApiBaselineWizardPage page = getApiBaselineWizardPage(); + if (page != null) { + page.cancel(); + } return super.performCancel(); } } diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/ApiBaselineWizardPage.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/ApiBaselineWizardPage.java index 558e095ad3..e6a565e19a 100644 --- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/ApiBaselineWizardPage.java +++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/ApiBaselineWizardPage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2013 IBM Corporation and others. + * Copyright (c) 2007, 2015 IBM Corporation 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 @@ -7,72 +7,34 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Manumitting Technologies Inc - bug 324310 *******************************************************************************/ package org.eclipse.pde.api.tools.ui.internal.wizards; import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import java.net.URL; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.jdt.launching.JavaRuntime; -import org.eclipse.jdt.launching.environments.IExecutionEnvironment; -import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.viewers.ViewerComparator; -import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.osgi.service.datalocation.Location; import org.eclipse.pde.api.tools.internal.ApiBaselineManager; import org.eclipse.pde.api.tools.internal.model.ApiModelFactory; -import org.eclipse.pde.api.tools.internal.model.SystemLibraryApiComponent; import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline; import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; -import org.eclipse.pde.api.tools.ui.internal.ApiToolsLabelProvider; import org.eclipse.pde.api.tools.ui.internal.ApiUIPlugin; import org.eclipse.pde.api.tools.ui.internal.IApiToolsConstants; -import org.eclipse.pde.api.tools.ui.internal.IApiToolsHelpContextIds; -import org.eclipse.pde.api.tools.ui.internal.SWTFactory; import org.eclipse.pde.api.tools.ui.internal.preferences.ApiBaselinePreferencePage; -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.layout.GridData; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.DirectoryDialog; -import org.eclipse.swt.widgets.Text; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.ui.PlatformUI; -/** - * The wizard page allowing a new API profiles to be created or an existing one - * to be edited - * - * @since 1.0.0 - */ -public class ApiBaselineWizardPage extends WizardPage { +public abstract class ApiBaselineWizardPage extends WizardPage { /** * an EE entry (child of an api component in the viewer) @@ -174,45 +136,6 @@ public class ApiBaselineWizardPage extends WizardPage { } /** - * Resets the baseline contents based on current settings and a location - * from which to read plug-ins. - */ - class ReloadOperation implements IRunnableWithProgress { - private String location, name; - - /** - * Constructor - * - * @param platformPath - */ - public ReloadOperation(String name, String location) { - this.location = location; - this.name = name; - } - - /* - * (non-Javadoc) - * @see - * org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse - * .core.runtime.IProgressMonitor) - */ - @Override - public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - monitor.beginTask(WizardMessages.ApiProfileWizardPage_0, 10); - try { - fProfile = ApiModelFactory.newApiBaseline(name, location); - ApiModelFactory.addComponents(fProfile, location, monitor); - ApiBaselineWizardPage.this.contentchange = true; - } catch (CoreException e) { - ApiPlugin.log(e); - } finally { - monitor.done(); - } - } - - } - - /** * Operation that creates a new working copy for an {@link IApiProfile} that * is being edited */ @@ -272,33 +195,13 @@ public class ApiBaselineWizardPage extends WizardPage { IApiBaseline fProfile = null; private String originalname = null; + /** * Flag to know if the baselines' content has actually changed, or just some * other attribute https://bugs.eclipse.org/bugs/show_bug.cgi?id=267875 */ boolean contentchange = false; - /** - * We need to know if we are initializing the page to not respond to changed - * events causing validation when the wizard opens. - * - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=266597 - */ - private boolean initializing = false; - - /** - * widgets - */ - private Text nametext = null; - private TreeViewer treeviewer = null; - Combo locationcombo = null; - private Button browsebutton = null, reloadbutton = null; - - /** - * Constructor - * - * @param profile - */ protected ApiBaselineWizardPage(IApiBaseline profile) { super(WizardMessages.ApiProfileWizardPage_1); this.fProfile = profile; @@ -306,257 +209,38 @@ public class ApiBaselineWizardPage extends WizardPage { if (profile == null) { setMessage(WizardMessages.ApiProfileWizardPage_3); } else { + originalname = fProfile.getName(); setMessage(WizardMessages.ApiProfileWizardPage_4); } setImageDescriptor(ApiUIPlugin.getImageDescriptor(IApiToolsConstants.IMG_WIZBAN_PROFILE)); } - /* - * (non-Javadoc) - * @see - * org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets - * .Composite) - */ - @Override - public void createControl(Composite parent) { - Composite comp = SWTFactory.createComposite(parent, 4, 1, GridData.FILL_HORIZONTAL); - SWTFactory.createWrapLabel(comp, WizardMessages.ApiProfileWizardPage_5, 1); - nametext = SWTFactory.createText(comp, SWT.BORDER | SWT.SINGLE, 3, GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL | GridData.BEGINNING); - nametext.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - setPageComplete(pageValid()); - } - }); - - IExecutionEnvironment[] envs = JavaRuntime.getExecutionEnvironmentsManager().getExecutionEnvironments(); - ArrayList<String> items = new ArrayList<String>(); - for (int i = 0; i < envs.length; i++) { - if (envs[i].getCompatibleVMs().length > 0) { - items.add(envs[i].getId()); - } - } - Collections.sort(items, new Comparator<Object>() { - @Override - public int compare(Object o1, Object o2) { - return ((String) o1).compareTo((String) o2); - } - }); - - SWTFactory.createVerticalSpacer(comp, 1); - - SWTFactory.createWrapLabel(comp, WizardMessages.ApiProfileWizardPage_9, 1); - locationcombo = SWTFactory.createCombo(comp, SWT.BORDER | SWT.SINGLE, 1, GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL | GridData.BEGINNING, null); - locationcombo.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - setPageComplete(pageValid()); - updateButtons(); - } - }); - browsebutton = SWTFactory.createPushButton(comp, WizardMessages.ApiProfileWizardPage_10, null); - browsebutton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - DirectoryDialog dialog = new DirectoryDialog(getShell()); - dialog.setMessage(WizardMessages.ApiProfileWizardPage_11); - String loctext = locationcombo.getText().trim(); - if (loctext.length() > 0) { - dialog.setFilterPath(loctext); - } - String newPath = dialog.open(); - if (newPath != null && (!new Path(loctext).equals(new Path(newPath)) || getCurrentComponents().length == 0)) { - /* - * If the path is identical, but there is no component - * loaded, we still want to reload. This might be the case - * if the combo is initialized by copy/paste with a path - * that points to a plugin directory - */ - locationcombo.setText(newPath); - setErrorMessage(null); - doReload(); - } - } - }); - - reloadbutton = SWTFactory.createPushButton(comp, WizardMessages.ApiProfileWizardPage_12, null); - reloadbutton.setEnabled(locationcombo.getText().trim().length() > 0); - reloadbutton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - doReload(); - } - }); - - SWTFactory.createWrapLabel(comp, WizardMessages.ApiProfileWizardPage_13, 4); - Tree tree = new Tree(comp, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION); - GridData gd = new GridData(GridData.FILL_BOTH); - gd.heightHint = 250; - gd.horizontalSpan = 4; - tree.setLayoutData(gd); - treeviewer = new TreeViewer(tree); - treeviewer.setLabelProvider(new ApiToolsLabelProvider()); - treeviewer.setContentProvider(new ContentProvider()); - treeviewer.setComparator(new ViewerComparator()); - treeviewer.setInput(getCurrentComponents()); - treeviewer.addSelectionChangedListener(new ISelectionChangedListener() { - @Override - public void selectionChanged(SelectionChangedEvent event) { - updateButtons(); - } - }); - treeviewer.addFilter(new ViewerFilter() { - @Override - public boolean select(Viewer viewer, Object parentElement, Object element) { - if (element instanceof IApiComponent) { - IApiComponent component = (IApiComponent) element; - try { - if (component.isSourceComponent() || component.isSystemComponent()) { - return false; - } - } catch (CoreException e) { - ApiPlugin.log(e); - } - return true; - } - return !(element instanceof SystemLibraryApiComponent); - } - }); - - setControl(comp); - setPageComplete(fProfile != null); - initialize(); - PlatformUI.getWorkbench().getHelpSystem().setHelp(comp, IApiToolsHelpContextIds.APIPROFILES_WIZARD_PAGE); - Dialog.applyDialogFont(comp); - } - /** - * Initializes the controls of the page if the profile is not - * <code>null</code> + * Hook up the widgets to the profile, if any. Subclasses should call this + * method as part of + * {@link #createControl(org.eclipse.swt.widgets.Composite)} as it makes a + * working copy of the provided profile, which could take a long time. */ protected void initialize() { - initializing = true; - try { - if (fProfile != null) { - originalname = fProfile.getName(); - WorkingCopyOperation op = new WorkingCopyOperation(fProfile); - try { - getContainer().run(false, false, op); - } catch (InvocationTargetException e) { - ApiUIPlugin.log(e); - } catch (InterruptedException e) { - ApiUIPlugin.log(e); - } - fProfile = op.getWorkingCopy(); - nametext.setText(fProfile.getName()); - IApiComponent[] components = fProfile.getApiComponents(); - HashSet<String> locations = new HashSet<String>(); - String loc = fProfile.getLocation(); - IPath location = null; - if (loc != null) { - location = new Path(loc); - // check if the location is a file - if (location.toFile().isDirectory()) { - locations.add(location.removeTrailingSeparator().toOSString()); - } - } else { - for (int i = 0; i < components.length; i++) { - if (!components[i].isSystemComponent()) { - location = new Path(components[i].getLocation()).removeLastSegments(1); - if (location.toFile().isDirectory()) { - locations.add(location.removeTrailingSeparator().toOSString()); - } - } - } - } - if (locations.size() > 0) { - locationcombo.setItems(locations.toArray(new String[locations.size()])); - locationcombo.select(0); - } - } else { - // try to set the default location to be the current install - // directory - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=258969 - Location location = Platform.getInstallLocation(); - if (location != null) { - URL url = location.getURL(); - IPath path = new Path(url.getFile()).removeTrailingSeparator(); - if (path.toFile().exists()) { - locationcombo.add(path.toOSString()); - locationcombo.select(0); - } - } - } - } finally { - initializing = false; + if (fProfile == null) { + return; } - } - - /** - * Reloads all of the plugins from the location specified in the location - * text field. - */ - protected void doReload() { - ReloadOperation op = new ReloadOperation(nametext.getText().trim(), locationcombo.getText().trim()); + WorkingCopyOperation op = new WorkingCopyOperation(fProfile); try { - getContainer().run(true, true, op); - treeviewer.setInput(getCurrentComponents()); - treeviewer.refresh(); - setPageComplete(pageValid()); - } catch (InvocationTargetException ite) { - } catch (InterruptedException ie) { - } - } - - /** - * @return if the page is valid, such that it is considered complete and can - * be 'finished' - */ - protected boolean pageValid() { - if (initializing) { - return false; - } - setErrorMessage(null); - if (!isNameValid(nametext.getText().trim())) { - return false; - } - String text = locationcombo.getText().trim(); - if (text.length() < 1) { - setErrorMessage(WizardMessages.ApiProfileWizardPage_23); - reloadbutton.setEnabled(false); - return false; + getContainer().run(true, false, op); + } catch (InvocationTargetException e) { + ApiUIPlugin.log(e); + } catch (InterruptedException e) { + ApiUIPlugin.log(e); } - if (!new Path(text).toFile().exists()) { - setErrorMessage(WizardMessages.ApiProfileWizardPage_24); - reloadbutton.setEnabled(false); - return false; - } - if (fProfile != null) { - if (fProfile.getApiComponents().length == 0) { - setErrorMessage(WizardMessages.ApiProfileWizardPage_2); - return false; - } - IStatus status = fProfile.getExecutionEnvironmentStatus(); - if (status.getSeverity() == IStatus.ERROR) { - setErrorMessage(status.getMessage()); - return false; - } - if (!fProfile.getLocation().equals(locationcombo.getText())) { - setErrorMessage(WizardMessages.ApiProfileWizardPage_location_needs_reset); - return false; - } - } else { - setErrorMessage(WizardMessages.ApiProfileWizardPage_location_needs_reset); - return false; - } - return true; + fProfile = op.getWorkingCopy(); } /** * @param name * @return */ - private boolean isNameValid(String name) { + protected boolean isNameValid(String name) { if (name.length() < 1) { setErrorMessage(WizardMessages.ApiProfileWizardPage_20); return false; @@ -588,14 +272,6 @@ public class ApiBaselineWizardPage extends WizardPage { } /** - * Updates the state of a variety of buttons on this page - */ - protected void updateButtons() { - String loctext = locationcombo.getText().trim(); - reloadbutton.setEnabled(loctext.length() > 0); - } - - /** * Creates or edits the profile and returns it * * @return a new {@link IApiProfile} or <code>null</code> if an error was @@ -603,12 +279,7 @@ public class ApiBaselineWizardPage extends WizardPage { * @throws IOException * @throws CoreException */ - public IApiBaseline finish() throws IOException, CoreException { - if (fProfile != null) { - fProfile.setName(nametext.getText().trim()); - } - return fProfile; - } + public abstract IApiBaseline finish() throws IOException, CoreException; /** * @return if the actual content of the base line has changed and not just @@ -626,4 +297,5 @@ public class ApiBaselineWizardPage extends WizardPage { fProfile.dispose(); } } + } diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/DirectoryBasedApiBaselineWizardPage.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/DirectoryBasedApiBaselineWizardPage.java new file mode 100644 index 0000000000..acc07933e1 --- /dev/null +++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/DirectoryBasedApiBaselineWizardPage.java @@ -0,0 +1,367 @@ +/******************************************************************************* + * Copyright (c) 2007, 2015 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Manumitting Technologies Inc - bug 324310 + *******************************************************************************/ +package org.eclipse.pde.api.tools.ui.internal.wizards; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.util.HashSet; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.osgi.service.datalocation.Location; +import org.eclipse.pde.api.tools.internal.model.ApiModelFactory; +import org.eclipse.pde.api.tools.internal.model.SystemLibraryApiComponent; +import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; +import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline; +import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; +import org.eclipse.pde.api.tools.ui.internal.ApiToolsLabelProvider; +import org.eclipse.pde.api.tools.ui.internal.IApiToolsHelpContextIds; +import org.eclipse.pde.api.tools.ui.internal.SWTFactory; +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.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.PlatformUI; + +/** + * The wizard page allowing a new directory-based API profiles to be created or + * an existing one to be edited. + * + * @since 1.0.0 + */ +public class DirectoryBasedApiBaselineWizardPage extends ApiBaselineWizardPage { + public static boolean isApplicable(IApiBaseline profile) { + String loc = profile.getLocation(); + return loc != null && new Path(loc).toFile().exists(); + } + + /** + * Resets the baseline contents based on current settings and a location + * from which to read plug-ins. + */ + class ReloadOperation implements IRunnableWithProgress { + private String location, name; + + /** + * Constructor + * + * @param platformPath + */ + public ReloadOperation(String name, String location) { + this.location = location; + this.name = name; + } + + /* + * (non-Javadoc) + * @see + * org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse + * .core.runtime.IProgressMonitor) + */ + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + monitor.beginTask(WizardMessages.ApiProfileWizardPage_0, 10); + try { + fProfile = ApiModelFactory.newApiBaseline(name, location); + ApiModelFactory.addComponents(fProfile, location, monitor); + DirectoryBasedApiBaselineWizardPage.this.contentchange = true; + } catch (CoreException e) { + ApiPlugin.log(e); + } finally { + monitor.done(); + } + } + + } + + + /** + * widgets + */ + private Text nametext = null; + private TreeViewer treeviewer = null; + Combo locationcombo = null; + private Button browsebutton = null, reloadbutton = null; + + /** + * We need to know if we are initializing the page to not respond to changed + * events causing validation when the wizard opens. + * + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=266597 + */ + private boolean initializing = false; + + /** + * Constructor + * + * @param profile + */ + protected DirectoryBasedApiBaselineWizardPage(IApiBaseline profile) { + super(profile); + } + + /* + * (non-Javadoc) + * @see + * org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets + * .Composite) + */ + @Override + public void createControl(Composite parent) { + Composite comp = SWTFactory.createComposite(parent, 4, 1, GridData.FILL_HORIZONTAL); + SWTFactory.createWrapLabel(comp, WizardMessages.ApiProfileWizardPage_5, 1); + nametext = SWTFactory.createText(comp, SWT.BORDER | SWT.SINGLE, 3, GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL | GridData.BEGINNING); + nametext.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + setPageComplete(pageValid()); + } + }); + + SWTFactory.createVerticalSpacer(comp, 1); + + SWTFactory.createWrapLabel(comp, WizardMessages.ApiProfileWizardPage_9, 1); + locationcombo = SWTFactory.createCombo(comp, SWT.BORDER | SWT.SINGLE, 1, GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL | GridData.BEGINNING, null); + locationcombo.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + setPageComplete(pageValid()); + updateButtons(); + } + }); + browsebutton = SWTFactory.createPushButton(comp, WizardMessages.ApiProfileWizardPage_10, null); + browsebutton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + DirectoryDialog dialog = new DirectoryDialog(getShell()); + dialog.setMessage(WizardMessages.ApiProfileWizardPage_11); + String loctext = locationcombo.getText().trim(); + if (loctext.length() > 0) { + dialog.setFilterPath(loctext); + } + String newPath = dialog.open(); + if (newPath != null && (!new Path(loctext).equals(new Path(newPath)) || getCurrentComponents().length == 0)) { + /* + * If the path is identical, but there is no component + * loaded, we still want to reload. This might be the case + * if the combo is initialized by copy/paste with a path + * that points to a plugin directory + */ + locationcombo.setText(newPath); + setErrorMessage(null); + doReload(); + } + } + }); + + reloadbutton = SWTFactory.createPushButton(comp, WizardMessages.ApiProfileWizardPage_12, null); + reloadbutton.setEnabled(locationcombo.getText().trim().length() > 0); + reloadbutton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + doReload(); + } + }); + + SWTFactory.createWrapLabel(comp, WizardMessages.ApiProfileWizardPage_13, 4); + Tree tree = new Tree(comp, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION); + GridData gd = new GridData(GridData.FILL_BOTH); + gd.heightHint = 250; + gd.horizontalSpan = 4; + tree.setLayoutData(gd); + treeviewer = new TreeViewer(tree); + treeviewer.setLabelProvider(new ApiToolsLabelProvider()); + treeviewer.setContentProvider(new ContentProvider()); + treeviewer.setComparator(new ViewerComparator()); + treeviewer.setInput(getCurrentComponents()); + treeviewer.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + updateButtons(); + } + }); + treeviewer.addFilter(new ViewerFilter() { + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) { + if (element instanceof IApiComponent) { + IApiComponent component = (IApiComponent) element; + try { + if (component.isSourceComponent() || component.isSystemComponent()) { + return false; + } + } catch (CoreException e) { + ApiPlugin.log(e); + } + return true; + } + return !(element instanceof SystemLibraryApiComponent); + } + }); + + setControl(comp); + setPageComplete(fProfile != null); + initialize(); + PlatformUI.getWorkbench().getHelpSystem().setHelp(comp, IApiToolsHelpContextIds.APIPROFILES_WIZARD_PAGE); + Dialog.applyDialogFont(comp); + } + + /** + * Initializes the controls of the page if the profile is not + * <code>null</code> + */ + protected void initialize() { + initializing = true; + try { + super.initialize(); + if (fProfile != null) { + nametext.setText(fProfile.getName()); + IApiComponent[] components = fProfile.getApiComponents(); + HashSet<String> locations = new HashSet<String>(); + String loc = fProfile.getLocation(); + IPath location = null; + if (loc != null) { + location = new Path(loc); + // check if the location is a file + if (location.toFile().isDirectory()) { + locations.add(location.removeTrailingSeparator().toOSString()); + } + } else { + for (int i = 0; i < components.length; i++) { + if (!components[i].isSystemComponent()) { + location = new Path(components[i].getLocation()).removeLastSegments(1); + if (location.toFile().isDirectory()) { + locations.add(location.removeTrailingSeparator().toOSString()); + } + } + } + } + if (locations.size() > 0) { + locationcombo.setItems(locations.toArray(new String[locations.size()])); + locationcombo.select(0); + } + } else { + // try to set the default location to be the current install + // directory + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=258969 + Location location = Platform.getInstallLocation(); + if (location != null) { + URL url = location.getURL(); + IPath path = new Path(url.getFile()).removeTrailingSeparator(); + if (path.toFile().exists()) { + locationcombo.add(path.toOSString()); + locationcombo.select(0); + } + } + } + } finally { + initializing = false; + } + } + + /** + * Reloads all of the plugins from the location specified in the location + * text field. + */ + protected void doReload() { + IRunnableWithProgress op = new ReloadOperation(nametext.getText().trim(), locationcombo.getText().trim()); + try { + getContainer().run(true, true, op); + treeviewer.setInput(getCurrentComponents()); + treeviewer.refresh(); + setPageComplete(pageValid()); + } catch (InvocationTargetException ite) { + } catch (InterruptedException ie) { + } + } + + @Override + public IApiBaseline finish() throws IOException, CoreException { + if (fProfile != null) { + fProfile.setName(nametext.getText().trim()); + } + return fProfile; + } + + /** + * @return if the page is valid, such that it is considered complete and can + * be 'finished' + */ + protected boolean pageValid() { + if (initializing) { + return false; + } + setErrorMessage(null); + if (!isNameValid(nametext.getText().trim())) { + return false; + } + String text = locationcombo.getText().trim(); + if (text.length() < 1) { + setErrorMessage(WizardMessages.ApiProfileWizardPage_23); + reloadbutton.setEnabled(false); + return false; + } + if (!new Path(text).toFile().exists()) { + setErrorMessage(WizardMessages.ApiProfileWizardPage_24); + reloadbutton.setEnabled(false); + return false; + } + if (fProfile != null) { + if (fProfile.getApiComponents().length == 0) { + setErrorMessage(WizardMessages.ApiProfileWizardPage_2); + return false; + } + IStatus status = fProfile.getExecutionEnvironmentStatus(); + if (status.getSeverity() == IStatus.ERROR) { + setErrorMessage(status.getMessage()); + return false; + } + if (fProfile.getLocation() != null && !fProfile.getLocation().equals(locationcombo.getText())) { + setErrorMessage(WizardMessages.ApiProfileWizardPage_location_needs_reset); + return false; + } + } else { + setErrorMessage(WizardMessages.ApiProfileWizardPage_location_needs_reset); + return false; + } + return true; + } + + /** + * Updates the state of a variety of buttons on this page + */ + protected void updateButtons() { + String loctext = locationcombo.getText().trim(); + reloadbutton.setEnabled(loctext.length() > 0); + } + +} diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/SelectApiBaselineTypeWizardPage.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/SelectApiBaselineTypeWizardPage.java new file mode 100644 index 0000000000..8d826e0b23 --- /dev/null +++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/SelectApiBaselineTypeWizardPage.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2015 Manumitting Technologies Inc 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: + * Manumitting Technologies Inc - initial API and implementation + *******************************************************************************/ +package org.eclipse.pde.api.tools.ui.internal.wizards; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.wizard.IWizardPage; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.pde.api.tools.ui.internal.ApiUIPlugin; +import org.eclipse.pde.api.tools.ui.internal.IApiToolsConstants; +import org.eclipse.pde.api.tools.ui.internal.IApiToolsHelpContextIds; +import org.eclipse.pde.api.tools.ui.internal.SWTFactory; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.PlatformUI; + +public class SelectApiBaselineTypeWizardPage extends WizardPage { + + protected SelectApiBaselineTypeWizardPage() { + super(WizardMessages.ApiProfileWizardPage_1); + setTitle(WizardMessages.ApiProfileWizardPage_1); + setMessage(WizardMessages.ApiProfileWizardPage_3); + setImageDescriptor(ApiUIPlugin.getImageDescriptor(IApiToolsConstants.IMG_WIZBAN_PROFILE)); + } + + private Button locationIsDirectory; + private Button locationIsTarget; + + @Override + public void createControl(Composite parent) { + Composite comp = SWTFactory.createComposite(parent, 1, 1, GridData.FILL_HORIZONTAL); + setControl(comp); + + SWTFactory.createWrapLabel(comp, WizardMessages.SelectApiBaselineTypeWizardPage_select_baseline_source, 1); + locationIsDirectory = SWTFactory.createRadioButton(comp, WizardMessages.SelectApiBaselineTypeWizardPage_source_installation_directory); + locationIsTarget = SWTFactory.createRadioButton(comp, WizardMessages.SelectApiBaselineTypeWizardPage_source_target_platform); + locationIsDirectory.setSelection(true); + + SelectionListener typeListener = new SelectionListener() { + @Override + public void widgetSelected(SelectionEvent e) { + update(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + }; + MouseListener mouseClickListener = new MouseAdapter() { + @Override + public void mouseDoubleClick(MouseEvent e) { + update(); + getContainer().showPage(getNextPage()); + } + }; + locationIsTarget.addSelectionListener(typeListener); + locationIsTarget.addMouseListener(mouseClickListener); + locationIsDirectory.addSelectionListener(typeListener); + locationIsDirectory.addMouseListener(mouseClickListener); + + update(); + PlatformUI.getWorkbench().getHelpSystem().setHelp(comp, IApiToolsHelpContextIds.APIPROFILES_WIZARD_PAGE); + Dialog.applyDialogFont(comp); + } + + @Override + public boolean canFlipToNextPage() { + return locationIsTarget.getSelection() || locationIsDirectory.getSelection(); + } + + @Override + public IWizardPage getNextPage() { + IWizardPage next = null; + if (locationIsTarget.getSelection()) { + next = new TargetBasedApiBaselineWizardPage(null); + } else if (locationIsDirectory.getSelection()) { + next = new DirectoryBasedApiBaselineWizardPage(null); + } + ((Wizard) getWizard()).addPage(next); + return next; + } + + private void update() { + setPageComplete(canFlipToNextPage()); + } +} diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/TargetBasedApiBaselineWizardPage.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/TargetBasedApiBaselineWizardPage.java new file mode 100644 index 0000000000..ae09958b7e --- /dev/null +++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/TargetBasedApiBaselineWizardPage.java @@ -0,0 +1,397 @@ +/******************************************************************************* + * Copyright (c) 2007, 2015 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Manumitting Technologies Inc - bug 324310 + *******************************************************************************/ +package org.eclipse.pde.api.tools.ui.internal.wizards; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StyledCellLabelProvider; +import org.eclipse.jface.viewers.StyledString; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.pde.api.tools.internal.model.ApiModelFactory; +import org.eclipse.pde.api.tools.internal.model.SystemLibraryApiComponent; +import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; +import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline; +import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; +import org.eclipse.pde.api.tools.ui.internal.ApiToolsLabelProvider; +import org.eclipse.pde.api.tools.ui.internal.IApiToolsHelpContextIds; +import org.eclipse.pde.api.tools.ui.internal.SWTFactory; +import org.eclipse.pde.core.target.ITargetDefinition; +import org.eclipse.pde.core.target.ITargetHandle; +import org.eclipse.pde.core.target.ITargetPlatformService; +import org.eclipse.pde.internal.core.PDECore; +import org.eclipse.pde.internal.core.target.ExternalFileTargetHandle; +import org.eclipse.pde.internal.core.target.WorkspaceFileTargetHandle; +import org.eclipse.pde.internal.ui.PDELabelProvider; +import org.eclipse.pde.internal.ui.PDEPlugin; +import org.eclipse.pde.internal.ui.PDEPluginImages; +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.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.PlatformUI; + +/** + * Define a baseline from a Target Definition + * + * @since 1.0.600 + */ +public class TargetBasedApiBaselineWizardPage extends ApiBaselineWizardPage { + public static boolean isApplicable(IApiBaseline profile) { + return ApiModelFactory.isDerivedFromTarget(profile); + } + + /** + * Resets the baseline contents based on current settings and a target + * definition from which to read plug-ins. + */ + class ReloadTargetOperation implements IRunnableWithProgress { + private ITargetDefinition definition; + private String name; + + /** + * Constructor + * + * @param platformPath + */ + public ReloadTargetOperation(ITargetDefinition definition, String name) { + this.definition = definition; + this.name = name; + } + + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + try { + fProfile = ApiModelFactory.newApiBaselineFromTarget(name, definition, monitor); + TargetBasedApiBaselineWizardPage.this.contentchange = true; + } catch (CoreException e) { + // error reported via the definition's status in pageValid() + ApiPlugin.log(e); + } + } + } + + private static class TargetLabelProvider extends StyledCellLabelProvider { + private PDELabelProvider pdeLabelProvider = PDEPlugin.getDefault().getLabelProvider(); + + public TargetLabelProvider() { + pdeLabelProvider.connect(this); + } + + @Override + public void update(ViewerCell cell) { + final Object element = cell.getElement(); + + ITargetDefinition targetDef = (ITargetDefinition) element; + ITargetHandle targetHandle = targetDef.getHandle(); + String name = targetDef.getName(); + if (name == null || name.length() == 0) { + name = targetHandle.toString(); + } + + StyledString styledString = new StyledString(name); + if (targetHandle instanceof WorkspaceFileTargetHandle) { + IFile file = ((WorkspaceFileTargetHandle) targetHandle).getTargetFile(); + String location = " - " + file.getFullPath(); //$NON-NLS-1$ + styledString.append(location, StyledString.DECORATIONS_STYLER); + } else if (targetHandle instanceof ExternalFileTargetHandle) { + URI uri = ((ExternalFileTargetHandle) targetHandle).getLocation(); + String location = " - " + uri.toASCIIString(); //$NON-NLS-1$ + styledString.append(location, StyledString.DECORATIONS_STYLER); + } + + cell.setText(styledString.toString()); + cell.setStyleRanges(styledString.getStyleRanges()); + cell.setImage(getImage(targetDef)); + super.update(cell); + } + + public Image getImage(Object e) { + return pdeLabelProvider.get(PDEPluginImages.DESC_TARGET_DEFINITION); + } + + @Override + public void dispose() { + pdeLabelProvider.disconnect(this); + super.dispose(); + } + } + + /** + * Initial collection of targets (handles are realized into definitions as + * working copies) + */ + private List<ITargetDefinition> fTargets = new ArrayList<ITargetDefinition>(); + + private ITargetDefinition selectedTargetDefinition; + + /** + * widgets + */ + private Text nametext = null; + private CheckboxTableViewer targetsViewer; + private TreeViewer treeviewer = null; + private Button reloadbutton = null; + + public TargetBasedApiBaselineWizardPage(IApiBaseline profile) { + super(profile); + } + + @Override + public void createControl(Composite parent) { + Composite comp = SWTFactory.createComposite(parent, 4, 1, GridData.FILL_HORIZONTAL); + SWTFactory.createWrapLabel(comp, WizardMessages.ApiProfileWizardPage_5, 1); + nametext = SWTFactory.createText(comp, SWT.BORDER | SWT.SINGLE, 3, GridData.FILL_HORIZONTAL | GridData.BEGINNING); + nametext.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + setPageComplete(pageValid()); + } + }); + + SWTFactory.createVerticalSpacer(comp, 1); + targetsViewer = CheckboxTableViewer.newCheckList(comp, SWT.MULTI | SWT.BORDER); + GridDataFactory.fillDefaults().span(3, 1).grab(true, true).applyTo(targetsViewer.getControl()); + + targetsViewer.setLabelProvider(new TargetLabelProvider()); + targetsViewer.setContentProvider(ArrayContentProvider.getInstance()); + targetsViewer.addCheckStateListener(new ICheckStateListener() { + @Override + public void checkStateChanged(CheckStateChangedEvent event) { + if (event.getChecked()) { + targetsViewer.setCheckedElements(new Object[] { + event.getElement() }); + selectedTargetDefinition = (ITargetDefinition) event.getElement(); + } else { + selectedTargetDefinition = null; + } + updateButtons(); + setPageComplete(pageValid()); + } + }); + + // add the targets + ITargetPlatformService service = getTargetService(); + if (service != null) { + for (ITargetHandle handle : service.getTargets(null)) { + try { + fTargets.add(handle.getTargetDefinition()); + } catch (CoreException e) { + PDECore.log(e); + } + } + if (fTargets.isEmpty()) { + // Ensure we have at least a default TP + try { + fTargets.add(service.getWorkspaceTargetDefinition()); + } catch (CoreException e) { + PDECore.log(e); + } + } + targetsViewer.setInput(fTargets); + } + + targetsViewer.setComparator(new ViewerComparator() { + @Override + public int compare(Viewer viewer, Object e1, Object e2) { + String name1 = ((ITargetDefinition) e1).getName(); + String name2 = ((ITargetDefinition) e2).getName(); + if (name1 == null) { + return -1; + } + if (name2 == null) { + return 1; + } + return name1.compareToIgnoreCase(name2); + } + }); + + reloadbutton = SWTFactory.createPushButton(comp, WizardMessages.ApiProfileWizardPage_12, null); + reloadbutton.setEnabled(targetsViewer.getCheckedElements().length == 1); + reloadbutton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + doReload(); + } + }); + + SWTFactory.createWrapLabel(comp, WizardMessages.ApiProfileWizardPage_13, 4); + Tree tree = new Tree(comp, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION); + GridData gd = new GridData(GridData.FILL_BOTH); + gd.heightHint = 100; + gd.horizontalSpan = 4; + tree.setLayoutData(gd); + treeviewer = new TreeViewer(tree); + treeviewer.setLabelProvider(new ApiToolsLabelProvider()); + treeviewer.setContentProvider(new ContentProvider()); + treeviewer.setComparator(new ViewerComparator()); + treeviewer.setInput(getCurrentComponents()); + treeviewer.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + updateButtons(); + } + }); + treeviewer.addFilter(new ViewerFilter() { + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) { + if (element instanceof IApiComponent) { + IApiComponent component = (IApiComponent) element; + try { + if (component.isSourceComponent() || component.isSystemComponent()) { + return false; + } + } catch (CoreException e) { + ApiPlugin.log(e); + } + return true; + } + return !(element instanceof SystemLibraryApiComponent); + } + }); + + setControl(comp); + if (fProfile != null) { + nametext.setText(fProfile.getName()); + + ITargetDefinition found = null; + // Use isDerivedFromTarget as the target may have had its + // sequence number bumped several times + for (ITargetDefinition target : fTargets) { + if (ApiModelFactory.isDerivedFromTarget(fProfile, target)) { + found = target; + break; + } + } + if (found != null) { + selectedTargetDefinition = found; + targetsViewer.setCheckedElements(new Object[] { found }); + } + } + initialize(); + updateButtons(); + setPageComplete(pageValid()); + PlatformUI.getWorkbench().getHelpSystem().setHelp(comp, IApiToolsHelpContextIds.APIPROFILES_WIZARD_PAGE); + Dialog.applyDialogFont(comp); + } + + /** + * @return if the page is valid, such that it is considered complete and can + * be 'finished' + */ + protected boolean pageValid() { + setErrorMessage(null); + // If a target is selected then report any resolving problems before + // any missing-name errors. It's strange to click on 'reset' and see + // the progress bar and having any resolving errors masked by a + // missing-name or no-bundles-error + ITargetDefinition selected = getSelectedTargetDefinition(); + if (selected != null && selected.getStatus() != null && !selected.getStatus().isOK()) { + setErrorMessage(WizardMessages.TargetBasedApiBaselineWizardPage_loading_error); + return false; + } + if (!isNameValid(nametext.getText().trim())) { + return false; + } + if(targetsViewer.getCheckedElements().length != 1) { + setErrorMessage(WizardMessages.ApiProfileWizardPage_select_target); + reloadbutton.setEnabled(false); + return false; + } + if (fProfile != null) { + if (fProfile.getApiComponents().length == 0) { + setErrorMessage(WizardMessages.ApiProfileWizardPage_2); + return false; + } + IStatus status = fProfile.getExecutionEnvironmentStatus(); + if (status.getSeverity() == IStatus.ERROR) { + setErrorMessage(status.getMessage()); + return false; + } + if (!ApiModelFactory.isUpToDateWithTarget(fProfile, selected)) { + setErrorMessage(WizardMessages.ApiProfileWizardPage_location_needs_reset); + return false; + } + } else { + setErrorMessage(WizardMessages.ApiProfileWizardPage_location_needs_reset); + return false; + } + return true; + } + + private ITargetDefinition getSelectedTargetDefinition() { + // don't query the table directly as may be called from non-UI thread + return selectedTargetDefinition; + } + + /** + * Updates the state of a variety of buttons on this page + */ + protected void updateButtons() { + reloadbutton.setEnabled(getSelectedTargetDefinition() != null); + } + + @Override + public IApiBaseline finish() throws IOException, CoreException { + if (fProfile != null) { + fProfile.setName(nametext.getText().trim()); + } + return fProfile; + } + + /** + * Reloads all of the plugins from the location specified in the location + * text field. + */ + protected void doReload() { + IRunnableWithProgress op = new ReloadTargetOperation(getSelectedTargetDefinition(), nametext.getText().trim()); + try { + getContainer().run(true, true, op); + treeviewer.setInput(getCurrentComponents()); + treeviewer.refresh(); + setPageComplete(pageValid()); + } catch (InvocationTargetException ite) { + } catch (InterruptedException ie) { + } + } + + private ITargetPlatformService getTargetService() { + return (ITargetPlatformService) ApiPlugin.getDefault().acquireService(ITargetPlatformService.class.getName()); + } +} diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/WizardMessages.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/WizardMessages.java index ca7c84dd63..de01173e10 100644 --- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/WizardMessages.java +++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/WizardMessages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2013 IBM Corporation and others. + * Copyright (c) 2008, 2015 IBM Corporation 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Manumitting Technologies Inc - bug 324310 *******************************************************************************/ package org.eclipse.pde.api.tools.ui.internal.wizards; @@ -35,6 +36,7 @@ public class WizardMessages extends NLS { public static String ApiProfileWizardPage_create_working_copy; public static String ApiProfileWizardPage_location_needs_reset; public static String ApiProfileWizardPage_profile_with_that_name_exists; + public static String ApiProfileWizardPage_select_target; public static String ApiToolingSetupWizard_0; public static String ApiToolingSetupWizardPage_0; public static String ApiToolingSetupWizardPage_1; @@ -65,6 +67,10 @@ public class WizardMessages extends NLS { public static String ProjectUpdateChange_add_nature_and_builder; public static String ProjectUpdateChange_adding_nature_and_builder; public static String ProjectUpdateChange_project_not_accessible; + public static String SelectApiBaselineTypeWizardPage_select_baseline_source; + public static String SelectApiBaselineTypeWizardPage_source_installation_directory; + public static String SelectApiBaselineTypeWizardPage_source_target_platform; + public static String TargetBasedApiBaselineWizardPage_loading_error; public static String UpdateJavadocTagsWizard_0; public static String UpdateJavadocTagsWizardPage_10; public static String UpdateJavadocTagsWizardPage_11; diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/wizardmessages.properties b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/wizardmessages.properties index cedf0405b1..262ce11fc1 100644 --- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/wizardmessages.properties +++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/wizardmessages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2008, 2013 IBM Corporation and others. +# Copyright (c) 2008, 2015 IBM Corporation 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 @@ -7,6 +7,7 @@ # # Contributors: # IBM Corporation - initial API and implementation +# Manumitting Technologies Inc - bug 324310 ############################################################################### ApiProfileWizard_0=New API Baseline ApiProfileWizard_1=Edit API Baseline @@ -29,6 +30,7 @@ ApiProfileWizardPage_copy_profile_attribs=Copying baseline attributes... ApiProfileWizardPage_create_working_copy=Creating baseline working copy ApiProfileWizardPage_location_needs_reset=Press 'Reset' to scan the location for plug-ins/bundles ApiProfileWizardPage_profile_with_that_name_exists=A baseline with that name already exists +ApiProfileWizardPage_select_target=Select the target definition ApiToolingSetupWizard_0=API Tools Setup ApiToolingSetupWizardPage_0=Delete component.xml after &update is complete ApiToolingSetupWizardPage_1=No API baseline @@ -59,6 +61,10 @@ JavadocTagRefactoring_3=Javadoc Tag Refactoring ProjectUpdateChange_add_nature_and_builder=Add API nature and API analysis builder ProjectUpdateChange_adding_nature_and_builder=Adding API project nature and builder... ProjectUpdateChange_project_not_accessible=The project [{0}] is not accessible +SelectApiBaselineTypeWizardPage_select_baseline_source=Select the source for this baseline: +SelectApiBaselineTypeWizardPage_source_installation_directory=An existing Eclipse installation directory +SelectApiBaselineTypeWizardPage_source_target_platform=A target platform +TargetBasedApiBaselineWizardPage_loading_error=An error occurred when loading the selected target definition: see the error log for details UpdateJavadocTagsWizard_0=API Tools Setup UpdateJavadocTagsWizardPage_10=&Select All UpdateJavadocTagsWizardPage_11=D&eselect All diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiBaseline.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiBaseline.java index 81f7416565..548c109a5c 100644 --- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiBaseline.java +++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiBaseline.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2014 IBM Corporation and others. + * Copyright (c) 2007, 2015 IBM Corporation 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Manumitting Technologies Inc - bug 324310 *******************************************************************************/ package org.eclipse.pde.api.tools.internal.model; @@ -162,7 +163,7 @@ public class ApiBaseline extends ApiElement implements IApiBaseline, IVMInstallC * Constructs a new API baseline with the given attributes. * * @param name baseline name - * @param eeDescriptoin execution environment description file + * @param eeDescription execution environment description file * @throws CoreException if unable to create a baseline with the given * attributes */ @@ -174,7 +175,7 @@ public class ApiBaseline extends ApiElement implements IApiBaseline, IVMInstallC * Constructs a new API baseline with the given attributes. * * @param name baseline name - * @param eeDescriptoin execution environment description file + * @param eeDescription execution environment description file * @param location the given baseline location * @throws CoreException if unable to create a baseline with the given * attributes diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiModelFactory.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiModelFactory.java index 822c8f48d4..cf1948639b 100644 --- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiModelFactory.java +++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiModelFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2013 IBM Corporation and others. + * Copyright (c) 2008, 2015 IBM Corporation 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 @@ -7,19 +7,23 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Manumitting Technologies Inc - bug 324310 *******************************************************************************/ package org.eclipse.pde.api.tools.internal.model; import java.io.File; import java.io.FilenameFilter; +import java.net.URI; import java.util.ArrayList; import java.util.List; +import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.URIUtil; @@ -31,9 +35,13 @@ import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; import org.eclipse.pde.api.tools.internal.util.Util; import org.eclipse.pde.core.plugin.IPluginModelBase; import org.eclipse.pde.core.target.ITargetDefinition; +import org.eclipse.pde.core.target.ITargetHandle; import org.eclipse.pde.core.target.ITargetLocation; import org.eclipse.pde.core.target.ITargetPlatformService; import org.eclipse.pde.core.target.TargetBundle; +import org.eclipse.pde.internal.core.target.ExternalFileTargetHandle; +import org.eclipse.pde.internal.core.target.TargetDefinition; +import org.eclipse.pde.internal.core.target.WorkspaceFileTargetHandle; /** * Utility class for creating new @@ -48,6 +56,13 @@ public class ApiModelFactory { public static final IApiComponent[] NO_COMPONENTS = new IApiComponent[0]; /** + * Prefix for API baseline locations indicates the baseline was derived from + * a target definition. These locations must be compatible with + * {@link Path#fromPortableString(String)}. + */ + private static final String TARGET_PREFIX = "target:"; //$NON-NLS-1$ + + /** * {@link FilenameFilter} for CVS files * * @since 1.0.1 @@ -302,4 +317,126 @@ public class ApiModelFactory { subMonitor.done(); } } + + public static IApiBaseline newApiBaselineFromTarget(String name, ITargetDefinition definition, IProgressMonitor monitor) throws CoreException { + IApiBaseline baseline = new ApiBaseline(name); + + SubMonitor subMonitor = SubMonitor.convert(monitor, Messages.configuring_baseline, 50); + try { + IStatus result = definition.resolve(subMonitor.newChild(30)); + if (!result.isOK()) { + throw new CoreException(result); + } + Util.updateMonitor(subMonitor, 1); + TargetBundle[] bundles = definition.getBundles(); + List<IApiComponent> components = new ArrayList<IApiComponent>(); + if (bundles.length > 0) { + subMonitor.setWorkRemaining(bundles.length); + for (int i = 0; i < bundles.length; i++) { + Util.updateMonitor(subMonitor, 1); + if (!bundles[i].isSourceBundle()) { + IApiComponent component = ApiModelFactory.newApiComponent(baseline, URIUtil.toFile(bundles[i].getBundleInfo().getLocation()).getAbsolutePath()); + if (component != null) { + subMonitor.subTask(NLS.bind(Messages.adding_component__0, component.getSymbolicName())); + components.add(component); + } + } + } + } + baseline.addApiComponents(components.toArray(new IApiComponent[components.size()])); + baseline.setLocation(generateTargetLocation(definition)); + return baseline; + } finally { + subMonitor.done(); + } + } + + /** + * Create predictable location description for a target definition. Form is + * <code>target:/targetSeq/definitionLocation</code>. A location must be + * compatible with + * {@link org.eclipse.core.runtime.Path#fromPortableString(String)}. + * + * @param definition the target platform definition + * @return an encoded location + * @see #isDerivedFromTarget + * @see #getDefinitionIdentifier + */ + private static String generateTargetLocation(ITargetDefinition definition) { + StringBuilder sb = new StringBuilder(TARGET_PREFIX); + sb.append(IPath.SEPARATOR); + if (definition instanceof TargetDefinition) { + sb.append(((TargetDefinition) definition).getSequenceNumber()); + } + sb.append(IPath.SEPARATOR); + sb.append(getDefinitionIdentifier(definition)); + return sb.toString(); + } + + /** + * Return a stable identifier for the provided definition. + * + * @param definition + * @return a stable identifier, in portable OS format as per + * {@link org.eclipse.core.runtime.Path#fromPortableString(String)}. + */ + private static String getDefinitionIdentifier(ITargetDefinition definition) { + ITargetHandle targetHandle = definition.getHandle(); + // It would be nicer if ITargetHandle had #getURI() or something + String location; + if (targetHandle instanceof WorkspaceFileTargetHandle) { + IFile file = ((WorkspaceFileTargetHandle) targetHandle).getTargetFile(); + location = file.getFullPath().toPortableString(); + } else if (targetHandle instanceof ExternalFileTargetHandle) { + URI uri = ((ExternalFileTargetHandle) targetHandle).getLocation(); + location = uri.toASCIIString(); + } else { + // LocalTargetHandle#toString() returns file name, + // and hope any other impls do the same + location = targetHandle.toString(); + } + return location.replace(':', IPath.SEPARATOR); + } + + /** + * Return true if the provided profile seems to have been derived from the + * given target definition. The target definition may have evolved since + * originally created. + * + * @param profile the API profile + * @param definition the target definition + * @return true if the profile was derived from the given definition + */ + public static boolean isDerivedFromTarget(IApiBaseline profile, ITargetDefinition definition) { + // strip off the scheme and sequence number and compare + String location = profile.getLocation(); + // location should be minimally "target://X" for some identifier X + if (location == null || !location.startsWith(TARGET_PREFIX) || location.length() <= TARGET_PREFIX.length() + 3 || location.charAt(TARGET_PREFIX.length()) != IPath.SEPARATOR) { + return false; + } + // 2 = ':/' + int seqEnd = location.indexOf(IPath.SEPARATOR, TARGET_PREFIX.length() + 2); + String targetIdentifier = location.substring(seqEnd + 1); + return targetIdentifier.equals(getDefinitionIdentifier(definition)); + } + + /** + * Return true if the provided profile was derived from a target definition. + */ + public static boolean isDerivedFromTarget(IApiBaseline profile) { + return profile.getLocation() != null && profile.getLocation().startsWith(ApiModelFactory.TARGET_PREFIX); + } + + /** + * Return true if the provided profile is up-to-date with the given target + * definition + * + * @param profile the API profile + * @param definition the target definition + * @return true if the profile is up-to-date + */ + public static boolean isUpToDateWithTarget(IApiBaseline profile, ITargetDefinition definition) { + // The target's sequence number, if any, is generated into the location + return profile.getLocation() != null && profile.getLocation().equals(generateTargetLocation(definition)); + } }
\ No newline at end of file diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java index 182539cf6e..3467a56e70 100644 --- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java +++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java @@ -857,7 +857,7 @@ public class TargetDefinition implements ITargetDefinition { buf.append("\n\tNo containers"); //$NON-NLS-1$ } else { for (int i = 0; i < fContainers.length; i++) { - buf.append("\n\t").append(fContainers.toString()); //$NON-NLS-1$ + buf.append("\n\t").append(fContainers[i].toString()); //$NON-NLS-1$ } } buf.append("\nEnv: ").append(fOS).append("/").append(fWS).append("/").append(fArch).append("/").append(fNL); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |