NEW - bug 256910: target platform: the next wave
https://bugs.eclipse.org/bugs/show_bug.cgi?id=256910
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PluginModelManager.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PluginModelManager.java
index fc11bf5..878f8e9 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PluginModelManager.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PluginModelManager.java
@@ -14,14 +14,15 @@
 import java.util.*;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.*;
 import org.eclipse.jdt.core.*;
 import org.eclipse.osgi.service.resolver.*;
 import org.eclipse.pde.core.*;
 import org.eclipse.pde.core.build.IBuild;
 import org.eclipse.pde.core.build.IBuildEntry;
 import org.eclipse.pde.core.plugin.*;
+import org.eclipse.pde.internal.core.target.impl.*;
+import org.eclipse.pde.internal.core.target.provisional.*;
 
 public class PluginModelManager implements IModelProviderListener {
 
@@ -420,6 +421,64 @@
 		}
 
 		fEntries = entries;
+
+		// Create default target platform definition if required
+		initDefaultTargetPlatformDefinition();
+	}
+
+	/**
+	 * Creates initial target platform definition in local metadata if not already created.
+	 */
+	private synchronized void initDefaultTargetPlatformDefinition() {
+		ITargetPlatformService service = (ITargetPlatformService) PDECore.getDefault().acquireService(ITargetPlatformService.class.getName());
+		if (service != null) {
+			String memento = PDECore.getDefault().getPluginPreferences().getString(ICoreConstants.WORKSPACE_TARGET_HANDLE);
+			if (memento.equals("")) { //$NON-NLS-1$
+				// no workspace target handle set, check for local targets
+				ITargetHandle[] targets = service.getTargets(null);
+				boolean local = false;
+				for (int i = 0; i < targets.length; i++) {
+					if (targets[i] instanceof LocalTargetHandle) {
+						local = true;
+						break;
+					}
+				}
+				if (!local) {
+					// no local targets, no workspace preference > create default target platform
+					ITargetDefinition def = null;
+					TargetPlatformService ts = (TargetPlatformService) service;
+					ITargetDefinition host = ts.newDefaultTargetDefinition();
+					try {
+						service.saveTargetDefinition(host);
+					} catch (CoreException e) {
+						PDECore.log(e);
+					}
+					// create target platform from current workspace settings
+					TargetDefinition curr = (TargetDefinition) ts.newTarget();
+					try {
+						ts.loadTargetDefinitionFromPreferences(curr);
+						if (curr.isContentEquivalent(host)) {
+							// current settings are the same as the default target platform
+							def = host;
+						} else {
+							// current settings are different than default
+							service.saveTargetDefinition(curr);
+							def = curr;
+						}
+					} catch (CoreException e) {
+						PDECore.log(e);
+					}
+					if (def != null) {
+						Preferences preferences = PDECore.getDefault().getPluginPreferences();
+						try {
+							preferences.setValue(ICoreConstants.WORKSPACE_TARGET_HANDLE, def.getHandle().getMemento());
+						} catch (CoreException e) {
+							PDECore.log(e);
+						}
+					}
+				}
+			}
+		}
 	}
 
 	/**
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/AbstractBundleContainer.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/AbstractBundleContainer.java
index 2710eb4..c10690c 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/AbstractBundleContainer.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/AbstractBundleContainer.java
@@ -68,8 +68,7 @@
 	 */

 	public final BundleInfo[] resolveSourceBundles(IProgressMonitor monitor) throws CoreException {

 		BundleInfo[] all = resolveAllSourceBundles(monitor);

-		// for now, don't restrict source bundles

-		return all;

+		return getMatchingBundles(all, getIncludedBundles());

 	}

 

 	/**

diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/TargetDefinition.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/TargetDefinition.java
index ce6362c..d240431 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/TargetDefinition.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/TargetDefinition.java
@@ -160,6 +160,9 @@
 	 * @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setProgramArguments(java.lang.String)

 	 */

 	public void setProgramArguments(String args) {

+		if (args != null && args.length() == 0) {

+			args = null;

+		}

 		fProgramArgs = args;

 	}

 

@@ -167,6 +170,9 @@
 	 * @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setVMArguments(java.lang.String)

 	 */

 	public void setVMArguments(String args) {

+		if (args != null && args.length() == 0) {

+			args = null;

+		}

 		fVMArgs = args;

 	}

 

@@ -346,6 +352,26 @@
 		return false;

 	}

 

+	/**

+	 * Returns whether the content of this definition is equivalent to the content of the

+	 * specified definition (excluding name/description).

+	 * 

+	 * @param definition

+	 * @return whether the content of this definition is equivalent to the content of the

+	 * specified definition

+	 */

+	public boolean isContentEquivalent(ITargetDefinition definition) {

+		if (isNullOrEqual(getArch(), definition.getArch()) && isNullOrEqual(getNL(), definition.getNL()) && isNullOrEqual(getOS(), definition.getOS()) && isNullOrEqual(getWS(), definition.getWS()) && isNullOrEqual(getProgramArguments(), definition.getProgramArguments()) && isNullOrEqual(getVMArguments(), definition.getVMArguments())) {

+			// check containers and implicit dependencies

+			IBundleContainer[] c1 = getBundleContainers();

+			IBundleContainer[] c2 = definition.getBundleContainers();

+			if (areContainersEqual(c1, c2)) {

+				return areEqual(getImplicitDependencies(), definition.getImplicitDependencies());

+			}

+		}

+		return false;

+	}

+

 	private boolean areEqual(BundleInfo[] c1, BundleInfo[] c2) {

 		if (c1 == null) {

 			return c2 == null;

diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/TargetPlatformService.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/TargetPlatformService.java
index 730af8e..6606f51 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/TargetPlatformService.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/impl/TargetPlatformService.java
@@ -435,6 +435,18 @@
 		} catch (CoreException e) {

 			target.setName("Running Platform (Default)");

 		}

+		Preferences preferences = PDECore.getDefault().getPluginPreferences();

+

+		// initialize environment with default settings

+		String value = getValueOrNull(preferences.getDefaultString(ICoreConstants.ARCH));

+		target.setArch(value);

+		value = getValueOrNull(preferences.getDefaultString(ICoreConstants.OS));

+		target.setOS(value);

+		value = getValueOrNull(preferences.getDefaultString(ICoreConstants.WS));

+		target.setWS(value);

+		value = getValueOrNull(preferences.getDefaultString(ICoreConstants.NL));

+		target.setNL(value);

+

 		return target;

 	}

 }

diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/target/TargetDefinitionTests.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/target/TargetDefinitionTests.java
index 9c11301..ecb1c91 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/target/TargetDefinitionTests.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/target/TargetDefinitionTests.java
@@ -82,22 +82,6 @@
 	}	

 	

 	/**

-	 * Retrieves all *code* bundles in the given target definition

-	 * returning them as a list of BundleInfos.

-	 * 

-	 * @param target target definition

-	 * @return all BundleInfos

-	 */

-	protected List getAllCodeBundleInfos(ITargetDefinition target) throws Exception {

-		BundleInfo[] code = target.resolveBundles(null);

-		List list = new ArrayList(code.length);

-		for (int i = 0; i < code.length; i++) {

-			list.add(code[i]);

-		}

-		return list;

-	}	

-	

-	/**

 	 * Collects all bundle symbolic names into a set.

 	 * 

 	 * @param infos bundles

@@ -282,7 +266,7 @@
 		};

 		container.setIncludedBundles(restrictions);

 		definition.setBundleContainers(new IBundleContainer[]{container});

-		List infos = getAllCodeBundleInfos(definition);

+		List infos = getAllBundleInfos(definition);

 		

 		assertEquals("Wrong number of bundles", 2, infos.size());

 		Set set = collectAllSymbolicNames(infos);

@@ -304,7 +288,7 @@
 		ITargetDefinition definition = getTargetService().newTarget();

 		IBundleContainer container = getTargetService().newProfileContainer(TargetPlatform.getDefaultLocation(), null);

 		definition.setBundleContainers(new IBundleContainer[]{container});

-		List infos = getAllCodeBundleInfos(definition);

+		List infos = getAllBundleInfos(definition);

 		// find right versions

 		String v1 = null;

 		String v2 = null;

@@ -325,7 +309,7 @@
 				new BundleInfo("org.eclipse.jdt.debug", v2, null, BundleInfo.NO_LEVEL, false)

 		};

 		container.setIncludedBundles(restrictions);

-		infos = getAllCodeBundleInfos(definition);

+		infos = getAllBundleInfos(definition);

 		

 		assertEquals("Wrong number of bundles", 2, infos.size());

 		iterator = infos.iterator();

@@ -355,7 +339,7 @@
 		};

 		container.setIncludedBundles(restrictions);

 		definition.setBundleContainers(new IBundleContainer[]{container});

-		List infos = getAllCodeBundleInfos(definition);

+		List infos = getAllBundleInfos(definition);

 		

 		assertEquals("Wrong number of bundles", 0, infos.size());		

 	}	

diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/preferences/TargetPlatformPreferencePage2.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/preferences/TargetPlatformPreferencePage2.java
index eaa8822..b0de71d 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/preferences/TargetPlatformPreferencePage2.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/preferences/TargetPlatformPreferencePage2.java
@@ -10,8 +10,6 @@
  *******************************************************************************/

 package org.eclipse.pde.internal.ui.preferences;

 

-import org.eclipse.pde.internal.ui.PDEUIMessages;

-

 import java.util.*;

 import java.util.List;

 import org.eclipse.core.runtime.CoreException;

@@ -23,7 +21,9 @@
 import org.eclipse.jface.window.Window;

 import org.eclipse.jface.wizard.WizardDialog;

 import org.eclipse.pde.internal.core.PDECore;

+import org.eclipse.pde.internal.core.PluginModelManager;

 import org.eclipse.pde.internal.core.target.impl.TargetDefinition;

+import org.eclipse.pde.internal.core.target.impl.TargetPlatformService;

 import org.eclipse.pde.internal.core.target.provisional.*;

 import org.eclipse.pde.internal.ui.*;

 import org.eclipse.pde.internal.ui.wizards.target.EditTargetDefinitionWizard;

@@ -46,7 +46,7 @@
 

 		public String getText(Object element) {

 			String name = ((ITargetDefinition) element).getName();

-			if (name == null || name.length()==0){

+			if (name == null || name.length() == 0) {

 				return ((ITargetDefinition) element).getHandle().toString();

 			}

 			return name;

@@ -245,13 +245,37 @@
 	 * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)

 	 */

 	public void init(IWorkbench workbench) {

+		// ensures default targets are created when page is opened (if not created yet)

+		PluginModelManager manager = PDECore.getDefault().getModelManager();

+		manager.getExternalModelManager();

 	}

 

 	/* (non-Javadoc)

 	 * @see org.eclipse.jface.preference.PreferencePage#performDefaults()

 	 */

 	public void performDefaults() {

-		// TODO

+		// add a default target platform and select it (or just select it if present)

+		ITargetPlatformService service = getTargetService();

+		if (service instanceof TargetPlatformService) {

+			TargetPlatformService ts = (TargetPlatformService) service;

+			ITargetDefinition deflt = ts.newDefaultTargetDefinition();

+			Iterator iterator = fTargets.iterator();

+			ITargetDefinition reuse = null;

+			while (iterator.hasNext()) {

+				TargetDefinition existing = (TargetDefinition) iterator.next();

+				if (existing.isContentEquivalent(deflt)) {

+					reuse = existing;

+					break;

+				}

+			}

+			if (reuse != null) {

+				deflt = reuse;

+			} else {

+				fTargets.add(deflt);

+			}

+			fTableViewer.refresh();

+			fTableViewer.setCheckedElements(new Object[] {deflt});

+		}

 		super.performDefaults();

 	}

 

@@ -291,7 +315,7 @@
 				} else {

 					ITargetDefinition original = prev.getTargetDefinition();

 					// TODO: should just check for structural changes

-					if (((TargetDefinition) original).isContentEqual(currD)) {

+					if (((TargetDefinition) original).isContentEquivalent(currD)) {

 						load = false;

 					} else {

 						load = true;

diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/AddBundleContainerSelectionPage.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/AddBundleContainerSelectionPage.java
index e20edce..255d714 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/AddBundleContainerSelectionPage.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/AddBundleContainerSelectionPage.java
@@ -338,7 +338,7 @@
 									BundleInfo[] resolved = container.resolveBundles(null);
 									if (resolved.length == 0) {
 										IBundleContainer pluginContainer = getTargetPlatformService().newDirectoryContainer(new File(dirs[i], "plugins").getPath()); //$NON-NLS-1$
-										resolved = container.resolveBundles(null);
+										resolved = pluginContainer.resolveBundles(null);
 										if (resolved.length > 0) {
 											container = pluginContainer;
 										}
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/BundleContainerTable.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/BundleContainerTable.java
index e3f7d06..82d12c8 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/BundleContainerTable.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/BundleContainerTable.java
@@ -157,6 +157,7 @@
 		fTreeViewer = new TreeViewer(tree);
 		fTreeViewer.setContentProvider(new TargetContentProvider());
 		fTreeViewer.setLabelProvider(new TargetLabelProvider());
+		fTreeViewer.setComparator(new ViewerComparator());
 		fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
 			public void selectionChanged(SelectionChangedEvent event) {
 				updateButtons();
@@ -240,15 +241,20 @@
 			if (container != null) {
 				// We need to get a list of all possible bundles, remove restrictions while resolving
 				BundleInfo[] oldRestrictions = container.getIncludedBundles();
-				container.setIncludedBundles(null);
 				BundleInfo[] resolvedBundles = null;
 				try {
-					resolvedBundles = container.resolveBundles(null);
+					container.setIncludedBundles(null);
+					BundleInfo[] bundles = container.resolveBundles(new NullProgressMonitor());
+					BundleInfo[] source = container.resolveSourceBundles(new NullProgressMonitor());
+					resolvedBundles = new BundleInfo[bundles.length + source.length];
+					System.arraycopy(bundles, 0, resolvedBundles, 0, bundles.length);
+					System.arraycopy(source, 0, resolvedBundles, bundles.length, source.length);
 				} catch (CoreException e) {
 					resolvedBundles = new BundleInfo[0];
 					PDEPlugin.log(e);
+				} finally {
+					container.setIncludedBundles(oldRestrictions);
 				}
-				container.setIncludedBundles(oldRestrictions);
 
 				RestrictionsListSelectionDialog dialog = new RestrictionsListSelectionDialog(fTreeViewer.getTree().getShell(), resolvedBundles, oldRestrictions);
 				if (dialog.open() == Window.OK) {
@@ -330,7 +336,13 @@
 				return containers != null ? containers : new Object[0];
 			} else if (parentElement instanceof IBundleContainer) {
 				try {
-					return ((IBundleContainer) parentElement).resolveBundles(new NullProgressMonitor());
+					IBundleContainer container = (IBundleContainer) parentElement;
+					BundleInfo[] bundles = container.resolveBundles(new NullProgressMonitor());
+					BundleInfo[] source = container.resolveSourceBundles(new NullProgressMonitor());
+					BundleInfo[] all = new BundleInfo[bundles.length + source.length];
+					System.arraycopy(bundles, 0, all, 0, bundles.length);
+					System.arraycopy(source, 0, all, bundles.length, source.length);
+					return all;
 				} catch (CoreException e) {
 					// TODO Handle proper status
 					return new String[] {"Error getting bundle list: " + e.getMessage()};
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/BundleInfoLabelProvider.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/BundleInfoLabelProvider.java
index 6cd725d..112e38e 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/BundleInfoLabelProvider.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/BundleInfoLabelProvider.java
@@ -30,7 +30,10 @@
 			buf.append(((BundleInfo) element).getSymbolicName());
 			String version = ((BundleInfo) element).getVersion();
 			if (version != null) {
-				buf.append(' ').append(version);
+				buf.append(' ');
+				buf.append('(');
+				buf.append(version);
+				buf.append(')');
 			}
 			return buf.toString();
 		}
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/target/TargetCreationPage.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/target/TargetCreationPage.java
index a26c2f4..5a47e1d 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/target/TargetCreationPage.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/target/TargetCreationPage.java
@@ -22,7 +22,8 @@
 import org.eclipse.pde.internal.core.itarget.ITargetModel;

 import org.eclipse.pde.internal.core.target.TargetModel;

 import org.eclipse.pde.internal.core.target.impl.TargetPlatformService;

-import org.eclipse.pde.internal.core.target.provisional.*;

+import org.eclipse.pde.internal.core.target.provisional.ITargetDefinition;

+import org.eclipse.pde.internal.core.target.provisional.ITargetPlatformService;

 import org.eclipse.pde.internal.ui.PDEUIMessages;

 import org.eclipse.pde.internal.ui.SWTFactory;

 import org.eclipse.pde.internal.ui.editor.target.OpenTargetProfileAction;

@@ -170,7 +171,12 @@
 					definition.setName(PDEUIMessages.TargetCreationPage_6);

 					break;

 				case USE_DEFAULT :

-					populateBasicTarget(definition);

+					try {

+						populateBasicTarget(definition);

+					} catch (CoreException e) {

+						setErrorMessage(e.getMessage());

+						return null;

+					}

 					break;

 				case USE_CURRENT_TP :

 					try {

@@ -198,12 +204,14 @@
 	 * Applies basic target settings to the given target definition.

 	 * 

 	 * @param definition

+	 * @throws CoreException 

 	 */

-	private void populateBasicTarget(ITargetDefinition definition) {

+	private void populateBasicTarget(ITargetDefinition definition) throws CoreException {

 		ITargetPlatformService service = getTargetService();

-		if (service != null) {

-			definition.setName(PDEUIMessages.TargetCreationPage_7);

-			definition.setBundleContainers(new IBundleContainer[] {service.newProfileContainer("${eclipse_home}", null)}); //$NON-NLS-1$

+		if (service instanceof TargetPlatformService) {

+			TargetPlatformService ts = (TargetPlatformService) service;

+			ITargetDefinition def = ts.newDefaultTargetDefinition();

+			ts.copyTargetDefinition(def, definition);

 		}

 	}