/*******************************************************************************
* Copyright (c) 2012, 2013 GoPivotal, Inc.
* 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:
* GoPivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.wizard.template;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.DecorationOverlayIcon;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.springframework.ide.eclipse.wizard.WizardImages;
import org.springframework.ide.eclipse.wizard.WizardPlugin;
import org.springframework.ide.eclipse.wizard.template.infrastructure.ITemplateElement;
import org.springframework.ide.eclipse.wizard.template.infrastructure.SimpleProjectContentManager;
import org.springframework.ide.eclipse.wizard.template.infrastructure.Template;
import org.springframework.ide.eclipse.wizard.template.infrastructure.TemplateCategory;
import org.springframework.ide.eclipse.wizard.template.util.TemplatesPreferencePage;
import org.springframework.ide.eclipse.wizard.template.util.TemplatesPreferencesModel;
import org.springsource.ide.eclipse.commons.content.core.ContentItem;
import org.springsource.ide.eclipse.commons.content.core.ContentManager;
import org.springsource.ide.eclipse.commons.content.core.ContentPlugin;
import org.springsource.ide.eclipse.commons.content.core.util.ContentUtil;
import org.springsource.ide.eclipse.commons.content.core.util.Descriptor;
import org.springsource.ide.eclipse.commons.content.core.util.IContentConstants;
import org.springsource.ide.eclipse.commons.ui.StsUiImages;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Part that displays templates available when creating a project. Templates are
* displayed in the part viewer based on metadata, but the actual contents of
* the template are not download unless explicitly requested through the
* download API. Selecting templates in the part viewer does not automatically
* download the contents. This template selection area only performs validations
* based on whether a template is selected or not.
* @author Terry Denney
* @author Leo Dos Santos
* @author Christian Dupuis
* @author Kaitlin Duck Sherwood
* @author Nieraj Singh
*/
public class TemplateSelectionPart extends WizardPageArea {
public static final String SIMPLE_PROJECTS_CATEGORY = "Simple Projects";
private final List<Template> templates;
private final IWizard wizard;
private Label descriptionLabel;
private StyledText descriptionText;
private TreeViewer treeViewer;
private Label legendImage;
private Label legendText;
private PropertyChangeListener contentManagerListener;
private Button refreshButton;
private final NewSpringProjectWizardModel model;
public TemplateSelectionPart(IWizard wizard, NewSpringProjectWizardModel model,
IWizardPageStatusHandler statusHandler) {
super(statusHandler);
this.wizard = wizard;
this.model = model;
templates = new ArrayList<Template>();
}
@Override
public Control createArea(Composite parent) {
initialiseTemplatesFromContentManager();
Composite container = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().margins(0, 0).spacing(0, 0).applyTo(container);
container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
Label label = new Label(container, SWT.NONE);
label.setText("Templates:"); //$NON-NLS-1$
label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
Tree tree = new Tree(container, SWT.FULL_SELECTION | SWT.BORDER);
tree.setLinesVisible(false);
tree.setHeaderVisible(false);
tree.setEnabled(true);
GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
data.heightHint = 170;
tree.setLayoutData(data);
treeViewer = new TreeViewer(tree);
treeViewer.setLabelProvider(new ILabelProvider() {
public void removeListener(ILabelProviderListener listener) {
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void dispose() {
}
public void addListener(ILabelProviderListener listener) {
}
public String getText(Object element) {
if (element instanceof ITemplateElement) {
return ((ITemplateElement) element).getName();
}
return null;
}
public Image getImage(Object element) {
if (element instanceof Template) {
Template template = (Template) element;
Image templateImage = WizardImages.getImage(WizardImages.TEMPLATE_ICON);
// Simple Project templates are bundled in the plugin,
// therefore do not require download icon, since they are
// not downloaded
if (template instanceof SimpleProject
|| ((template.getItem().isLocal() || TemplateUtils.hasBeenDownloaded(template)) && !template
.getItem().isNewerVersionAvailable())) {
return templateImage;
}
return WizardImages.getImage(new DecorationOverlayIcon(templateImage, new ImageDescriptor[] {
StsUiImages.DOWNLOAD_OVERLAY, null, null, null, null }));
}
if (element instanceof TemplateCategory) {
return WizardImages.getImage(WizardImages.TEMPLATE_CATEGORY_ICON);
}
return null;
}
});
treeViewer.setSorter(new ViewerSorter() {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
if (e1 instanceof TemplateCategory && e2 instanceof Template) {
return -1;
}
if (e1 instanceof Template && e2 instanceof TemplateCategory) {
return 1;
}
if (e1 instanceof ITemplateElement && e2 instanceof ITemplateElement) {
ITemplateElement t1 = (ITemplateElement) e1;
ITemplateElement t2 = (ITemplateElement) e2;
// Special Case, Simple Projects category is placed above
// others
if (t1.getName().equals(SIMPLE_PROJECTS_CATEGORY)) {
return -1;
}
else if (t2.getName().equals(SIMPLE_PROJECTS_CATEGORY)) {
return 1;
}
else {
return t1.getName().compareTo(t2.getName());
}
}
return super.compare(viewer, e1, e2);
}
});
treeViewer.setContentProvider(new TemplateContentProvider());
treeViewer.setInput(templates);
Composite legendContainer = new Composite(container, SWT.NONE);
legendContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
GridLayout headerLayout = new GridLayout(3, false);
headerLayout.marginWidth = 0;
headerLayout.marginHeight = 0;
legendContainer.setLayout(headerLayout);
Composite legendComposite = new Composite(legendContainer, SWT.NONE);
GridLayout legendLayout = new GridLayout(2, false);
legendLayout.verticalSpacing = 0;
legendLayout.marginHeight = 0;
legendLayout.marginBottom = 0;
int legendControlVerticalIndent = 5;
legendComposite.setLayout(legendLayout);
legendComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
legendImage = new Label(legendComposite, SWT.NONE);
GridDataFactory.fillDefaults().grab(false, false).indent(0, legendControlVerticalIndent).applyTo(legendImage);
legendImage.setImage(WizardImages.getImage(StsUiImages.DOWNLOAD_OVERLAY));
legendImage.setToolTipText("Templates with this icon will be downloaded after clicking the 'Next' button.");
legendText = new Label(legendComposite, SWT.NONE);
legendText.setText("requires downloading");
GridDataFactory.fillDefaults().grab(false, false).indent(0, legendControlVerticalIndent).applyTo(legendText);
Hyperlink hyperlink = new Hyperlink(legendContainer, SWT.WRAP);
GridDataFactory.fillDefaults().grab(false, false).indent(0, legendControlVerticalIndent).applyTo(hyperlink);
hyperlink.setText(NLS.bind("Configure templates...", null));
Color blue = new Color(null, 0, 0, 255);
hyperlink.setForeground(blue);
hyperlink.setUnderlined(true);
blue.dispose();
hyperlink.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent event) {
PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(null,
TemplatesPreferencePage.EXAMPLE_PREFERENCES_PAGE_ID, null, null);
refreshButton.setEnabled(false);
dialog.open();
downloadDescriptors();
refreshButton.setEnabled(!isRefreshing());
}
});
refreshButton = new Button(legendContainer, SWT.PUSH);
refreshButton.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false));
refreshButton.setText("Refresh");
refreshButton.setEnabled(!isRefreshing());
// refreshButton.setImage(WizardImages.getImage(WizardImages.REFRESH_ICON));
refreshButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// under most circumstances, we don't want to download templates
// if there has not been any change. However, when the user
// presses Refresh, they really do want to see something happen.
ContentPlugin.getDefault().getManager().setDirty();
downloadDescriptors();
}
});
refreshButton
.setToolTipText("Refresh the list of templates. Note that the current template selection will be cleared.");
Composite descriptionComposite = new Composite(container, SWT.NONE);
descriptionComposite.setLayout(new GridLayout());
descriptionComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
descriptionLabel = new Label(descriptionComposite, SWT.NONE);
descriptionLabel.setText("Description:"); //$NON-NLS-1$
descriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
descriptionText = new StyledText(descriptionComposite, SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL);
// descriptionText.setAlwaysShowScrollBars(false);
Display display = Display.getCurrent();
if (display != null) {
descriptionText.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
}
GridData descriptionData = new GridData(SWT.FILL, SWT.FILL, true, true);
descriptionData.widthHint = 200;
descriptionData.heightHint = 80;
descriptionText.setLayoutData(descriptionData);
treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = treeViewer.getSelection();
if (selection instanceof TreeSelection) {
Object element = ((TreeSelection) selection).getFirstElement();
if (element instanceof Template) {
setSeletectedTemplate((Template) element);
}
else if (element instanceof TemplateCategory) {
// Note: ONLY clear the selected template if the
// selection is a template category.
// Do not clear the template if there is an empty
// selection in the tree, as there
// are times when the viewer
// will set an empty selection in the tree due to a
// refresh operation, and if
// a template was already selected prior to that refresh
// request, it should not be
// overwritten with null as other operations will
// require that the selected template not be changed
setSeletectedTemplate(null);
}
}
}
});
this.contentManagerListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
ContentManager manager = event.getSource() instanceof ContentManager ? (ContentManager) event
.getSource() : null;
final boolean hasTemplateContentChanged = manager != null && manager.isDirty();
if (hasTemplateContentChanged) {
clearTemplateSelection();
// Only reinitialise templates if the manager is marked as
// dirty, as template contents may have changed, therefore
// new templates
// need to be created in the tree viewer
initialiseTemplatesFromContentManager();
}
// switch to UI thread to refresh the UI controls
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
public void run() {
refreshPage(hasTemplateContentChanged);
}
});
}
};
ContentManager manager = ContentPlugin.getDefault().getManager();
manager.addListener(contentManagerListener);
// This does not automatically add the templates to the tree viewer
// input.
// Rather it downloads templates asynchronously, and the content manager
// will then notify the tree viewer when the content is available and at
// that time
// refresh the tree input
downloadDescriptors();
expandCategory(SIMPLE_PROJECTS_CATEGORY);
return container;
}
protected void clearTemplateSelection() {
// Run synch in UI thread as it is most likely called from a non-worker
// thread
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
public void run() {
// clear any selection in the tree viewer as well.
if (treeViewer != null && !treeViewer.getTree().isDisposed()) {
treeViewer.setSelection(null);
}
setSeletectedTemplate(null);
}
});
}
protected void expandCategory(final String categoryName) {
// Run in UI
if (treeViewer == null || treeViewer.getTree().isDisposed()) {
return;
}
TreeItem[] items = treeViewer.getTree().getItems();
if (items != null) {
for (TreeItem item : items) {
Object itemObj = item.getData();
if (itemObj instanceof TemplateCategory && ((TemplateCategory) itemObj).getName().equals(categoryName)) {
// Note that calling expand on the tree item itself would
// not work, because at this stage
// the tree viewer content provider may not have yet
// contributed children to the category element
// and therefore the category tree item may not have
// corresponding tree item children to display.
// Instead, expand through the treeViewer rather than
// through the tree item, as the treeViewer expand request
// will trigger the content provider to create children for
// the category tree item.
treeViewer.expandToLevel(itemObj, 1);
break;
}
}
}
}
/**
* Refreshes list of descriptors, and clears any current template selection.
* This is to avoid retaining template selections that may no longer be up
* to date.
*/
protected void downloadDescriptors() {
// Must execute as an asynch in UI thread to avoid Invalid UI
// thread
// exceptions
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
final String[] error = new String[1];
final Exception[] e = new Exception[1];
try {
wizard.getContainer().run(true, true, new DownloadDescriptorJob());
}
catch (InvocationTargetException ie) {
e[0] = ie;
error[0] = ErrorUtils.getErrorMessage("Failed to download template descriptors", e[0]);
}
catch (InterruptedException inte) {
e[0] = inte;
error[0] = "Download of descriptors interrupted";
}
if (error[0] != null && e[0] != null) {
setError(error[0], e[0]);
}
}
});
}
protected void setSeletectedTemplate(Template template) {
model.selectedTemplate.setValue(template);
if (template != null) {
setDescription(template);
}
notifyStatusChange(validateArea());
}
@Override
protected IStatus validateArea() {
Template template = model.selectedTemplate.getValue();
IStatus status = Status.OK_STATUS;
if (template != null) {
String warning = getWarning(template);
// Warnings apply to both Simple Projects and templates
if (warning != null) {
status = createStatus(warning, IStatus.WARNING);
}
else if (!(template instanceof SimpleProject)) {
String message = "Click 'Next' to load the template contents.";
status = createStatus(message, IStatus.INFO);
}
// For the purposes of selecting a template, if it is not null, the
// area is complete.
// Other sections in the wizard may provider additional validation
// on the template, but it is not the responsibility of the template
// selection
// area to provide validation beyond just selecting a template
setAreaComplete(true);
}
else {
setAreaComplete(false);
status = createStatus("Please select a template.", IStatus.INFO);
}
return status;
}
protected void setError(String error, Throwable t) {
notifyStatusChange(new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, error, t), false);
}
protected void setError(IStatus error) {
notifyStatusChange(error, false);
}
/**
* This initialises the templates directly from the content manager with
* updated information. Any existing selections in the model are also
* removed, as that template may no longer be valid.
*
* Note that is is sometimes run in a worker thread, therefore any UI
* callbacks must be performed as UI jobs.
*
*/
private void initialiseTemplatesFromContentManager() {
templates.clear();
TemplatesPreferencesModel model = TemplatesPreferencesModel.getInstance();
Collection<ContentItem> items = ContentPlugin.getDefault().getManager()
.getItemsByKind(ContentManager.KIND_TEMPLATE);
List<ContentItem> sortedItems = new ArrayList<ContentItem>();
sortedItems.addAll(items);
Collections.sort(sortedItems, new Comparator<ContentItem>() {
public int compare(ContentItem o1, ContentItem o2) {
Descriptor descriptor1 = o1.getRemoteDescriptor();
if (descriptor1 == null) {
descriptor1 = o1.getLocalDescriptor();
}
Descriptor descriptor2 = o2.getRemoteDescriptor();
if (descriptor2 == null) {
descriptor2 = o2.getLocalDescriptor();
}
return descriptor1.getVersion().compareTo(descriptor2.getVersion()) * -1;
}
});
Set<String> templateIds = new HashSet<String>();
for (ContentItem item : sortedItems) {
String templateId = item.getId();
if (!templateIds.contains(templateId)) {
Template template = new Template(item, null);
templates.add(template);
templateIds.add(templateId);
}
}
// Add the Simple Projects
List<SimpleProject> simpleProjects = getSimpleProjects();
templates.addAll(simpleProjects);
if (model.shouldShowSelfHostedProjects()) {
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
for (IProject project : projects) {
IFile templateFile = project.getFile(IContentConstants.TEMPLATE_DATA_FILE_NAME);
IFile wizardFile = project.getFile(IContentConstants.WIZARD_DATA_FILE_NAME);
if (templateFile.exists() && wizardFile.exists()) {
File file = templateFile.getLocation().toFile();
try {
DocumentBuilder documentBuilder = ContentUtil.createDocumentBuilder();
Document document = documentBuilder.parse(file);
Element rootNode = document.getDocumentElement();
if (rootNode != null) {
NodeList children = rootNode.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node childNode = children.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
if ("descriptor".equals(childNode.getNodeName())) {
Descriptor descriptor = Descriptor.read(childNode);
ContentItem item = new ContentItem(descriptor.getId(), project);
item.setLocalDescriptor(descriptor);
descriptor.setUrl(project.getName());
ImageDescriptor icon = null;
Template template = new Template(item, icon);
templates.add(template);
}
}
}
}
}
catch (CoreException e) {
String message = NLS.bind("Error getting and parsing descriptors file in background {0}",
e.getMessage());
MessageDialog.openWarning(wizard.getContainer().getShell(), "Warning", message);
}
catch (SAXException e) {
String message = NLS.bind("Error parsing tmp descriptors file at {0} in background.\n{1}",
file, e.getMessage());
MessageDialog.openWarning(wizard.getContainer().getShell(), "Warning", message);
}
catch (IOException e) {
String message = NLS.bind("IO error on file at {0} opened in background.\n{1}", file,
e.getMessage());
MessageDialog.openWarning(wizard.getContainer().getShell(), "Warning", message);
}
}
}
}
Collections.sort(templates, new Comparator<Template>() {
public int compare(Template t1, Template t2) {
return t1.getName().compareTo(t2.getName());
}
});
}
/**
* Returns non-null list of Simple Projects. If errors occur while resolving
* simple projects, an empty list is returned, and error logged in the
* container of the part
*/
protected List<SimpleProject> getSimpleProjects() {
final List<SimpleProject> projects = new ArrayList<SimpleProject>();
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
public void run() {
final String[] error = new String[1];
final Exception[] exception = new Exception[1];
try {
IRunnableWithProgress runnable = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
try {
List<SimpleProject> prj = SimpleProjectContentManager.getManager().getSimpleProjects(
monitor);
projects.addAll(prj);
}
catch (CoreException e) {
throw new InvocationTargetException(e);
}
}
};
wizard.getContainer().run(false, false, runnable);
}
catch (InvocationTargetException e) {
error[0] = ErrorUtils.getErrorMessage("Failed to load Simple Project template content", e);
exception[0] = e;
}
catch (InterruptedException e) {
error[0] = "Failure while loading Simple Project templates due to interrupt exception. Template content may not have been loaded correctly.";
exception[0] = e;
}
if (error[0] != null && exception[0] != null) {
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
public void run() {
setError(error[0], exception[0]);
}
});
}
}
});
return projects;
}
private void refreshPage(boolean refreshAll) {
// The content may have changed (e.g. if templates manually refreshed by
// the user)
// therefore invoke the content provider again to refresh the contents
// of the tree viewer
// with the new contents.
if (refreshAll) {
treeViewer.refresh(true);
boolean needsDownload = false;
for (Template template : templates) {
if (!(template instanceof SimpleProject) && !template.getItem().isLocal()) {
needsDownload = true;
break;
}
}
expandCategory(SIMPLE_PROJECTS_CATEGORY);
legendImage.setVisible(needsDownload);
legendText.setVisible(needsDownload);
descriptionText.setText(""); //$NON-NLS-1$
refreshButton.setEnabled(true);
}
else {
refreshSelectedTemplateInViewer();
}
}
public void refreshSelectedTemplateInViewer() {
Template selectedTemplate = model.selectedTemplate.getValue();
if (selectedTemplate != null && treeViewer != null && !treeViewer.getTree().isDisposed()) {
treeViewer.refresh(selectedTemplate, true);
treeViewer.setSelection(new StructuredSelection(selectedTemplate), true);
}
}
private void setDescription(Template template) {
String description = null;
if (template != null) {
description = template.getDescription();
// Do not show URL for Simple Projects
if (!(template instanceof SimpleProject) && template.getItem().getRemoteDescriptor() != null) {
description += "\n\nURL:" + template.getItem().getRemoteDescriptor().getUrl();
}
}
if (description != null) {
descriptionText.setText(description);
}
else {
descriptionText.setText(""); //$NON-NLS-1$
}
descriptionText.redraw();
}
private String getWarning(Template template) {
String requiredBundleStr = null;
ContentItem contentItem = template.getItem();
if (contentItem.getLocalDescriptor() != null) {
requiredBundleStr = contentItem.getLocalDescriptor().getRequiresBundle();
}
if (requiredBundleStr == null && contentItem.getRemoteDescriptor() != null) {
requiredBundleStr = contentItem.getRemoteDescriptor().getRequiresBundle();
}
StringBuilder missingBundleStr = new StringBuilder();
if (requiredBundleStr != null) {
String[] requiredBundles = requiredBundleStr.split(",");
for (String requiredBundle : requiredBundles) {
if (Platform.getBundle(requiredBundle.trim()) == null) {
if (missingBundleStr.length() > 0) {
missingBundleStr.append(", ");
}
missingBundleStr.append(requiredBundle.trim());
}
}
}
if (missingBundleStr.length() > 0) {
String message = NLS.bind("To ensure project compiles properly, please install bundle(s) {0}.",
missingBundleStr);
return message;
}
return null;
}
public void dispose() {
Assert.isNotNull(contentManagerListener);
ContentPlugin.getDefault().getManager().removeListener(contentManagerListener);
}
private boolean isRefreshing() {
return ContentPlugin.getDefault().getManager().isRefreshing();
}
}