/******************************************************************************* * Copyright (c) 2009, 2015 Tasktop Technologies 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: * Tasktop Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.discovery.ui.wizards; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; 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.MultiStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.resource.ColorRegistry; import org.eclipse.jface.resource.FontDescriptor; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.IShellProvider; import org.eclipse.mylyn.commons.ui.CommonImages; import org.eclipse.mylyn.commons.ui.GradientCanvas; import org.eclipse.mylyn.commons.ui.SelectionProviderAdapter; import org.eclipse.mylyn.commons.ui.compatibility.CommonThemes; import org.eclipse.mylyn.commons.workbench.browser.BrowserUtil; import org.eclipse.mylyn.internal.discovery.core.model.AbstractDiscoverySource; import org.eclipse.mylyn.internal.discovery.core.model.BundleDiscoveryStrategy; import org.eclipse.mylyn.internal.discovery.core.model.ConnectorDescriptor; import org.eclipse.mylyn.internal.discovery.core.model.ConnectorDescriptorKind; import org.eclipse.mylyn.internal.discovery.core.model.ConnectorDiscovery; import org.eclipse.mylyn.internal.discovery.core.model.DiscoveryCategory; import org.eclipse.mylyn.internal.discovery.core.model.DiscoveryConnector; import org.eclipse.mylyn.internal.discovery.core.model.Icon; import org.eclipse.mylyn.internal.discovery.core.model.Overview; import org.eclipse.mylyn.internal.discovery.core.model.RemoteBundleDiscoveryStrategy; import org.eclipse.mylyn.internal.discovery.core.util.DiscoveryCategoryComparator; import org.eclipse.mylyn.internal.discovery.core.util.DiscoveryConnectorComparator; import org.eclipse.mylyn.internal.discovery.ui.DiscoveryImages; import org.eclipse.mylyn.internal.discovery.ui.DiscoveryUi; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.accessibility.ACC; import org.eclipse.swt.accessibility.AccessibleAdapter; import org.eclipse.swt.accessibility.AccessibleControlAdapter; import org.eclipse.swt.accessibility.AccessibleControlEvent; import org.eclipse.swt.accessibility.AccessibleEvent; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseTrackListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.Resource; 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.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.browser.IWorkbenchBrowserSupport; import org.eclipse.ui.forms.IFormColors; import org.eclipse.ui.progress.WorkbenchJob; import org.eclipse.ui.statushandlers.StatusManager; import org.eclipse.ui.themes.IThemeManager; import org.osgi.framework.Bundle; import org.osgi.framework.Version; /** * The main wizard page that allows users to select connectors that they wish to install. * * @author David Green * @author Steffen Pingel */ public class DiscoveryViewer { public class ConnectorBorderPaintListener implements PaintListener { public void paintControl(PaintEvent e) { Composite composite = (Composite) e.widget; Rectangle bounds = composite.getBounds(); GC gc = e.gc; gc.setLineStyle(SWT.LINE_DOT); gc.drawLine(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y); } } private class ConnectorDescriptorItemUi implements PropertyChangeListener, Runnable { private final DiscoveryConnector connector; private final Button checkbox; private final Label iconLabel; private final Label nameLabel; private ToolItem infoButton; private final Link providerLabel; private final Label description; private final Composite checkboxAndIconContainer; private final Composite checkboxContainer; private final Composite connectorContainer; private final Display display; private Image iconImage; // private Image warningIconImage; public ConnectorDescriptorItemUi(final DiscoveryConnector connector, Composite categoryChildrenContainer, Color background) { display = categoryChildrenContainer.getDisplay(); this.connector = connector; connector.addPropertyChangeListener(this); connectorContainer = new Composite(categoryChildrenContainer, SWT.NULL); configureLook(connectorContainer, background); GridDataFactory.fillDefaults().grab(true, false).applyTo(connectorContainer); GridLayout layout = new GridLayout(4, false); layout.marginLeft = 7; layout.marginTop = 2; layout.marginBottom = 2; connectorContainer.setLayout(layout); checkboxAndIconContainer = new Composite(connectorContainer, SWT.NULL); configureLook(checkboxAndIconContainer, background); GridDataFactory.swtDefaults().align(SWT.CENTER, SWT.BEGINNING).span(1, 2).applyTo(checkboxAndIconContainer); GridLayoutFactory.fillDefaults().spacing(1, 1).numColumns(2).applyTo(checkboxAndIconContainer); checkboxContainer = new Composite(checkboxAndIconContainer, SWT.NULL); GridLayout checkboxLayout = new GridLayout(1, false); checkboxLayout.marginRight = 7; checkboxContainer.setLayout(checkboxLayout); configureLook(checkboxContainer, background); checkbox = new Button(checkboxContainer, SWT.CHECK); // help UI tests checkbox.setData("connectorId", connector.getId()); //$NON-NLS-1$ checkbox.setVisible(connector.isInstallable()); checkbox.setSelection(installableConnectors.contains(connector)); checkbox.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { bodyScrolledComposite.showControl(connectorContainer); } }); GridDataFactory.swtDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(checkbox); iconLabel = new Label(checkboxAndIconContainer, SWT.NULL); configureLook(iconLabel, background); GridDataFactory.swtDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(iconLabel); if (connector.getIcon() != null) { iconImage = computeIconImage(connector.getSource(), connector.getIcon(), 32, false); if (iconImage != null) { iconLabel.setImage(iconImage); } } nameLabel = new Label(connectorContainer, SWT.NULL); configureLook(nameLabel, background); GridDataFactory.fillDefaults().grab(true, false).align(SWT.BEGINNING, SWT.CENTER).applyTo(nameLabel); nameLabel.setFont(h2Font); if (connector.isInstalled()) { nameLabel.setText(NLS.bind(Messages.DiscoveryViewer_X_installed, connector.getName())); } else { nameLabel.setText(connector.getName()); } providerLabel = new Link(connectorContainer, SWT.RIGHT); configureLook(providerLabel, background); GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(providerLabel); if (connector.getCertification() != null) { providerLabel.setText(NLS.bind(Messages.DiscoveryViewer_Certification_Label0, new String[] { connector.getProvider(), connector.getLicense(), connector.getCertification().getName() })); if (connector.getCertification().getUrl() != null) { providerLabel.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { BrowserUtil.openUrl(connector.getCertification().getUrl(), IWorkbenchBrowserSupport.AS_EXTERNAL); } }); } Overview overview = new Overview(); overview.setSummary(connector.getCertification().getDescription()); overview.setUrl(connector.getCertification().getUrl()); Image image = computeIconImage(connector.getSource(), connector.getCertification().getIcon(), 48, true); hookTooltip(providerLabel, providerLabel, connectorContainer, providerLabel, connector.getSource(), overview, image); } else { providerLabel.setText(NLS.bind(Messages.ConnectorDiscoveryWizardMainPage_provider_and_license, connector.getProvider(), connector.getLicense())); } if (hasTooltip(connector)) { ToolBar toolBar = new ToolBar(connectorContainer, SWT.FLAT); toolBar.setBackground(background); infoButton = new ToolItem(toolBar, SWT.PUSH); infoButton.setImage(infoImage); infoButton.setToolTipText(Messages.ConnectorDiscoveryWizardMainPage_tooltip_showOverview); hookTooltip(toolBar, infoButton, connectorContainer, nameLabel, connector.getSource(), connector.getOverview(), null); GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(toolBar); } else { Label label = new Label(connectorContainer, SWT.NULL); label.setText(" "); //$NON-NLS-1$ configureLook(label, background); } description = new Label(connectorContainer, SWT.NULL | SWT.WRAP); configureLook(description, background); GridDataFactory.fillDefaults().grab(true, false).span(3, 1).hint(100, SWT.DEFAULT).applyTo(description); String descriptionText = connector.getDescription(); int maxDescriptionLength = 162; if (descriptionText.length() > maxDescriptionLength) { descriptionText = descriptionText.substring(0, maxDescriptionLength); } description.setText(descriptionText.replaceAll("(\\r\\n)|\\n|\\r", " ")); //$NON-NLS-1$ //$NON-NLS-2$ // always disabled color to make it less prominent providerLabel.setForeground(colorDisabled); checkbox.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } public void widgetSelected(SelectionEvent e) { boolean selected = checkbox.getSelection(); maybeModifySelection(selected); } }); MouseListener connectorItemMouseListener = new MouseAdapter() { @Override public void mouseUp(MouseEvent e) { boolean selected = !checkbox.getSelection(); if (maybeModifySelection(selected)) { checkbox.setSelection(selected); } } }; checkboxAndIconContainer.addMouseListener(connectorItemMouseListener); checkboxContainer.addMouseListener(connectorItemMouseListener); connectorContainer.addMouseListener(connectorItemMouseListener); iconLabel.addMouseListener(connectorItemMouseListener); nameLabel.addMouseListener(connectorItemMouseListener); // the provider has clickable links //providerLabel.addMouseListener(connectorItemMouseListener); description.addMouseListener(connectorItemMouseListener); } protected boolean maybeModifySelection(boolean selected) { if (selected) { if (connector.isInstalled()) { MessageDialog.openWarning(shellProvider.getShell(), Messages.DiscoveryViewer_Install_Connector_Title, NLS.bind(Messages.DiscoveryViewer_Already_installed_Error, connector.getName())); return false; } if (!connector.isInstallable()) { if (connector.getInstallMessage() != null) { MessageDialog.openInformation(shellProvider.getShell(), Messages.DiscoveryViewer_Install_Connector_Title, connector.getInstallMessage()); } return false; } if (connector.getAvailable() != null && !connector.getAvailable()) { MessageDialog.openWarning(shellProvider.getShell(), Messages.ConnectorDiscoveryWizardMainPage_warningTitleConnectorUnavailable, NLS.bind( Messages.ConnectorDiscoveryWizardMainPage_warningMessageConnectorUnavailable, connector.getName())); return false; } } DiscoveryViewer.this.modifySelection(connector, selected); return true; } public void propertyChange(PropertyChangeEvent evt) { display.asyncExec(this); } public void run() { if (!connectorContainer.isDisposed()) { updateAvailability(); } } public void updateAvailability() { boolean enabled = !connector.isInstalled() && (connector.getAvailable() == null || connector.getAvailable()); checkbox.setEnabled(enabled); nameLabel.setEnabled(enabled); providerLabel.setEnabled(enabled); description.setEnabled(enabled); Color foreground; if (enabled) { foreground = connectorContainer.getForeground(); } else { foreground = colorDisabled; } nameLabel.setForeground(foreground); description.setForeground(foreground); if (iconImage != null) { // boolean unavailable = !enabled && connector.getAvailable() != null; // if (unavailable) { // if (warningIconImage == null) { // warningIconImage = new DecorationOverlayIcon(iconImage, DiscoveryImages.OVERLAY_WARNING_32, // IDecoration.BOTTOM_RIGHT).createImage(); // disposables.add(warningIconImage); // } // iconLabel.setImage(warningIconImage); // } else if (warningIconImage != null) { iconLabel.setImage(iconImage); // } } } } private static final int MINIMUM_HEIGHT = 100; private static boolean useNativeSearchField(Composite composite) { if (useNativeSearchField == null) { useNativeSearchField = Boolean.FALSE; Text testText = null; try { testText = new Text(composite, SWT.SEARCH | SWT.ICON_CANCEL); useNativeSearchField = Boolean.valueOf((testText.getStyle() & SWT.ICON_CANCEL) != 0); } finally { if (testText != null) { testText.dispose(); } } } return useNativeSearchField; } private boolean showConnectorDescriptorKindFilter; private boolean showConnectorDescriptorTextFilter; private static final String COLOR_WHITE = "white"; //$NON-NLS-1$ private static final String COLOR_DARK_GRAY = "DarkGray"; //$NON-NLS-1$ private static Boolean useNativeSearchField; private final List<ConnectorDescriptor> installableConnectors = new ArrayList<ConnectorDescriptor>(); private volatile ConnectorDiscovery discovery; private Composite body; private final List<Resource> disposables; private Font h2Font; private Font h1Font; private Color colorWhite; private Text filterText; private WorkbenchJob refreshJob; private String previousFilterText = ""; //$NON-NLS-1$ private Pattern filterPattern; private Label clearFilterTextControl; private Set<String> installedFeatures; private Image infoImage; private Cursor handCursor; private Color colorCategoryGradientStart; private Color colorCategoryGradientEnd; private Color colorDisabled; private ScrolledComposite bodyScrolledComposite; private boolean verifyUpdateSiteAvailability; private final Map<ConnectorDescriptorKind, Boolean> connectorDescriptorKindToVisibility = new HashMap<ConnectorDescriptorKind, Boolean>(); { for (ConnectorDescriptorKind kind : ConnectorDescriptorKind.values()) { connectorDescriptorKindToVisibility.put(kind, true); } } private Dictionary<Object, Object> environment; private boolean complete; private final IRunnableContext context; private final IShellProvider shellProvider; private Control control; private String directoryUrl; private final SelectionProviderAdapter selectionProvider; private List<DiscoveryConnector> allConnectors; private int minimumHeight; private final List<ViewerFilter> filters = new ArrayList<ViewerFilter>(); private boolean showInstalledFilterEnabled; private boolean showInstalled; public DiscoveryViewer(IShellProvider shellProvider, IRunnableContext context) { this.shellProvider = shellProvider; this.context = context; this.selectionProvider = new SelectionProviderAdapter(); this.allConnectors = Collections.emptyList(); this.disposables = new ArrayList<Resource>(); setShowConnectorDescriptorKindFilter(true); setShowConnectorDescriptorTextFilter(true); setMinimumHeight(MINIMUM_HEIGHT); createEnvironment(); setComplete(false); } public void addSelectionChangedListener(ISelectionChangedListener listener) { selectionProvider.addSelectionChangedListener(listener); } private void clearDisposables() { disposables.clear(); h1Font = null; h2Font = null; infoImage = null; handCursor = null; colorCategoryGradientStart = null; colorCategoryGradientEnd = null; } private void clearFilterText() { filterText.setText(""); //$NON-NLS-1$ filterTextChanged(); } private Image computeIconImage(AbstractDiscoverySource discoverySource, Icon icon, int dimension, boolean fallback) { String imagePath; switch (dimension) { case 64: imagePath = icon.getImage64(); if (imagePath != null || !fallback) { break; } case 48: imagePath = icon.getImage48(); if (imagePath != null || !fallback) { break; } case 32: imagePath = icon.getImage32(); break; default: throw new IllegalArgumentException(); } if (imagePath != null && imagePath.length() > 0) { URL resource = discoverySource.getResource(imagePath); if (resource != null) { ImageDescriptor descriptor = ImageDescriptor.createFromURL(resource); Image image = descriptor.createImage(); if (image != null) { disposables.add(image); return image; } } } return null; } private IStatus computeStatus(InvocationTargetException e, String message) { Throwable cause = e.getCause(); IStatus statusCause; if (cause instanceof CoreException) { statusCause = ((CoreException) cause).getStatus(); } else { statusCause = new Status(IStatus.ERROR, DiscoveryUi.ID_PLUGIN, cause.getMessage(), cause); } if (statusCause.getMessage() != null) { message = NLS.bind(Messages.ConnectorDiscoveryWizardMainPage_message_with_cause, message, statusCause.getMessage()); } IStatus status = new MultiStatus(DiscoveryUi.ID_PLUGIN, 0, new IStatus[] { statusCause }, message, cause); return status; } private void configureLook(Control control, Color background) { control.setBackground(background); } /** * cause the UI to respond to a change in visibility filters * * @see #setVisibility(ConnectorDescriptorKind, boolean) */ public void connectorDescriptorKindVisibilityUpdated() { createBodyContents(); } public void createBodyContents() { // remove any existing contents for (Control child : body.getChildren()) { child.dispose(); } clearDisposables(); allConnectors = new ArrayList<DiscoveryConnector>(); initializeCursors(); initializeImages(); initializeFonts(); initializeColors(); GridLayoutFactory.fillDefaults().applyTo(body); bodyScrolledComposite = new ScrolledComposite(body, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); configureLook(bodyScrolledComposite, colorWhite); GridDataFactory.fillDefaults().grab(true, true).applyTo(bodyScrolledComposite); final Composite scrolledContents = new Composite(bodyScrolledComposite, SWT.NONE); configureLook(scrolledContents, colorWhite); scrolledContents.setRedraw(false); try { createDiscoveryContents(scrolledContents); } finally { scrolledContents.layout(true); scrolledContents.setRedraw(true); } Point size = scrolledContents.computeSize(body.getSize().x, SWT.DEFAULT, true); scrolledContents.setSize(size); bodyScrolledComposite.setExpandHorizontal(true); bodyScrolledComposite.setMinWidth(100); bodyScrolledComposite.setExpandVertical(true); bodyScrolledComposite.setMinHeight(1); bodyScrolledComposite.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { // XXX small offset in case list has a scroll bar Point size = scrolledContents.computeSize(body.getSize().x - 20, SWT.DEFAULT, true); scrolledContents.setSize(size); bodyScrolledComposite.setMinHeight(size.y); } }); bodyScrolledComposite.setContent(scrolledContents); Dialog.applyDialogFont(body); // we've changed it so it needs to know body.layout(true); } private Label createClearFilterTextControl(Composite filterContainer, final Text filterText) { final Image inactiveImage = CommonImages.FIND_CLEAR_DISABLED.createImage(); final Image activeImage = CommonImages.FIND_CLEAR.createImage(); final Image pressedImage = new Image(filterContainer.getDisplay(), activeImage, SWT.IMAGE_GRAY); final Label clearButton = new Label(filterContainer, SWT.NONE); clearButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); clearButton.setImage(inactiveImage); clearButton.setToolTipText(Messages.ConnectorDiscoveryWizardMainPage_clearButton_toolTip); clearButton.setBackground(filterContainer.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); clearButton.addMouseListener(new MouseAdapter() { private MouseMoveListener fMoveListener; private boolean isMouseInButton(MouseEvent e) { Point buttonSize = clearButton.getSize(); return 0 <= e.x && e.x < buttonSize.x && 0 <= e.y && e.y < buttonSize.y; } @Override public void mouseDown(MouseEvent e) { clearButton.setImage(pressedImage); fMoveListener = new MouseMoveListener() { private boolean fMouseInButton = true; public void mouseMove(MouseEvent e) { boolean mouseInButton = isMouseInButton(e); if (mouseInButton != fMouseInButton) { fMouseInButton = mouseInButton; clearButton.setImage(mouseInButton ? pressedImage : inactiveImage); } } }; clearButton.addMouseMoveListener(fMoveListener); } @Override public void mouseUp(MouseEvent e) { if (fMoveListener != null) { clearButton.removeMouseMoveListener(fMoveListener); fMoveListener = null; boolean mouseInButton = isMouseInButton(e); clearButton.setImage(mouseInButton ? activeImage : inactiveImage); if (mouseInButton) { clearFilterText(); filterText.setFocus(); } } } }); clearButton.addMouseTrackListener(new MouseTrackListener() { public void mouseEnter(MouseEvent e) { clearButton.setImage(activeImage); } public void mouseExit(MouseEvent e) { clearButton.setImage(inactiveImage); } public void mouseHover(MouseEvent e) { } }); clearButton.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { inactiveImage.dispose(); activeImage.dispose(); pressedImage.dispose(); } }); clearButton.getAccessible().addAccessibleListener(new AccessibleAdapter() { @Override public void getName(AccessibleEvent e) { e.result = Messages.ConnectorDiscoveryWizardMainPage_clearButton_accessibleListener; } }); clearButton.getAccessible().addAccessibleControlListener(new AccessibleControlAdapter() { @Override public void getRole(AccessibleControlEvent e) { e.detail = ACC.ROLE_PUSHBUTTON; } }); return clearButton; } public void createControl(Composite parent) { createRefreshJob(); Composite container = new Composite(parent, SWT.NULL); container.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { refreshJob.cancel(); if (disposables != null) { for (Resource resource : disposables) { resource.dispose(); } clearDisposables(); } if (discovery != null) { discovery.dispose(); } } }); GridLayout layout = new GridLayout(1, false); layout.marginHeight = 0; layout.marginWidth = 0; container.setLayout(layout); // { // header Composite header = new Composite(container, SWT.NULL); GridLayoutFactory.fillDefaults().applyTo(header); GridDataFactory.fillDefaults().grab(true, false).applyTo(header); // TODO: refresh button? if (isShowConnectorDescriptorKindFilter() || isShowConnectorDescriptorTextFilter()) { Composite filterContainer = new Composite(header, SWT.NULL); GridDataFactory.fillDefaults().grab(true, false).applyTo(filterContainer); Label label = new Label(filterContainer, SWT.NULL); label.setText(Messages.ConnectorDiscoveryWizardMainPage_filterLabel); if (isShowConnectorDescriptorTextFilter()) { Composite textFilterContainer; boolean nativeSearch = useNativeSearchField(header); if (nativeSearch) { textFilterContainer = new Composite(filterContainer, SWT.NULL); } else { textFilterContainer = new Composite(filterContainer, SWT.BORDER); textFilterContainer.setBackground(header.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); } GridDataFactory.fillDefaults().grab(true, false).applyTo(textFilterContainer); GridLayoutFactory.fillDefaults().numColumns(2).applyTo(textFilterContainer); if (nativeSearch) { filterText = new Text(textFilterContainer, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL); } else { filterText = new Text(textFilterContainer, SWT.SINGLE); } filterText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { filterTextChanged(); } }); if (nativeSearch) { filterText.addSelectionListener(new SelectionAdapter() { @Override public void widgetDefaultSelected(SelectionEvent e) { if (e.detail == SWT.ICON_CANCEL) { clearFilterText(); } } }); GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(filterText); } else { GridDataFactory.fillDefaults().grab(true, false).applyTo(filterText); clearFilterTextControl = createClearFilterTextControl(textFilterContainer, filterText); clearFilterTextControl.setVisible(false); } } if (isShowInstalledFilterEnabled()) { final Button checkbox = new Button(filterContainer, SWT.CHECK); checkbox.setSelection(false); checkbox.setText(Messages.DiscoveryViewer_Show_Installed); checkbox.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } public void widgetSelected(SelectionEvent e) { setShowInstalled(checkbox.getSelection()); } }); } if (isShowConnectorDescriptorKindFilter()) { // filter // buttons for (final ConnectorDescriptorKind kind : ConnectorDescriptorKind.values()) { final Button checkbox = new Button(filterContainer, SWT.CHECK); checkbox.setSelection(isVisible(kind)); checkbox.setText(getFilterLabel(kind)); checkbox.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } public void widgetSelected(SelectionEvent e) { boolean selection = checkbox.getSelection(); setVisibility(kind, selection); connectorDescriptorKindVisibilityUpdated(); } }); } } GridLayoutFactory.fillDefaults() .numColumns(filterContainer.getChildren().length) .applyTo(filterContainer); } } { // container body = new Composite(container, SWT.NULL); GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, minimumHeight).applyTo(body); } Dialog.applyDialogFont(container); setControl(container); } public void setMinimumHeight(int minimumHeight) { this.minimumHeight = minimumHeight; if (body != null) { GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, minimumHeight).applyTo(body); } } public static int getMinimumHeight() { return MINIMUM_HEIGHT; } private void createDiscoveryContents(Composite container) { Color background = container.getBackground(); if (discovery == null || isEmpty(discovery)) { GridLayoutFactory.fillDefaults().margins(5, 5).applyTo(container); boolean atLeastOneKindFiltered = false; for (ConnectorDescriptorKind kind : ConnectorDescriptorKind.values()) { if (!isVisible(kind)) { atLeastOneKindFiltered = true; break; } } Control helpTextControl; if (filterPattern != null) { Link link = new Link(container, SWT.WRAP); link.setFont(container.getFont()); link.setText(Messages.ConnectorDiscoveryWizardMainPage_noMatchingItems_withFilterText); link.addListener(SWT.Selection, new Listener() { public void handleEvent(Event event) { clearFilterText(); filterText.setFocus(); } }); helpTextControl = link; } else { Label helpText = new Label(container, SWT.WRAP); helpText.setFont(container.getFont()); if (atLeastOneKindFiltered) { helpText.setText(Messages.ConnectorDiscoveryWizardMainPage_noMatchingItems_filteredType); } else { helpText.setText(Messages.ConnectorDiscoveryWizardMainPage_noMatchingItems_noFilter); } helpTextControl = helpText; } configureLook(helpTextControl, background); GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).applyTo(helpTextControl); } else { GridLayoutFactory.fillDefaults().numColumns(2).spacing(0, 0).applyTo(container); List<DiscoveryCategory> categories = new ArrayList<DiscoveryCategory>(discovery.getCategories()); Collections.sort(categories, new DiscoveryCategoryComparator()); Composite categoryChildrenContainer = null; for (DiscoveryCategory category : categories) { if (isEmpty(category)) { // don't add empty categories continue; } { // category header final GradientCanvas categoryHeaderContainer = new GradientCanvas(container, SWT.NONE); categoryHeaderContainer.setSeparatorVisible(true); categoryHeaderContainer.setSeparatorAlignment(SWT.TOP); categoryHeaderContainer.setBackgroundGradient(new Color[] { colorCategoryGradientStart, colorCategoryGradientEnd }, new int[] { 100 }, true); categoryHeaderContainer.putColor(IFormColors.H_BOTTOM_KEYLINE1, colorCategoryGradientStart); categoryHeaderContainer.putColor(IFormColors.H_BOTTOM_KEYLINE2, colorCategoryGradientEnd); GridDataFactory.fillDefaults().span(2, 1).applyTo(categoryHeaderContainer); GridLayoutFactory.fillDefaults() .numColumns(3) .margins(5, 5) .equalWidth(false) .applyTo(categoryHeaderContainer); Label iconLabel = new Label(categoryHeaderContainer, SWT.NULL); if (category.getIcon() != null) { Image image = computeIconImage(category.getSource(), category.getIcon(), 48, true); if (image != null) { iconLabel.setImage(image); } } iconLabel.setBackground(null); GridDataFactory.swtDefaults().align(SWT.CENTER, SWT.BEGINNING).span(1, 2).applyTo(iconLabel); Label nameLabel = new Label(categoryHeaderContainer, SWT.NULL); nameLabel.setFont(h1Font); nameLabel.setText(category.getName()); nameLabel.setBackground(null); GridDataFactory.fillDefaults().grab(true, false).applyTo(nameLabel); if (hasTooltip(category)) { ToolBar toolBar = new ToolBar(categoryHeaderContainer, SWT.FLAT); toolBar.setBackground(null); ToolItem infoButton = new ToolItem(toolBar, SWT.PUSH); infoButton.setImage(infoImage); infoButton.setToolTipText(Messages.ConnectorDiscoveryWizardMainPage_tooltip_showOverview); hookTooltip(toolBar, infoButton, categoryHeaderContainer, nameLabel, category.getSource(), category.getOverview(), null); GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(toolBar); } else { new Label(categoryHeaderContainer, SWT.NULL).setText(" "); //$NON-NLS-1$ } Label description = new Label(categoryHeaderContainer, SWT.WRAP); GridDataFactory.fillDefaults() .grab(true, false) .span(2, 1) .hint(100, SWT.DEFAULT) .applyTo(description); description.setBackground(null); description.setText(category.getDescription()); } categoryChildrenContainer = new Composite(container, SWT.NULL); configureLook(categoryChildrenContainer, background); GridDataFactory.fillDefaults().span(2, 1).grab(true, false).applyTo(categoryChildrenContainer); GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(categoryChildrenContainer); int numChildren = 0; List<DiscoveryConnector> connectors = new ArrayList<DiscoveryConnector>(category.getConnectors()); Collections.sort(connectors, new DiscoveryConnectorComparator(category)); for (final DiscoveryConnector connector : connectors) { if (isFiltered(connector)) { continue; } if (++numChildren > 1) { // a separator between connector descriptors Composite border = new Composite(categoryChildrenContainer, SWT.NULL); GridDataFactory.fillDefaults().grab(true, false).hint(SWT.DEFAULT, 1).applyTo(border); GridLayoutFactory.fillDefaults().applyTo(border); border.addPaintListener(new ConnectorBorderPaintListener()); } ConnectorDescriptorItemUi itemUi = new ConnectorDescriptorItemUi(connector, categoryChildrenContainer, background); itemUi.updateAvailability(); allConnectors.add(connector); } } // last one gets a border Composite border = new Composite(categoryChildrenContainer, SWT.NULL); GridDataFactory.fillDefaults().grab(true, false).hint(SWT.DEFAULT, 1).applyTo(border); GridLayoutFactory.fillDefaults().applyTo(border); border.addPaintListener(new ConnectorBorderPaintListener()); } container.layout(true); container.redraw(); } private void createEnvironment() { environment = new Hashtable<Object, Object>(System.getProperties()); // add the installed Mylyn version to the environment so that we can // have // connectors that are filtered based on version of Mylyn Bundle bundle = Platform.getBundle("org.eclipse.mylyn.tasks.core"); //$NON-NLS-1$ String versionString = (String) bundle.getHeaders().get("Bundle-Version"); //$NON-NLS-1$ if (versionString != null) { Version version = new Version(versionString); environment.put("org.eclipse.mylyn.version", version.toString()); //$NON-NLS-1$ environment.put("org.eclipse.mylyn.version.major", version.getMajor()); //$NON-NLS-1$ environment.put("org.eclipse.mylyn.version.minor", version.getMinor()); //$NON-NLS-1$ environment.put("org.eclipse.mylyn.version.micro", version.getMicro()); //$NON-NLS-1$ } } protected Pattern createPattern(String filterText) { if (filterText == null || filterText.length() == 0) { return null; } String regex = filterText; regex.replace("\\", "\\\\").replace("?", ".").replace("*", ".*?"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ return Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL); } private void createRefreshJob() { refreshJob = new WorkbenchJob("filter") { //$NON-NLS-1$ @Override public IStatus runInUIThread(IProgressMonitor monitor) { if (filterText.isDisposed()) { return Status.CANCEL_STATUS; } String text = filterText.getText(); text = text.trim(); if (!previousFilterText.equals(text)) { previousFilterText = text; filterPattern = createPattern(previousFilterText); if (clearFilterTextControl != null) { clearFilterTextControl.setVisible(filterPattern != null); } createBodyContents(); } return Status.OK_STATUS; } }; refreshJob.setSystem(true); } private void discoveryUpdated(boolean wasCancelled) { createBodyContents(); if (discovery != null && !wasCancelled) { int categoryWithConnectorCount = 0; for (DiscoveryCategory category : discovery.getCategories()) { categoryWithConnectorCount += category.getConnectors().size(); } if (categoryWithConnectorCount == 0) { // nothing was discovered: notify the user MessageDialog.openWarning(getShell(), Messages.ConnectorDiscoveryWizardMainPage_noConnectorsFound, Messages.ConnectorDiscoveryWizardMainPage_noConnectorsFound_description); } } selectionProvider.setSelection(StructuredSelection.EMPTY); } private boolean filterMatches(String text) { return text != null && filterPattern.matcher(text).find(); } private void filterTextChanged() { refreshJob.cancel(); refreshJob.schedule(200L); } public Control getControl() { return control; } public String getDirectoryUrl() { return directoryUrl; } public ConnectorDiscovery getDiscovery() { return discovery; } /** * the environment in which discovery should be performed. * * @see ConnectorDiscovery#getEnvironment() */ public Dictionary<Object, Object> getEnvironment() { return environment; } private String getFilterLabel(ConnectorDescriptorKind kind) { switch (kind) { case DOCUMENT: return Messages.ConnectorDiscoveryWizardMainPage_filter_documents; case TASK: return Messages.ConnectorDiscoveryWizardMainPage_filter_tasks; case VCS: return Messages.ConnectorDiscoveryWizardMainPage_filter_vcs; default: throw new IllegalStateException(kind.name()); } } public String getFilterText() { return filterText.getText(); } public List<ConnectorDescriptor> getInstallableConnectors() { return installableConnectors; } public IStructuredSelection getSelection() { return (IStructuredSelection) selectionProvider.getSelection(); } private Shell getShell() { return shellProvider.getShell(); } public boolean getVerifyUpdateSiteAvailability() { return verifyUpdateSiteAvailability; } private boolean hasTooltip(final DiscoveryCategory category) { return category.getOverview() != null && category.getOverview().getSummary() != null && category.getOverview().getSummary().length() > 0; } private boolean hasTooltip(final DiscoveryConnector connector) { return connector.getOverview() != null && connector.getOverview().getSummary() != null && connector.getOverview().getSummary().length() > 0; } private void hookRecursively(Control control, Listener listener) { control.addListener(SWT.Dispose, listener); control.addListener(SWT.MouseHover, listener); control.addListener(SWT.MouseMove, listener); control.addListener(SWT.MouseExit, listener); control.addListener(SWT.MouseDown, listener); control.addListener(SWT.MouseWheel, listener); if (control instanceof Composite) { for (Control child : ((Composite) control).getChildren()) { hookRecursively(child, listener); } } } private void hookTooltip(final Control parent, final Widget tipActivator, final Control exitControl, final Control titleControl, AbstractDiscoverySource source, Overview overview, Image image) { final OverviewToolTip toolTip = new OverviewToolTip(parent, source, overview, image); Listener listener = new Listener() { public void handleEvent(Event event) { switch (event.type) { case SWT.MouseHover: toolTip.show(titleControl); break; case SWT.Dispose: case SWT.MouseWheel: toolTip.hide(); break; } } }; tipActivator.addListener(SWT.Dispose, listener); tipActivator.addListener(SWT.MouseWheel, listener); if (image != null) { tipActivator.addListener(SWT.MouseHover, listener); } Listener selectionListener = new Listener() { public void handleEvent(Event event) { toolTip.show(titleControl); } }; tipActivator.addListener(SWT.Selection, selectionListener); Listener exitListener = new Listener() { public void handleEvent(Event event) { switch (event.type) { case SWT.MouseWheel: toolTip.hide(); break; case SWT.MouseExit: /* * Check if the mouse exit happened because we move over the * tooltip */ Rectangle containerBounds = exitControl.getBounds(); Point displayLocation = exitControl.getParent().toDisplay(containerBounds.x, containerBounds.y); containerBounds.x = displayLocation.x; containerBounds.y = displayLocation.y; if (containerBounds.contains(Display.getCurrent().getCursorLocation())) { break; } toolTip.hide(); break; } } }; hookRecursively(exitControl, exitListener); } private void initializeColors() { IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager(); if (colorWhite == null) { ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); if (!colorRegistry.hasValueFor(COLOR_WHITE)) { colorRegistry.put(COLOR_WHITE, new RGB(255, 255, 255)); } colorWhite = colorRegistry.get(COLOR_WHITE); } if (colorDisabled == null) { ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); if (!colorRegistry.hasValueFor(COLOR_DARK_GRAY)) { colorRegistry.put(COLOR_DARK_GRAY, new RGB(0x69, 0x69, 0x69)); } colorDisabled = colorRegistry.get(COLOR_DARK_GRAY); } if (colorCategoryGradientStart == null) { colorCategoryGradientStart = themeManager.getCurrentTheme() .getColorRegistry() .get(CommonThemes.COLOR_CATEGORY_GRADIENT_START); colorCategoryGradientEnd = themeManager.getCurrentTheme() .getColorRegistry() .get(CommonThemes.COLOR_CATEGORY_GRADIENT_END); } } private void initializeCursors() { if (handCursor == null) { handCursor = new Cursor(getShell().getDisplay(), SWT.CURSOR_HAND); disposables.add(handCursor); } } private FontDescriptor createFontDescriptor(int style, float heightMultiplier) { Font baseFont = JFaceResources.getDialogFont(); FontData[] fontData = baseFont.getFontData(); FontData[] newFontData = new FontData[fontData.length]; for (int i = 0; i < newFontData.length; i++) { newFontData[i] = new FontData(fontData[i].getName(), (int) (fontData[i].getHeight() * heightMultiplier), fontData[i].getStyle() | style); } return FontDescriptor.createFrom(newFontData); } private void initializeFonts() { // create a level-2 heading font if (h2Font == null) { h2Font = new Font(Display.getCurrent(), createFontDescriptor(SWT.BOLD, 1.25f).getFontData()); disposables.add(h2Font); } // create a level-1 heading font if (h1Font == null) { h1Font = new Font(Display.getCurrent(), createFontDescriptor(SWT.BOLD, 1.35f).getFontData()); disposables.add(h1Font); } } private void initializeImages() { if (infoImage == null) { infoImage = DiscoveryImages.MESSAGE_INFO.createImage(); disposables.add(infoImage); } } public boolean isComplete() { return complete; } /** * indicate if there is nothing to display in the UI, given the current state of * {@link ConnectorDiscoveryWizard#isVisible(ConnectorDescriptorKind) filters}. */ private boolean isEmpty(ConnectorDiscovery discovery) { for (DiscoveryCategory category : discovery.getCategories()) { if (!isEmpty(category)) { return false; } } return true; } /** * indicate if the category has nothing to display in the UI, given the current state of * {@link ConnectorDiscoveryWizard#isVisible(ConnectorDescriptorKind) filters}. */ private boolean isEmpty(DiscoveryCategory category) { if (category.getConnectors().isEmpty()) { return true; } for (ConnectorDescriptor descriptor : category.getConnectors()) { if (!isFiltered(descriptor)) { return false; } } return true; } public void addFilter(ViewerFilter filter) { filters.add(filter); } public void removeFilter(ViewerFilter filter) { filters.remove(filter); } private boolean isFiltered(ConnectorDescriptor descriptor) { boolean kindFiltered = true; for (ConnectorDescriptorKind kind : descriptor.getKind()) { if (isVisible(kind)) { kindFiltered = false; break; } } if (kindFiltered) { return true; } if (!showInstalled && descriptor.isInstalled()) { return true; } if (filterPattern != null) { if (!(filterMatches(descriptor.getName()) || filterMatches(descriptor.getDescription()) || filterMatches(descriptor.getProvider()) || filterMatches(descriptor.getLicense()))) { return true; } } for (ViewerFilter filter : filters) { if (!filter.select(null, null, descriptor)) { return true; } } return false; } /** * indicate if the connector descriptor filters should be shown in the UI. Changing this setting only has an effect * before the UI is presented. */ public boolean isShowConnectorDescriptorKindFilter() { return showConnectorDescriptorKindFilter; } /** * indicate if a text field should be provided to allow the user to filter connector descriptors */ public boolean isShowConnectorDescriptorTextFilter() { return showConnectorDescriptorTextFilter; } public boolean isShowInstalled() { return showInstalled; } public boolean isShowInstalledFilterEnabled() { return showInstalledFilterEnabled; } /** * indicate if the given kind of connector is currently visible in the wizard * * @see #setVisibility(ConnectorDescriptorKind, boolean) */ public boolean isVisible(ConnectorDescriptorKind kind) { if (kind == null) { throw new IllegalArgumentException(); } return connectorDescriptorKindToVisibility.get(kind); } private void modifySelection(final DiscoveryConnector connector, boolean selected) { modifySelectionInternal(connector, selected); updateState(); } private void modifySelectionInternal(final DiscoveryConnector connector, boolean selected) { connector.setSelected(selected); if (selected) { installableConnectors.add(connector); } else { installableConnectors.remove(connector); } } public void removeSelectionChangedListener(ISelectionChangedListener listener) { selectionProvider.removeSelectionChangedListener(listener); } public void setComplete(boolean complete) { this.complete = complete; } protected void setControl(Control control) { this.control = control; } public void setDirectoryUrl(String directoryUrl) { this.directoryUrl = directoryUrl; } /** * the environment in which discovery should be performed. * * @see ConnectorDiscovery#getEnvironment() */ public void setEnvironment(Dictionary<Object, Object> environment) { if (environment == null) { throw new IllegalArgumentException(); } this.environment = environment; } public void setFilterText(String text) { Assert.isNotNull(text); filterText.setText(text); filterTextChanged(); } public void setSelection(IStructuredSelection selection) { Set<ConnectorDescriptor> selected = new HashSet<ConnectorDescriptor>(); for (Object descriptor : selection.toArray()) { if (descriptor instanceof ConnectorDescriptor) { selected.add((ConnectorDescriptor) descriptor); } } for (DiscoveryConnector connector : allConnectors) { modifySelectionInternal(connector, selected.contains(connector)); } updateState(); } /** * indicate if the connector descriptor filters should be shown in the UI. Changing this setting only has an effect * before the UI is presented. */ public void setShowConnectorDescriptorKindFilter(boolean showConnectorDescriptorKindFilter) { this.showConnectorDescriptorKindFilter = showConnectorDescriptorKindFilter; } /** * indicate if a text field should be provided to allow the user to filter connector descriptors */ public void setShowConnectorDescriptorTextFilter(boolean showConnectorDescriptorTextFilter) { this.showConnectorDescriptorTextFilter = showConnectorDescriptorTextFilter; } public void setShowInstalled(boolean showInstalled) { this.showInstalled = showInstalled; connectorDescriptorKindVisibilityUpdated(); } public void setShowInstalledFilterEnabled(boolean showInstalledFilter) { this.showInstalledFilterEnabled = showInstalledFilter; } public void setVerifyUpdateSiteAvailability(boolean verifyUpdateSiteAvailability) { this.verifyUpdateSiteAvailability = verifyUpdateSiteAvailability; } /** * configure the page to show or hide connector descriptors of the given kind * * @see #connectorDescriptorKindVisibilityUpdated() */ public void setVisibility(ConnectorDescriptorKind kind, boolean visible) { if (kind == null) { throw new IllegalArgumentException(); } connectorDescriptorKindToVisibility.put(kind, visible); } public void updateDiscovery() { final Dictionary<Object, Object> environment = getEnvironment(); boolean wasCancelled = false; try { final IStatus[] result = new IStatus[1]; context.run(true, true, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { if (DiscoveryViewer.this.installedFeatures == null) { DiscoveryViewer.this.installedFeatures = getInstalledFeatures(monitor); } ConnectorDiscovery connectorDiscovery = new ConnectorDiscovery(); // look for descriptors from installed bundles connectorDiscovery.getDiscoveryStrategies().add(new BundleDiscoveryStrategy()); // look for remote descriptor if (directoryUrl != null) { RemoteBundleDiscoveryStrategy remoteDiscoveryStrategy = new RemoteBundleDiscoveryStrategy(); remoteDiscoveryStrategy.setDirectoryUrl(directoryUrl); connectorDiscovery.getDiscoveryStrategies().add(remoteDiscoveryStrategy); } connectorDiscovery.setEnvironment(environment); connectorDiscovery.setVerifyUpdateSiteAvailability(false); try { result[0] = connectorDiscovery.performDiscovery(monitor); } finally { DiscoveryViewer.this.discovery = connectorDiscovery; postDiscovery(connectorDiscovery); } if (monitor.isCanceled()) { throw new InterruptedException(); } } }); if (result[0] != null && !result[0].isOK()) { StatusManager.getManager().handle(result[0], StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG); } } catch (InvocationTargetException e) { IStatus status = computeStatus(e, Messages.ConnectorDiscoveryWizardMainPage_unexpectedException); StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG); } catch (InterruptedException e) { // cancelled by user so nothing to do here. wasCancelled = true; } // check if control was closed if (body.isDisposed()) { return; } if (discovery != null) { discoveryUpdated(wasCancelled); if (verifyUpdateSiteAvailability && !discovery.getConnectors().isEmpty()) { try { context.run(true, true, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { discovery.verifySiteAvailability(monitor); } }); } catch (InvocationTargetException e) { IStatus status = computeStatus(e, Messages.ConnectorDiscoveryWizardMainPage_unexpectedException); StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG); } catch (InterruptedException e) { // cancelled by user so nothing to do here. wasCancelled = true; } } // check if control was closed if (body.isDisposed()) { return; } // createBodyContents() shouldn't be necessary but for some // reason checkboxes don't // regain their enabled state createBodyContents(); } // help UI tests body.setData("discoveryComplete", "true"); //$NON-NLS-1$ //$NON-NLS-2$ } private void updateState() { setComplete(!installableConnectors.isEmpty()); selectionProvider.setSelection(new StructuredSelection(getInstallableConnectors())); } protected void postDiscovery(ConnectorDiscovery connectorDiscovery) { for (DiscoveryConnector connector : connectorDiscovery.getConnectors()) { connector.setInstalled(installedFeatures != null && installedFeatures.containsAll(connector.getInstallableUnits())); } } protected Set<String> getInstalledFeatures(IProgressMonitor monitor) throws InterruptedException { return DiscoveryUi.createInstallJob().getInstalledFeatures(monitor); } }