Java tutorial
/******************************************************************************* * Copyright (c) 2009, 2011 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 *******************************************************************************/ package com.siteview.mde.internal.ui.shared.target; import com.siteview.mde.core.monitor.IMonitorModelBase; import com.ibm.icu.text.MessageFormat; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.net.*; import java.util.*; import java.util.List; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.eclipse.core.runtime.*; import org.eclipse.equinox.frameworkadmin.BundleInfo; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.*; import org.eclipse.osgi.util.ManifestElement; import com.siteview.mde.internal.core.DependencyManager; import com.siteview.mde.internal.core.MDEState; import com.siteview.mde.internal.core.ifeature.*; import com.siteview.mde.internal.core.target.TargetDefinition; import com.siteview.mde.internal.core.target.provisional.*; import com.siteview.mde.internal.ui.MDEPlugin; import com.siteview.mde.internal.ui.SWTFactory; import com.siteview.mde.internal.ui.editor.targetdefinition.TargetEditor; import com.siteview.mde.internal.ui.parts.ComboPart; import com.siteview.mde.internal.ui.shared.CachedCheckboxTreeViewer; import com.siteview.mde.internal.ui.shared.FilteredCheckboxTree; import com.siteview.mde.internal.ui.wizards.target.TargetDefinitionContentPage; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.*; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.widgets.FormToolkit; import org.osgi.framework.BundleException; /** * UI Part that displays all of the bundle contents of a target. The bundles can be * excluded by unchecking them. There are a variety of options to change the tree's * format. * * @see TargetEditor * @see TargetDefinitionContentPage * @see ITargetDefinition * @see IResolvedBundle */ public class TargetContentsGroup { private CachedCheckboxTreeViewer fTree; private MenuManager fMenuManager; private Button fSelectButton; private Button fDeselectButton; private Button fSelectAllButton; private Button fDeselectAllButton; private Button fSelectRequiredButton; private Label fModeLabel; private Button fPluginModeButton; private Button fFeaureModeButton; private Label fShowLabel; private Button fShowSourceButton; private Button fShowPluginsButton; private Label fCountLabel; private Label fGroupLabel; private Combo fGroupCombo; private ComboPart fGroupComboPart; private ViewerFilter fSourceFilter; private ViewerFilter fPluginFilter; private ITargetDefinition fTargetDefinition; /** * Maps file paths to a list of bundles that reside in that location, use {@link #getFileBundleMapping()} rather than accessing the field directly */ private Map fFileBundleMapping; /** * List of IResolvedBundles that are being used to display error statuses for missing plug-ins/features, possibly <code>null</code> */ private List fMissing; private static final NameVersionDescriptor OTHER_CATEGORY = new NameVersionDescriptor( Messages.TargetContentsGroup_OtherPluginsParent, null); /** * Cached list of all bundles, used to quickly obtain bundle counts. */ private List fAllBundles = new ArrayList(); private int fGrouping; private static final int GROUP_BY_NONE = 0; private static final int GROUP_BY_FILE_LOC = 1; private static final int GROUP_BY_CONTAINER = 2; private ListenerList fChangeListeners = new ListenerList(); /** * Creates this part using the form toolkit and adds it to the given composite. * * @param parent parent composite * @param toolkit toolkit to create the widgets with * @return generated instance of the table part */ public static TargetContentsGroup createInForm(Composite parent, FormToolkit toolkit) { TargetContentsGroup contentTable = new TargetContentsGroup(); contentTable.createFormContents(parent, toolkit); return contentTable; } /** * Creates this part using standard dialog widgets and adds it to the given composite. * * @param parent parent composite * @return generated instance of the table part */ public static TargetContentsGroup createInDialog(Composite parent) { TargetContentsGroup contentTable = new TargetContentsGroup(); contentTable.createDialogContents(parent); return contentTable; } /** * Use {@link #createInDialog(Composite)} or {@link #createInDialog(Composite)} */ protected TargetContentsGroup() { } /** * Adds a listener to the set of listeners that will be notified when the bundle containers * are modified. This method has no effect if the listener has already been added. * * @param listener target changed listener to add */ public void addTargetChangedListener(ITargetChangedListener listener) { fChangeListeners.add(listener); } /** * Informs the target content listeners that check state has changed */ public void contentChanged() { Object[] listeners = fChangeListeners.getListeners(); for (int i = 0; i < listeners.length; i++) { ((ITargetChangedListener) listeners[i]).contentsChanged(fTargetDefinition, this, false, false); } } /** * Disposes the contents of this group */ public void dispose() { if (fMenuManager != null) { fMenuManager.dispose(); } } /** * Creates the contents of this group, using the given toolkit where appropriate so that the controls * have the form editor look and feel. * * @param parent parent composite * @param toolkit toolkit to create controls with */ protected void createFormContents(Composite parent, FormToolkit toolkit) { fGrouping = GROUP_BY_NONE; Composite comp = toolkit.createComposite(parent); GridLayout layout = new GridLayout(2, false); layout.marginWidth = layout.marginHeight = 0; comp.setLayout(layout); comp.setLayoutData(new GridData(GridData.FILL_BOTH)); comp.setFont(parent.getFont()); createTree(comp, toolkit); createButtons(comp, toolkit); fCountLabel = toolkit.createLabel(comp, ""); //$NON-NLS-1$ GridData data = new GridData(GridData.FILL_HORIZONTAL); data.horizontalSpan = 2; fCountLabel.setLayoutData(data); updateButtons(); initializeFilters(); } /** * Creates the contents of this group in the normal dialog style * * @param parent parent composite */ protected void createDialogContents(Composite parent) { fGrouping = GROUP_BY_NONE; Composite comp = SWTFactory.createComposite(parent, 2, 1, GridData.FILL_BOTH, 0, 0); createTree(comp, null); createButtons(comp, null); fCountLabel = SWTFactory.createLabel(comp, "", 2); //$NON-NLS-1$ updateButtons(); initializeFilters(); } /** * Creates the tree in this group * * @param parent parent composite * @param style toolkit for form style or <code>null</code> for dialog style */ private TreeViewer createTree(Composite parent, FormToolkit toolkit) { FilteredCheckboxTree tree = new FilteredCheckboxTree(parent, toolkit); tree.setLayoutData(new GridData(GridData.FILL_BOTH)); tree.getPatternFilter().setIncludeLeadingWildcard(true); tree.getFilterControl().setFont(parent.getFont()); fTree = tree.getCheckboxTreeViewer(); ((GridData) fTree.getControl().getLayoutData()).heightHint = 300; fTree.getControl().setFont(parent.getFont()); fTree.setUseHashlookup(true); fTree.setContentProvider(new TreeContentProvider()); fTree.setLabelProvider(new StyledBundleLabelProvider(true, false)); fTree.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { IStructuredSelection selection = (IStructuredSelection) event.getSelection(); Object first = selection.getFirstElement(); fTree.setChecked(first, !fTree.getChecked(first)); saveIncludedBundleState(); contentChanged(); updateButtons(); fTree.update(fTargetDefinition.getBundleContainers(), new String[] { IBasicPropertyConstants.P_TEXT }); } }); fTree.addCheckStateListener(new ICheckStateListener() { public void checkStateChanged(CheckStateChangedEvent event) { saveIncludedBundleState(); contentChanged(); updateButtons(); fTree.update(fTargetDefinition.getBundleContainers(), new String[] { IBasicPropertyConstants.P_TEXT }); } }); fTree.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { updateButtons(); } }); fTree.setSorter(new ViewerSorter() { public int compare(Viewer viewer, Object e1, Object e2) { if (fFeaureModeButton.getSelection()) { if (e1 == OTHER_CATEGORY) { return 1; } if (e2 == OTHER_CATEGORY) { return -1; } } if (e1 instanceof IResolvedBundle && !(e2 instanceof IResolvedBundle)) { return -1; } if (e2 instanceof IResolvedBundle && !(e1 instanceof IResolvedBundle)) { return 1; } if (e1 instanceof IResolvedBundle && e2 instanceof IResolvedBundle) { IStatus status1 = ((IResolvedBundle) e1).getStatus(); IStatus status2 = ((IResolvedBundle) e2).getStatus(); if (!status1.isOK() && status2.isOK()) { return -1; } if (status1.isOK() && !status2.isOK()) { return 1; } } return super.compare(viewer, e1, e2); } }); fMenuManager = new MenuManager(); fMenuManager.add(new Action(Messages.TargetContentsGroup_collapseAll, PlatformUI.getWorkbench() .getSharedImages().getImageDescriptor(ISharedImages.IMG_ELCL_COLLAPSEALL)) { public void run() { fTree.collapseAll(); } }); Menu contextMenu = fMenuManager.createContextMenu(tree); tree.setMenu(contextMenu); return fTree; } /** * Creates the buttons in this group inside a new composite * * @param parent parent composite * @param toolkit toolkit to give form style or <code>null</code> for dialog style */ private void createButtons(Composite parent, FormToolkit toolkit) { if (toolkit != null) { Composite buttonComp = toolkit.createComposite(parent); GridLayout layout = new GridLayout(); layout.marginWidth = layout.marginHeight = 0; buttonComp.setLayout(layout); buttonComp.setLayoutData(new GridData(GridData.FILL_VERTICAL)); fSelectButton = toolkit.createButton(buttonComp, Messages.IncludedBundlesTree_0, SWT.PUSH); fSelectButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); fDeselectButton = toolkit.createButton(buttonComp, Messages.IncludedBundlesTree_1, SWT.PUSH); fDeselectButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Label emptySpace = new Label(buttonComp, SWT.NONE); GridData gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING); gd.widthHint = gd.heightHint = 5; emptySpace.setLayoutData(gd); fSelectAllButton = toolkit.createButton(buttonComp, Messages.IncludedBundlesTree_2, SWT.PUSH); fSelectAllButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); fDeselectAllButton = toolkit.createButton(buttonComp, Messages.IncludedBundlesTree_3, SWT.PUSH); fDeselectAllButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); emptySpace = new Label(buttonComp, SWT.NONE); gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING); gd.widthHint = gd.heightHint = 5; emptySpace.setLayoutData(gd); fSelectRequiredButton = toolkit.createButton(buttonComp, Messages.TargetContentsGroup_4, SWT.PUSH); fSelectRequiredButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Composite filterComp = toolkit.createComposite(buttonComp); layout = new GridLayout(); layout.marginWidth = layout.marginHeight = 0; filterComp.setLayout(layout); filterComp.setLayoutData(new GridData(SWT.LEFT, SWT.BOTTOM, true, true)); fModeLabel = toolkit.createLabel(filterComp, Messages.TargetContentsGroup_ManageUsing); fPluginModeButton = toolkit.createButton(filterComp, Messages.TargetContentsGroup_PluginMode, SWT.RADIO); fPluginModeButton.setSelection(true); fFeaureModeButton = toolkit.createButton(filterComp, Messages.TargetContentsGroup_FeatureMode, SWT.RADIO); fFeaureModeButton.setSelection(true); emptySpace = new Label(filterComp, SWT.NONE); gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING); gd.widthHint = gd.heightHint = 5; emptySpace.setLayoutData(gd); fShowLabel = toolkit.createLabel(filterComp, Messages.BundleContainerTable_9); fShowPluginsButton = toolkit.createButton(filterComp, Messages.BundleContainerTable_14, SWT.CHECK); fShowPluginsButton.setSelection(true); fShowSourceButton = toolkit.createButton(filterComp, Messages.BundleContainerTable_15, SWT.CHECK); fShowSourceButton.setSelection(true); emptySpace = new Label(filterComp, SWT.NONE); gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING); gd.widthHint = gd.heightHint = 5; emptySpace.setLayoutData(gd); fGroupLabel = toolkit.createLabel(filterComp, Messages.TargetContentsGroup_0); fGroupComboPart = new ComboPart(); fGroupComboPart.createControl(filterComp, toolkit, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalIndent = 10; fGroupComboPart.getControl().setLayoutData(gd); fGroupComboPart.setItems(new String[] { Messages.TargetContentsGroup_1, Messages.TargetContentsGroup_2, Messages.TargetContentsGroup_3 }); fGroupComboPart.setVisibleItemCount(30); fGroupComboPart.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { handleGroupChange(); } }); fGroupComboPart.select(0); } else { Composite buttonComp = SWTFactory.createComposite(parent, 1, 1, GridData.FILL_VERTICAL, 0, 0); fSelectButton = SWTFactory.createPushButton(buttonComp, Messages.IncludedBundlesTree_0, null); fDeselectButton = SWTFactory.createPushButton(buttonComp, Messages.IncludedBundlesTree_1, null); Label emptySpace = new Label(buttonComp, SWT.NONE); GridData gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING); gd.widthHint = gd.heightHint = 5; emptySpace.setLayoutData(gd); fSelectAllButton = SWTFactory.createPushButton(buttonComp, Messages.IncludedBundlesTree_2, null); fDeselectAllButton = SWTFactory.createPushButton(buttonComp, Messages.IncludedBundlesTree_3, null); emptySpace = new Label(buttonComp, SWT.NONE); gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING); gd.widthHint = gd.heightHint = 5; emptySpace.setLayoutData(gd); fSelectRequiredButton = SWTFactory.createPushButton(buttonComp, Messages.TargetContentsGroup_4, null); Composite filterComp = SWTFactory.createComposite(buttonComp, 1, 1, SWT.NONE, 0, 0); filterComp.setLayoutData(new GridData(SWT.LEFT, SWT.BOTTOM, true, true)); fModeLabel = SWTFactory.createLabel(filterComp, Messages.TargetContentsGroup_ManageUsing, 1); fPluginModeButton = SWTFactory.createRadioButton(filterComp, Messages.TargetContentsGroup_PluginMode); fFeaureModeButton = SWTFactory.createRadioButton(filterComp, Messages.TargetContentsGroup_FeatureMode); emptySpace = new Label(filterComp, SWT.NONE); gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING); gd.widthHint = gd.heightHint = 5; emptySpace.setLayoutData(gd); fShowLabel = SWTFactory.createLabel(filterComp, Messages.BundleContainerTable_9, 1); fShowPluginsButton = SWTFactory.createCheckButton(filterComp, Messages.BundleContainerTable_14, null, true, 1); fShowSourceButton = SWTFactory.createCheckButton(filterComp, Messages.BundleContainerTable_15, null, true, 1); emptySpace = new Label(filterComp, SWT.NONE); gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING); gd.widthHint = gd.heightHint = 5; emptySpace.setLayoutData(gd); fGroupLabel = SWTFactory.createLabel(filterComp, Messages.TargetContentsGroup_0, 1); fGroupCombo = SWTFactory.createCombo(filterComp, SWT.READ_ONLY, 1, new String[] { Messages.TargetContentsGroup_1, Messages.TargetContentsGroup_2, Messages.TargetContentsGroup_3 }); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalIndent = 10; fGroupCombo.setLayoutData(gd); fGroupCombo.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { handleGroupChange(); } }); fGroupCombo.select(0); } fSelectButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (!fTree.getSelection().isEmpty()) { Object[] selected = ((IStructuredSelection) fTree.getSelection()).toArray(); for (int i = 0; i < selected.length; i++) { fTree.setChecked(selected[i], true); } saveIncludedBundleState(); contentChanged(); updateButtons(); fTree.update(fTargetDefinition.getBundleContainers(), new String[] { IBasicPropertyConstants.P_TEXT }); } } }); fDeselectButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (!fTree.getSelection().isEmpty()) { Object[] selected = ((IStructuredSelection) fTree.getSelection()).toArray(); for (int i = 0; i < selected.length; i++) { fTree.setChecked(selected[i], false); } saveIncludedBundleState(); contentChanged(); updateButtons(); fTree.update(fTargetDefinition.getBundleContainers(), new String[] { IBasicPropertyConstants.P_TEXT }); } } }); fSelectAllButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { fTree.setAllChecked(true); saveIncludedBundleState(); contentChanged(); updateButtons(); fTree.update(fTargetDefinition.getBundleContainers(), new String[] { IBasicPropertyConstants.P_TEXT }); } }); fDeselectAllButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { fTree.setAllChecked(false); saveIncludedBundleState(); contentChanged(); updateButtons(); fTree.update(fTargetDefinition.getBundleContainers(), new String[] { IBasicPropertyConstants.P_TEXT }); } }); fSelectRequiredButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { Object[] allChecked = fTree.getCheckedLeafElements(); Object[] required = null; if (fFeaureModeButton.getSelection()) { required = getRequiredFeatures(fTargetDefinition.getAllFeatures(), allChecked); } else { required = getRequiredPlugins(fAllBundles, allChecked); } for (int i = 0; i < required.length; i++) { fTree.setChecked(required[i], true); } saveIncludedBundleState(); contentChanged(); updateButtons(); fTree.update(fTargetDefinition.getBundleContainers(), new String[] { IBasicPropertyConstants.P_TEXT }); } }); fPluginModeButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { // Moving from feature based filtering to plug-in based, need to update storage ((TargetDefinition) fTargetDefinition).setUIMode(TargetDefinition.MODE_PLUGIN); contentChanged(); fTargetDefinition.setIncluded(null); fGroupLabel.setEnabled(true); if (fGroupCombo != null) { fGroupCombo.setEnabled(true); } else { fGroupComboPart.getControl().setEnabled(true); } fTree.getControl().setRedraw(false); fTree.refresh(false); fTree.expandAll(); updateCheckState(); updateButtons(); fTree.getControl().setRedraw(true); } }); fPluginModeButton.setSelection(true); GridData gd = new GridData(); gd.horizontalIndent = 10; fPluginModeButton.setLayoutData(gd); fFeaureModeButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { // Moving from plug-in based filtering to feature based, need to update storage ((TargetDefinition) fTargetDefinition).setUIMode(TargetDefinition.MODE_FEATURE); contentChanged(); fTargetDefinition.setIncluded(null); fGroupLabel.setEnabled(false); if (fGroupCombo != null) { fGroupCombo.setEnabled(false); } else { fGroupComboPart.getControl().setEnabled(false); } fTree.getControl().setRedraw(false); fTree.refresh(false); fTree.expandAll(); updateCheckState(); updateButtons(); fTree.getControl().setRedraw(true); } }); fFeaureModeButton.setSelection(false); gd = new GridData(); gd.horizontalIndent = 10; fFeaureModeButton.setLayoutData(gd); fShowPluginsButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (!fShowPluginsButton.getSelection()) { fTree.addFilter(fPluginFilter); } else { fTree.removeFilter(fPluginFilter); fTree.expandAll(); updateCheckState(); } updateButtons(); } }); fShowPluginsButton.setSelection(true); gd = new GridData(); gd.horizontalIndent = 10; fShowPluginsButton.setLayoutData(gd); fShowSourceButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (!fShowSourceButton.getSelection()) { fTree.addFilter(fSourceFilter); } else { fTree.removeFilter(fSourceFilter); fTree.expandAll(); updateCheckState(); } updateButtons(); } }); fShowSourceButton.setSelection(true); gd = new GridData(); gd.horizontalIndent = 10; fShowSourceButton.setLayoutData(gd); } private void initializeFilters() { fSourceFilter = new ViewerFilter() { public boolean select(Viewer viewer, Object parentElement, Object element) { if (element instanceof IResolvedBundle) { if (((IResolvedBundle) element).isSourceBundle()) { return false; } } return true; } }; fPluginFilter = new ViewerFilter() { public boolean select(Viewer viewer, Object parentElement, Object element) { if (element instanceof IResolvedBundle) { if (!((IResolvedBundle) element).isSourceBundle()) { return false; } } return true; } }; } /** * Returns the file path where the given resolved bundle can be found. * Used to group bundles by file path in the tree. * * @param bundle bundle to lookup parent path for * @return path of parent directory, if unknown it will be a path object containing "Unknown" */ private IPath getParentPath(IResolvedBundle bundle) { URI location = bundle.getBundleInfo().getLocation(); if (location == null) { return new Path(Messages.TargetContentsGroup_8); } IPath path = new Path(URIUtil.toUnencodedString(location)); path = path.removeLastSegments(1); return path; } /** * Parses a bunlde's manifest into a dictionary. The bundle may be in a jar * or in a directory at the specified location. * * @param bundleLocation root location of the bundle * @return bundle manifest dictionary or <code>null</code> if none * @throws IOException if unable to parse */ protected Map loadManifest(File bundleLocation) throws IOException { ZipFile jarFile = null; InputStream manifestStream = null; String extension = new Path(bundleLocation.getName()).getFileExtension(); try { if (extension != null && extension.equals("jar") && bundleLocation.isFile()) { //$NON-NLS-1$ jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ); ZipEntry manifestEntry = jarFile.getEntry(JarFile.MANIFEST_NAME); if (manifestEntry != null) { manifestStream = jarFile.getInputStream(manifestEntry); } } else { File file = new File(bundleLocation, JarFile.MANIFEST_NAME); if (file.exists()) manifestStream = new FileInputStream(file); } if (manifestStream == null) { return null; } return ManifestElement.parseBundleManifest(manifestStream, new Hashtable(10)); } catch (BundleException e) { MDEPlugin.log(e); } finally { try { if (manifestStream != null) { manifestStream.close(); } } catch (IOException e) { MDEPlugin.log(e); } try { if (jarFile != null) { jarFile.close(); } } catch (IOException e) { MDEPlugin.log(e); } } return null; } /** * Uses the target state to determine all bundles required by the * currently checked bundles and returns them so they can be checked in the tree. * * @param allBundles list of all bundles to search requirements in * @param checkedBundles list of bundles to get requirements for * @return list of resolved bundles from the collection to be checked */ private Object[] getRequiredPlugins(final Collection allBundles, final Object[] checkedBundles) { final Set dependencies = new HashSet(); IRunnableWithProgress op = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) { try { monitor.beginTask(Messages.TargetContentsGroup_5, 150); // Get all the bundle locations List allLocations = new ArrayList(allBundles.size()); for (Iterator iterator = allBundles.iterator(); iterator.hasNext();) { IResolvedBundle current = (IResolvedBundle) iterator.next(); try { // Some bundles, such as those with errors, may not have locations URI location = current.getBundleInfo().getLocation(); if (location != null) { allLocations.add(new File(location).toURL()); } } catch (MalformedURLException e) { MDEPlugin.log(e); monitor.setCanceled(true); return; } } if (monitor.isCanceled()) { return; } monitor.worked(20); // Create a PDE State containing all of the target bundles MDEState state = new MDEState((URL[]) allLocations.toArray(new URL[allLocations.size()]), true, new SubProgressMonitor(monitor, 50)); if (monitor.isCanceled()) { return; } // Figure out which of the models have been checked IMonitorModelBase[] models = state.getTargetModels(); List checkedModels = new ArrayList(checkedBundles.length); for (int i = 0; i < checkedBundles.length; i++) { if (checkedBundles[i] instanceof IResolvedBundle) { BundleInfo bundle = ((IResolvedBundle) checkedBundles[i]).getBundleInfo(); for (int j = 0; j < models.length; j++) { if (models[j].getBundleDescription().getSymbolicName() .equals(bundle.getSymbolicName()) && models[j].getBundleDescription().getVersion().toString() .equals(bundle.getVersion())) { checkedModels.add(models[j]); break; } } } } monitor.worked(20); if (monitor.isCanceled()) { return; } // Get implicit dependencies as a list of strings // This is wasteful since the dependency calculation puts them back into BundleInfos NameVersionDescriptor[] implicitDependencies = fTargetDefinition.getImplicitDependencies(); List implicitIDs = new ArrayList(); if (implicitDependencies != null) { for (int i = 0; i < implicitDependencies.length; i++) { implicitIDs.add(implicitDependencies[i].getId()); } } monitor.worked(10); // Get all dependency bundles // exclude "org.eclipse.ui.workbench.compatibility" - it is only needed for pre-3.0 bundles dependencies.addAll(DependencyManager.getDependencies(checkedModels.toArray(), (String[]) implicitIDs.toArray(new String[implicitIDs.size()]), state.getState(), new String[] { "org.eclipse.ui.workbench.compatibility" })); //$NON-NLS-1$ monitor.worked(50); } finally { monitor.done(); } } }; try { // Calculate the dependencies new ProgressMonitorDialog(fTree.getControl().getShell()).run(true, true, op); // We want to check the dependents, the source of the dependents, and the source of the originally checked Set checkedNames = new HashSet(checkedBundles.length); for (int i = 0; i < checkedBundles.length; i++) { if (checkedBundles[i] instanceof IResolvedBundle) { checkedNames.add(((IResolvedBundle) checkedBundles[i]).getBundleInfo().getSymbolicName()); } } List toCheck = new ArrayList(); for (Iterator iterator = fAllBundles.iterator(); iterator.hasNext();) { IResolvedBundle bundle = (IResolvedBundle) iterator.next(); if (bundle.isSourceBundle()) { String name = bundle.getSourceTarget().getSymbolicName(); if (name != null && (dependencies.contains(name) || checkedNames.contains(name))) { toCheck.add(bundle); } } else if (dependencies.contains(bundle.getBundleInfo().getSymbolicName())) { toCheck.add(bundle); } } return toCheck.toArray(); } catch (InvocationTargetException e) { MDEPlugin.log(e); } catch (InterruptedException e) { } return new Object[0]; } /** * Uses the feature model to determine the set of features required by the * given list of checked features * * @param allFeatures list of all features to search requirements in * @param checkedFeatures list of features to get requirements for * @return list of features to be checked */ private Object[] getRequiredFeatures(final IFeatureModel[] allFeatures, final Object[] checkedFeatures) { ArrayList required = new ArrayList(); for (int j = 0; j < checkedFeatures.length; j++) { if (checkedFeatures[j] instanceof IFeatureModel) { getFeatureDependencies((IFeatureModel) checkedFeatures[j], allFeatures, required); } } return required.toArray(); } /** * Recursively gets the ID of required features of this feature and adds them to the list * @param model feature model to get requirements of * @param requiredFeatureList collector for the required features */ private void getFeatureDependencies(IFeatureModel model, IFeatureModel[] allFeatures, ArrayList requiredFeatureList) { IFeature feature = model.getFeature(); IFeatureImport[] featureImports = feature.getImports(); for (int i = 0; i < featureImports.length; i++) { if (featureImports[i].getType() == IFeatureImport.FEATURE) { for (int j = 0; j < allFeatures.length; j++) { if (allFeatures[j].getFeature().getId().equals(featureImports[i].getId())) { requiredFeatureList.add(allFeatures[j]); getFeatureDependencies(allFeatures[j], allFeatures, requiredFeatureList); break; } } } } IFeatureChild[] featureIncludes = feature.getIncludedFeatures(); for (int i = 0; i < featureIncludes.length; i++) { requiredFeatureList.add(featureIncludes[i].getId()); for (int j = 0; j < allFeatures.length; j++) { if (allFeatures[j].getFeature().getId().equals(featureIncludes[i].getId())) { requiredFeatureList.add(allFeatures[j]); getFeatureDependencies(allFeatures[j], allFeatures, requiredFeatureList); break; } } } } private void handleGroupChange() { int index; if (fGroupCombo != null) { index = fGroupCombo.getSelectionIndex(); } else { index = fGroupComboPart.getSelectionIndex(); } if (index != fGrouping) { // Refresh tree fGrouping = index; fTree.getControl().setRedraw(false); fTree.refresh(false); fTree.expandAll(); updateCheckState(); updateButtons(); fTree.getControl().setRedraw(true); } } private void updateButtons() { if (fTargetDefinition != null && !fTree.getSelection().isEmpty()) { Object[] selection = ((IStructuredSelection) fTree.getSelection()).toArray(); boolean hasResolveBundle = false; boolean hasParent = false; boolean allSelected = true; boolean noneSelected = true; for (int i = 0; i < selection.length; i++) { if (!hasResolveBundle || !hasParent) { if (selection[i] instanceof IResolvedBundle) { hasResolveBundle = true; } else { hasParent = true; } } boolean checked = fTree.getChecked(selection[i]); if (checked) { noneSelected = false; } else { allSelected = false; } } // Selection is available if not everything is already selected and not both a parent and child item are selected fSelectButton.setEnabled(!allSelected && !(hasResolveBundle && hasParent)); fDeselectButton.setEnabled(!noneSelected && !(hasResolveBundle && hasParent)); } else { fSelectButton.setEnabled(false); fDeselectButton.setEnabled(false); } int total = fAllBundles.size(); if (fFeaureModeButton.getSelection()) { if (fTargetDefinition == null) { total = 0; } else { total = fTargetDefinition.getAllFeatures().length; total += ((TargetDefinition) fTargetDefinition).getOtherBundles().length; } } if (fMissing != null) { total += fMissing.size(); } fSelectAllButton.setEnabled(fTargetDefinition != null && fTree.getCheckedLeafCount() != total); fDeselectAllButton.setEnabled(fTargetDefinition != null && fTree.getCheckedLeafCount() != 0); fSelectRequiredButton.setEnabled(fTargetDefinition != null && fTree.getCheckedLeafCount() > 0 && fTree.getCheckedLeafCount() != total); if (fTargetDefinition != null) { fCountLabel.setText(MessageFormat.format(Messages.TargetContentsGroup_9, new String[] { Integer.toString(fTree.getCheckedLeafCount()), Integer.toString(total) })); } else { fCountLabel.setText(""); //$NON-NLS-1$ } } /** * Set the container to display in the tree or <code>null</code> to disable the tree * @param input bundle container or <code>null</code> */ public void setInput(ITargetDefinition input) { fTargetDefinition = input; // Update the cached data fFileBundleMapping = null; fAllBundles.clear(); if (input == null || !input.isResolved()) { fTree.setInput(Messages.TargetContentsGroup_10); setEnabled(false); return; } IResolvedBundle[] allResolvedBundles = input.getAllBundles(); if (allResolvedBundles == null || allResolvedBundles.length == 0) { fTree.setInput(Messages.TargetContentsGroup_11); setEnabled(false); return; } for (int i = 0; i < allResolvedBundles.length; i++) { fAllBundles.add(allResolvedBundles[i]); } boolean isFeatureMode = ((TargetDefinition) fTargetDefinition).getUIMode() == TargetDefinition.MODE_FEATURE; fFeaureModeButton.setSelection(isFeatureMode); fPluginModeButton.setSelection(!isFeatureMode); fGroupLabel.setEnabled(!isFeatureMode); fTree.getControl().setRedraw(false); fTree.setInput(fTargetDefinition); fTree.expandAll(); updateCheckState(); updateButtons(); setEnabled(true); fTree.getControl().setRedraw(true); } private void updateCheckState() { List result = new ArrayList(); // Checked error statuses if (fMissing != null) { result.addAll(fMissing); } if (fFeaureModeButton.getSelection()) { // Checked features and plugins result.addAll(((TargetDefinition) fTargetDefinition).getFeaturesAndBundles()); } else { // Bundles with errors are already included from fMissing, do not add twice IResolvedBundle[] bundles = fTargetDefinition.getBundles(); for (int i = 0; i < bundles.length; i++) { if (bundles[i].getStatus().isOK()) { result.add(bundles[i]); } } } fTree.setCheckedElements(result.toArray()); } /** * This method clears any current target information and puts "Resolve Cancelled" into the * tree. Setting the input to null results in "Resolving..." to be put into the table which * may not be accurate. */ public void setCancelled() { fTargetDefinition = null; fTree.setInput(Messages.TargetContentsGroup_resolveCancelled); setEnabled(false); } /** * @return a map connecting IPath to the resolved bundles in that path */ private Map getFileBundleMapping() { if (fFileBundleMapping != null) { return fFileBundleMapping; } // Map the bundles into their file locations fFileBundleMapping = new HashMap(); for (Iterator iterator = fAllBundles.iterator(); iterator.hasNext();) { IResolvedBundle currentBundle = (IResolvedBundle) iterator.next(); IPath parentPath = getParentPath(currentBundle); List bundles = (List) fFileBundleMapping.get(parentPath); if (bundles == null) { bundles = new ArrayList(); bundles.add(currentBundle); fFileBundleMapping.put(parentPath, bundles); } else { bundles.add(currentBundle); } } return fFileBundleMapping; } private Object[] getBundleChildren(Object parent) { Object[] result = null; if (parent == null) { result = fAllBundles.toArray(); } else if (fFeaureModeButton.getSelection() && parent == OTHER_CATEGORY) { result = ((TargetDefinition) fTargetDefinition).getOtherBundles(); } else if (fGrouping == GROUP_BY_CONTAINER && parent instanceof IBundleContainer) { IBundleContainer container = (IBundleContainer) parent; result = container.getBundles(); } else if (fGrouping == GROUP_BY_FILE_LOC && parent instanceof IPath) { List bundles = (List) getFileBundleMapping().get(parent); if (bundles != null && bundles.size() > 0) { result = bundles.toArray(); } } if (result == null) { return new Object[0]; } return result; } /* (non-Javadoc) * @see org.eclipse.swt.widgets.Control#setEnabled(boolean) */ public void setEnabled(boolean enabled) { fTree.getControl().setEnabled(enabled); if (enabled) { updateButtons(); } else { fSelectButton.setEnabled(false); fSelectAllButton.setEnabled(false); fDeselectButton.setEnabled(false); fDeselectAllButton.setEnabled(false); fSelectRequiredButton.setEnabled(false); fCountLabel.setText(""); //$NON-NLS-1$ } fModeLabel.setEnabled(enabled); fPluginModeButton.setEnabled(enabled); fFeaureModeButton.setEnabled(enabled); fShowLabel.setEnabled(enabled); fShowPluginsButton.setEnabled(enabled); fShowSourceButton.setEnabled(enabled); boolean isPluginMode = !fFeaureModeButton.getSelection(); fGroupLabel.setEnabled(enabled && isPluginMode); if (fGroupCombo != null) { fGroupCombo.setEnabled(enabled && isPluginMode); } else { fGroupComboPart.setEnabled(enabled && isPluginMode); } } public void saveIncludedBundleState() { if (fFeaureModeButton.getSelection()) { // Create a list of checked bundle infos List included = new ArrayList(); int missingCount = 0; Object[] checked = fTree.getCheckedLeafElements(); for (int i = 0; i < checked.length; i++) { if (checked[i] instanceof IFeatureModel) { included.add(new NameVersionDescriptor(((IFeatureModel) checked[i]).getFeature().getId(), null, NameVersionDescriptor.TYPE_FEATURE)); } if (checked[i] instanceof IResolvedBundle) { // Missing features are included as IResolvedBundles, save them as features instead if (((IResolvedBundle) checked[i]).getStatus() .getCode() == IResolvedBundle.STATUS_PLUGIN_DOES_NOT_EXIST) { included.add(new NameVersionDescriptor( ((IResolvedBundle) checked[i]).getBundleInfo().getSymbolicName(), null, NameVersionDescriptor.TYPE_PLUGIN)); missingCount++; } else if (((IResolvedBundle) checked[i]).getStatus() .getCode() == IResolvedBundle.STATUS_FEATURE_DOES_NOT_EXIST) { included.add(new NameVersionDescriptor( ((IResolvedBundle) checked[i]).getBundleInfo().getSymbolicName(), null, NameVersionDescriptor.TYPE_FEATURE)); missingCount++; } else { included.add(new NameVersionDescriptor( ((IResolvedBundle) checked[i]).getBundleInfo().getSymbolicName(), null)); } } } if (included.size() == 0) { fTargetDefinition.setIncluded(new NameVersionDescriptor[0]); } else if (included.size() == 0 || included.size() - missingCount == fTargetDefinition.getAllFeatures().length + ((TargetDefinition) fTargetDefinition).getOtherBundles().length) { fTargetDefinition.setIncluded(null); } else { fTargetDefinition.setIncluded( (NameVersionDescriptor[]) included.toArray(new NameVersionDescriptor[included.size()])); } } else { // Figure out if there are multiple bundles sharing the same id Set multi = new HashSet(); // BSNs of bundles with multiple versions available Set all = new HashSet(); for (Iterator iterator = fAllBundles.iterator(); iterator.hasNext();) { IResolvedBundle rb = (IResolvedBundle) iterator.next(); if (!all.add(rb.getBundleInfo().getSymbolicName())) { multi.add(rb.getBundleInfo().getSymbolicName()); } } // Create a list of checked bundle infos List included = new ArrayList(); Object[] checked = fTree.getCheckedLeafElements(); for (int i = 0; i < checked.length; i++) { if (checked[i] instanceof IResolvedBundle) { // Create the bundle info object String bsn = ((IResolvedBundle) checked[i]).getBundleInfo().getSymbolicName(); NameVersionDescriptor info = null; if (multi.contains(bsn)) { // include version info info = new NameVersionDescriptor(bsn, ((IResolvedBundle) checked[i]).getBundleInfo().getVersion()); } else { // don't store version info info = new NameVersionDescriptor(bsn, null); } included.add(info); } } if (included.size() == 0) { fTargetDefinition.setIncluded(new NameVersionDescriptor[0]); } else if (included.size() == fAllBundles.size() + fMissing.size()) { fTargetDefinition.setIncluded(null); } else { fTargetDefinition.setIncluded( (NameVersionDescriptor[]) included.toArray(new NameVersionDescriptor[included.size()])); } } } /** * Content provider for the content tree. Allows for different groupings to be used. * */ class TreeContentProvider implements ITreeContentProvider { public Object[] getChildren(Object parentElement) { return getBundleChildren(parentElement); } public Object getParent(Object element) { return null; } public boolean hasChildren(Object element) { if (fFeaureModeButton.getSelection() && element == OTHER_CATEGORY) { return true; } if (fGrouping == GROUP_BY_NONE || element instanceof IResolvedBundle) { return false; } if (element instanceof IBundleContainer || element instanceof IPath) { return getBundleChildren(element).length > 0; } return false; } public Object[] getElements(Object inputElement) { if (inputElement instanceof ITargetDefinition) { List result = new ArrayList(); // Check if there are any errors for missing features/bundles to display if (fMissing == null) { fMissing = new ArrayList(); } else { fMissing.clear(); } IResolvedBundle[] bundles = fTargetDefinition.getBundles(); for (int i = 0; i < bundles.length; i++) { if (!bundles[i].getStatus().isOK()) { fMissing.add(bundles[i]); result.add(bundles[i]); } } if (fFeaureModeButton.getSelection()) { IFeatureModel[] features = fTargetDefinition.getAllFeatures(); result.addAll(Arrays.asList(features)); // Check if we need the other category if (((TargetDefinition) fTargetDefinition).getOtherBundles().length > 0) { result.add(OTHER_CATEGORY); } } else if (fGrouping == GROUP_BY_CONTAINER) { result.addAll(Arrays.asList(fTargetDefinition.getBundleContainers())); } else if (fGrouping == GROUP_BY_NONE) { // Missing bundles are already handled by adding to fMissing, avoid adding twice IResolvedBundle[] allBundles = fTargetDefinition.getAllBundles(); for (int i = 0; i < allBundles.length; i++) { if (allBundles[i].getStatus().isOK()) { result.add(allBundles[i]); } } } else { result.addAll(Arrays.asList(getFileBundleMapping().keySet().toArray())); } return result.toArray(); } return new Object[] { inputElement }; } public void dispose() { } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } } }