Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordgreen2009-05-06 03:52:22 +0000
committerdgreen2009-05-06 03:52:22 +0000
commit8894f3a497069790954e55b16067088e20c332a0 (patch)
treedbe890bbbf5edb81f02e46f341b753dd47bdc8f2
parentb2ea69e599269f651476695fdeb08d1897f3451c (diff)
downloadorg.eclipse.mylyn.commons-8894f3a497069790954e55b16067088e20c332a0.tar.gz
org.eclipse.mylyn.commons-8894f3a497069790954e55b16067088e20c332a0.tar.xz
org.eclipse.mylyn.commons-8894f3a497069790954e55b16067088e20c332a0.zip
NEW - bug 275029: Add a text search field to the discovery UI wizard
https://bugs.eclipse.org/bugs/show_bug.cgi?id=275029
-rw-r--r--org.eclipse.mylyn.discovery.ui/src/org/eclipse/mylyn/internal/discovery/ui/wizards/ConnectorDiscoveryWizard.java16
-rw-r--r--org.eclipse.mylyn.discovery.ui/src/org/eclipse/mylyn/internal/discovery/ui/wizards/ConnectorDiscoveryWizardMainPage.java371
2 files changed, 352 insertions, 35 deletions
diff --git a/org.eclipse.mylyn.discovery.ui/src/org/eclipse/mylyn/internal/discovery/ui/wizards/ConnectorDiscoveryWizard.java b/org.eclipse.mylyn.discovery.ui/src/org/eclipse/mylyn/internal/discovery/ui/wizards/ConnectorDiscoveryWizard.java
index e9a6dbfc..af6ac0aa 100644
--- a/org.eclipse.mylyn.discovery.ui/src/org/eclipse/mylyn/internal/discovery/ui/wizards/ConnectorDiscoveryWizard.java
+++ b/org.eclipse.mylyn.discovery.ui/src/org/eclipse/mylyn/internal/discovery/ui/wizards/ConnectorDiscoveryWizard.java
@@ -47,6 +47,8 @@ public class ConnectorDiscoveryWizard extends Wizard {
private boolean showConnectorDescriptorKindFilter = true;
+ private boolean showConnectorDescriptorTextFilter = true;
+
public ConnectorDiscoveryWizard() {
setWindowTitle("Connector Discovery");
setNeedsProgressMonitor(true);
@@ -116,4 +118,18 @@ public class ConnectorDiscoveryWizard extends Wizard {
this.showConnectorDescriptorKindFilter = showConnectorDescriptorKindFilter;
}
+ /**
+ * indicate if a text field should be provided to allow the user to filter connector descriptors
+ */
+ public boolean isShowConnectorDescriptorTextFilter() {
+ return showConnectorDescriptorTextFilter;
+ }
+
+ /**
+ * indicate if a text field should be provided to allow the user to filter connector descriptors
+ */
+ public void setShowConnectorDescriptorTextFilter(boolean showConnectorDescriptorTextFilter) {
+ this.showConnectorDescriptorTextFilter = showConnectorDescriptorTextFilter;
+ }
+
}
diff --git a/org.eclipse.mylyn.discovery.ui/src/org/eclipse/mylyn/internal/discovery/ui/wizards/ConnectorDiscoveryWizardMainPage.java b/org.eclipse.mylyn.discovery.ui/src/org/eclipse/mylyn/internal/discovery/ui/wizards/ConnectorDiscoveryWizardMainPage.java
index c8800739..e0851708 100644
--- a/org.eclipse.mylyn.discovery.ui/src/org/eclipse/mylyn/internal/discovery/ui/wizards/ConnectorDiscoveryWizardMainPage.java
+++ b/org.eclipse.mylyn.discovery.ui/src/org/eclipse/mylyn/internal/discovery/ui/wizards/ConnectorDiscoveryWizardMainPage.java
@@ -15,10 +15,8 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
-import java.util.Stack;
+import java.util.regex.Pattern;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -44,11 +42,25 @@ import org.eclipse.mylyn.internal.discovery.core.model.RemoteBundleDiscoveryStra
import org.eclipse.mylyn.internal.discovery.ui.DiscoveryUi;
import org.eclipse.mylyn.internal.discovery.ui.util.DiscoveryCategoryComparator;
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.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.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;
@@ -60,6 +72,7 @@ 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;
@@ -67,7 +80,13 @@ 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.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.ui.progress.WorkbenchJob;
/**
* The main wizard page that allows users to select connectors that they wish to install.
@@ -76,8 +95,20 @@ import org.eclipse.swt.widgets.Listener;
*/
public class ConnectorDiscoveryWizardMainPage extends WizardPage {
+ /**
+ * Image descriptor for enabled clear button.
+ */
+ private static final String CLEAR_ICON = "org.eclipse.ui.internal.dialogs.CLEAR_ICON"; //$NON-NLS-1$
+
+ /**
+ * Image descriptor for disabled clear button.
+ */
+ private static final String DISABLED_CLEAR_ICON = "org.eclipse.ui.internal.dialogs.DCLEAR_ICON"; //$NON-NLS-1$
+
private static final String COLOR_WHITE = "white"; //$NON-NLS-1$
+ private static Boolean useNativeSearchField;
+
private final List<ConnectorDescriptor> installableConnectors = new ArrayList<ConnectorDescriptor>();
private ConnectorDiscovery discovery;
@@ -92,6 +123,18 @@ public class ConnectorDiscoveryWizardMainPage extends WizardPage {
private Color colorWhite;
+ private Text filterText;
+
+ private WorkbenchJob refreshJob;
+
+ private final String initialText = "type filter text";
+
+ private String previousFilterText = ""; //$NON-NLS-1$
+
+ private Pattern filterPattern;
+
+ private Label clearFilterTextControl;
+
public ConnectorDiscoveryWizardMainPage() {
super(ConnectorDiscoveryWizardMainPage.class.getSimpleName());
setTitle("Connector Discovery");
@@ -101,7 +144,14 @@ public class ConnectorDiscoveryWizardMainPage extends WizardPage {
}
public void createControl(Composite parent) {
+ createRefreshJob();
+
Composite container = new Composite(parent, SWT.NULL);
+ container.addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ refreshJob.cancel();
+ }
+ });
container.setLayout(new GridLayout(1, false));
//
{ // header
@@ -109,7 +159,7 @@ public class ConnectorDiscoveryWizardMainPage extends WizardPage {
GridLayoutFactory.fillDefaults().applyTo(header);
GridDataFactory.fillDefaults().grab(true, false).applyTo(header);
- // TODO: header needed? instructions, refresh button
+// TODO: refresh button?
if (getWizard().isShowConnectorDescriptorKindFilter()) { // filter buttons
Composite checkboxContainer = new Composite(header, SWT.NULL);
@@ -135,6 +185,81 @@ public class ConnectorDiscoveryWizardMainPage extends WizardPage {
});
}
}
+
+ if (getWizard().isShowConnectorDescriptorTextFilter()) {
+ Composite filterContainer;
+ boolean nativeSearch = useNativeSearchField(header);
+ if (nativeSearch) {
+ filterContainer = new Composite(header, SWT.NULL);
+ } else {
+ filterContainer = new Composite(header, SWT.BORDER);
+ filterContainer.setBackground(header.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+ }
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(filterContainer);
+ GridLayoutFactory.fillDefaults().numColumns(2).applyTo(filterContainer);
+
+ if (nativeSearch) {
+ filterText = new Text(filterContainer, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL);
+ } else {
+ filterText = new Text(filterContainer, SWT.SINGLE);
+ }
+
+ filterText.setText(initialText);
+ filterText.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusGained(FocusEvent e) {
+ Display display = filterText.getDisplay();
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (!filterText.isDisposed()) {
+ if (initialText.equals(filterText.getText().trim())) {
+ filterText.selectAll();
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (filterText.getText().trim().length() == 0) {
+ filterText.setText(initialText);
+ }
+ }
+ });
+ filterText.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseDown(MouseEvent e) {
+ if (filterText.getText().equals(initialText)) {
+ clearFilterText();
+ }
+ }
+ });
+ 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);
+ // native platform doesn't support a clear filter text button
+ // so we add one here instead. Based on FilteredTree implementation
+ initSearchFieldImages();
+
+ clearFilterTextControl = createClearFilterTextControl(filterContainer, filterText);
+ clearFilterTextControl.setVisible(false);
+ }
+ }
}
{ // container
body = new Composite(container, SWT.NULL);
@@ -144,11 +269,168 @@ public class ConnectorDiscoveryWizardMainPage extends WizardPage {
setControl(container);
}
+ 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 = new Boolean((testText.getStyle() & SWT.ICON_CANCEL) != 0);
+ } finally {
+ if (testText != null) {
+ testText.dispose();
+ }
+ }
+
+ }
+ return useNativeSearchField;
+ }
+
+ 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 (initialText.equals(text)) {
+ text = ""; //$NON-NLS-1$
+ }
+ if (!previousFilterText.equals(text)) {
+ previousFilterText = text;
+ filterPattern = createPattern(previousFilterText);
+ clearFilterTextControl.setVisible(filterPattern != null);
+ createBodyContents();
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ refreshJob.setSystem(true);
+ }
+
+ 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 Label createClearFilterTextControl(Composite filterContainer, final Text filterText) {
+ final Image inactiveImage = JFaceResources.getImageRegistry().getDescriptor(DISABLED_CLEAR_ICON).createImage();
+ final Image activeImage = JFaceResources.getImageRegistry().getDescriptor(CLEAR_ICON).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(WorkbenchMessages.FilteredTree_ClearToolTip);
+ clearButton.setBackground(filterContainer.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+ clearButton.addMouseListener(new MouseAdapter() {
+ private MouseMoveListener fMoveListener;
+
+ @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();
+ }
+ }
+ }
+
+ private boolean isMouseInButton(MouseEvent e) {
+ Point buttonSize = clearButton.getSize();
+ return 0 <= e.x && e.x < buttonSize.x && 0 <= e.y && e.y < buttonSize.y;
+ }
+ });
+ 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 = WorkbenchMessages.FilteredTree_AccessibleListenerClearButton;
+ }
+ });
+ clearButton.getAccessible().addAccessibleControlListener(new AccessibleControlAdapter() {
+ @Override
+ public void getRole(AccessibleControlEvent e) {
+ e.detail = ACC.ROLE_PUSHBUTTON;
+ }
+ });
+ return clearButton;
+ }
+
+ private void initSearchFieldImages() {
+ ImageDescriptor descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(PlatformUI.PLUGIN_ID,
+ "$nl$/icons/full/etool16/clear_co.gif"); //$NON-NLS-1$
+ if (descriptor != null) {
+ JFaceResources.getImageRegistry().put(CLEAR_ICON, descriptor);
+ }
+ descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(PlatformUI.PLUGIN_ID,
+ "$nl$/icons/full/dtool16/clear_co.gif"); //$NON-NLS-1$
+ if (descriptor != null) {
+ JFaceResources.getImageRegistry().put(DISABLED_CLEAR_ICON, descriptor);
+ }
+ }
+
@Override
public ConnectorDiscoveryWizard getWizard() {
return (ConnectorDiscoveryWizard) super.getWizard();
}
+ private void clearFilterText() {
+ filterText.setText(""); //$NON-NLS-1$
+ filterTextChanged();
+ }
+
+ private void filterTextChanged() {
+ refreshJob.cancel();
+ refreshJob.schedule(200L);
+ }
+
private String getFilterLabel(ConnectorDescriptorKind kind) {
switch (kind) {
case DOCUMENT:
@@ -195,7 +477,7 @@ public class ConnectorDiscoveryWizardMainPage extends WizardPage {
initializeFonts();
initializeColors();
- body.setLayout(new GridLayout(1, true));
+ GridLayoutFactory.fillDefaults().applyTo(body);
// we put the contents in a scrolled composite since we don't know how
// big it will be
@@ -267,13 +549,29 @@ public class ConnectorDiscoveryWizardMainPage extends WizardPage {
break;
}
}
- Label helpText = new Label(container, SWT.WRAP);
- GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).applyTo(helpText);
- if (atLeastOneKindFiltered) {
- helpText.setText("There are no connectors of the selected type. Please select another connector type or try again later.");
+ Control helpTextControl;
+ if (filterPattern != null) {
+ Link link = new Link(container, SWT.WRAP);
+ link.setFont(container.getFont());
+ link.setText("There are no matching connectors. Please <a>clear the filter text</a> or try again later.");
+ link.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event event) {
+ clearFilterText();
+ filterText.setFocus();
+ }
+ });
+ helpTextControl = link;
} else {
- helpText.setText("Sorry, there are no available connectors. Please try again later.");
+ Label helpText = new Label(container, SWT.WRAP);
+ helpText.setFont(container.getFont());
+ if (atLeastOneKindFiltered) {
+ helpText.setText("There are no connectors of the selected type. Please select another connector type or try again later.");
+ } else {
+ helpText.setText("Sorry, there are no available connectors. Please try again later.");
+ }
+ helpTextControl = helpText;
}
+ GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).applyTo(helpTextControl);
} else {
List<DiscoveryCategory> categories = new ArrayList<DiscoveryCategory>(discovery.getCategories());
Collections.sort(categories, new DiscoveryCategoryComparator());
@@ -315,7 +613,9 @@ public class ConnectorDiscoveryWizardMainPage extends WizardPage {
GridDataFactory.fillDefaults().grab(true, false).hint(SWT.DEFAULT, 1).applyTo(border);
border.addPaintListener(new ConnectorBorderPaintListener());
for (final DiscoveryConnector connector : category.getConnectors()) {
-
+ if (isFiltered(connector)) {
+ continue;
+ }
Composite connectorContainer = new Composite(categoryContainer, SWT.NULL);
connectorContainer.setBackground(background);
GridDataFactory.fillDefaults().grab(true, false).applyTo(connectorContainer);
@@ -407,29 +707,6 @@ public class ConnectorDiscoveryWizardMainPage extends WizardPage {
container.redraw();
}
- private boolean hasOverviewUrl(final DiscoveryConnector connector) {
- return connector.getOverview() != null && connector.getOverview().getUrl() != null
- && connector.getOverview().getUrl().length() > 0;
- }
-
- private Set<Control> collectComponentHierarchy(Composite c) {
- Set<Control> components = new HashSet<Control>();
- Stack<Composite> work = new Stack<Composite>();
- work.push(c);
- while (!work.isEmpty()) {
- c = work.pop();
- components.add(c);
- for (Control child : c.getChildren()) {
- if (child instanceof Composite) {
- work.push((Composite) child);
- } else {
- components.add(child);
- }
- }
- }
- return components;
- }
-
private void hookTooltip(final Composite container, final Control titleControl, DiscoveryConnector connector) {
final ConnectorDescriptorToolTip toolTip = new ConnectorDescriptorToolTip(container, connector);
Listener listener = new Listener() {
@@ -513,13 +790,37 @@ public class ConnectorDiscoveryWizardMainPage extends WizardPage {
return true;
}
for (ConnectorDescriptor descriptor : category.getConnectors()) {
- if (getWizard().isVisible(descriptor.getKind())) {
+ if (!isFiltered(descriptor)) {
return false;
}
}
return true;
}
+ private boolean isFiltered(ConnectorDescriptor descriptor) {
+ boolean kindFiltered = !getWizard().isVisible(descriptor.getKind());
+ if (kindFiltered) {
+ return true;
+ }
+ if (filterPattern != null) {
+ if (filterMatches(descriptor.getName()) || filterMatches(descriptor.getDescription())
+ || filterMatches(descriptor.getProvider())) {
+ return false;
+ }
+ if (descriptor.getOverview() != null) {
+ if (filterMatches(descriptor.getOverview().getSummary())) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private boolean filterMatches(String text) {
+ return text != null && filterPattern.matcher(text).find();
+ }
+
private Image computeIconImage(AbstractDiscoverySource discoverySource, Icon icon) {
// FIXME: which image?
String imagePath = icon.getImage32();

Back to the top