Bug 500598 - CleanDialog should offer filter option - clean up previous
commit

If the native platform does not support SWT.ICON_CANCEL a label is
generated for it.
If not active this label is excluded from layout. This leads to similar
behavior as the preference filter box.

Change-Id: I17578dfbda9c6d0c9dfb46fe144cd1ab04f5b88a
Signed-off-by: David Weiser <david.weiser@vogella.com>
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java
index 5521e2b..e1d35c5 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java
@@ -1005,6 +1005,9 @@
 	public static String CleanDialog_cleanSelectedTaskName;
 	public static String CleanDialog_cleanAllTaskName;
 	public static String CleanDialog_alwaysCleanAllButton;
+	public static String CleanDialog_typeFilterText;
+	public static String CleanDialog_clearToolTip;
+	public static String CleanDialog_AccessibleListenerClearButton;
 	public static String IDEEncoding_EncodingJob;
 	public static String IDEEditorsPreferencePage_WorkbenchPreference_viewsRelatedLink;
 	public static String IDEEditorsPreferencePage_WorkbenchPreference_FileEditorsRelatedLink;
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/CleanDialog.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/CleanDialog.java
index a67e6df..22c3af2 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/CleanDialog.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/dialogs/CleanDialog.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2015 IBM Corporation and others.
+ * Copyright (c) 2004, 2017 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,6 +12,7 @@
  *     Christian Georgi <christian.georgi@sap.com> -  [IDE] Clean dialog should scroll to reveal selected projects - http://bugs.eclipse.org/415522
  *     Andrey Loskutov <loskutov@gmx.de> - generified interface, bug 462760
  *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472784
+ *     David Weiser <David.Weiser@vogella.com> - Bug 500598
  *******************************************************************************/
 package org.eclipse.ui.internal.ide.dialogs;
 
@@ -33,12 +34,26 @@
 import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.dialogs.IDialogSettings;
 import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.viewers.CheckboxTableViewer;
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.jface.viewers.ViewerFilter;
 import org.eclipse.jface.window.IShellProvider;
 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.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+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.SelectionListener;
+import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
@@ -49,13 +64,16 @@
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.actions.BuildAction;
 import org.eclipse.ui.actions.GlobalBuildAction;
+import org.eclipse.ui.dialogs.SearchPattern;
 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
 import org.eclipse.ui.internal.ide.actions.BuildUtilities;
 import org.eclipse.ui.model.WorkbenchContentProvider;
 import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.eclipse.ui.progress.IProgressConstants2;
 
 /**
@@ -91,7 +109,7 @@
     private static final String BUILD_NOW = "BUILD_NOW"; //$NON-NLS-1$
     private static final String BUILD_ALL = "BUILD_ALL"; //$NON-NLS-1$
 
-	private Button selectAllButton, deselectAllButton, alwaysCleanButton, buildNowButton, globalBuildButton,
+	private Button alwaysCleanButton, buildNowButton, globalBuildButton,
 			projectBuildButton;
 
     private CheckboxTableViewer projectNames;
@@ -101,7 +119,34 @@
     private IWorkbenchWindow window;
 
 	private Text filterText;
-	private String filterRegexPattern = ".*"; //$NON-NLS-1$
+	private SearchPattern searchPattern = new SearchPattern();
+	private Label clearLabel;
+
+	/**
+	 * Image descriptor for enabled clear button.
+	 */
+	private static final String CLEAR_ICON = "org.eclipse.ui.internal.dialogs.CLEANDIALOG_CLEAR_ICON"; //$NON-NLS-1$
+
+	/**
+	 * Image descriptor for disabled clear button.
+	 */
+	private static final String DISABLED_CLEAR_ICON = "org.eclipse.ui.internal.dialogs.CLEANDIALOG_DCLEAR_ICON"; //$NON-NLS-1$
+
+	/**
+	 * Get image descriptors for the clear button.
+	 */
+	static {
+		ImageDescriptor descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(PlatformUI.PLUGIN_ID,
+				"$nl$/icons/full/etool16/clear_co.png"); //$NON-NLS-1$
+		if (descriptor != null) {
+			JFaceResources.getImageRegistry().put(CLEAR_ICON, descriptor);
+		}
+		descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(PlatformUI.PLUGIN_ID,
+				"$nl$/icons/full/dtool16/clear_co.png"); //$NON-NLS-1$
+		if (descriptor != null) {
+			JFaceResources.getImageRegistry().put(DISABLED_CLEAR_ICON, descriptor);
+		}
+	}
 
     /**
      * Gets the text of the clean dialog, depending on whether the
@@ -130,6 +175,7 @@
         if (this.selection == null) {
             this.selection = new Object[0];
         }
+		searchPattern.setPattern(""); //$NON-NLS-1$
     }
 
     @Override
@@ -189,57 +235,87 @@
     @Override
 	protected Control createCustomArea(Composite parent) {
         Composite area = new Composite(parent, SWT.NONE);
-        GridLayout layout = new GridLayout();
-        layout.marginWidth = layout.marginHeight = 0;
-        layout.numColumns = 2;
-		layout.makeColumnsEqualWidth = false;
-        area.setLayout(layout);
+        GridLayout areaLayout = new GridLayout();
+        areaLayout.marginWidth = areaLayout.marginHeight = 0;
+		areaLayout.numColumns = 1;
+		areaLayout.makeColumnsEqualWidth = false;
+        area.setLayout(areaLayout);
         area.setLayoutData(new GridData(GridData.FILL_BOTH));
 
 		IDialogSettings settings = getDialogSettings(DIALOG_SETTINGS_SECTION);
 
-        //first row
-		filterText = new Text(area, SWT.SEARCH | SWT.ICON_CANCEL);
+		alwaysCleanButton = new Button(area, SWT.CHECK);
+		alwaysCleanButton.setText(IDEWorkbenchMessages.CleanDialog_alwaysCleanAllButton);
+		alwaysCleanButton.setSelection(!settings.getBoolean(TOGGLE_SELECTED));
+		alwaysCleanButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			updateEnablement();
+			if (!alwaysCleanButton.getSelection()) {
+				setInitialFilterText();
+			} else {
+				filterText.setText(""); //$NON-NLS-1$
+			}
+		}));
+
+		Composite filterTextArea = null;
+		if (useNativeSearchField(area)) {
+			filterTextArea = new Composite(area, SWT.NONE);
+			filterText = new Text(filterTextArea, SWT.BORDER | SWT.SINGLE | SWT.SEARCH | SWT.ICON_CANCEL);
+		} else {
+			filterTextArea = new Composite(area, SWT.BORDER);
+			filterText = new Text(filterTextArea, SWT.SINGLE);
+		}
+
+		GridLayout filterTextLayout = new GridLayout();
+		filterTextLayout.marginWidth = 0;
+		filterTextLayout.marginHeight = 0;
+		filterTextLayout.numColumns = 1;
+		filterTextLayout.horizontalSpacing = 0;
+		filterTextLayout.makeColumnsEqualWidth = false;
+		filterTextArea.setLayout(filterTextLayout);
+		filterTextArea.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		filterText.setMessage(IDEWorkbenchMessages.CleanDialog_typeFilterText);
 		GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
 		filterText.setLayoutData(gd);
-		filterText.setFocus();
 		filterText.addModifyListener(e -> {
-			filterRegexPattern = ".*" + filterText.getText() + ".*"; //$NON-NLS-1$ //$NON-NLS-2$
+			String filter = filterText.getText();
+			if (filter.startsWith("*") || filter.startsWith("?")) { //$NON-NLS-1$ //$NON-NLS-2$
+				searchPattern.setPattern(filter);
+			} else {
+				searchPattern.setPattern("*" + filter); //$NON-NLS-1$
+			}
+
+			if (filter.isEmpty()) {
+				filterText.setMessage(IDEWorkbenchMessages.CleanDialog_typeFilterText);
+			}
+
+			showClearButton(!filter.isEmpty() && !filter.equals(IDEWorkbenchMessages.CleanDialog_typeFilterText));
+
+
 			projectNames.refresh();
 		});
 
-		selectAllButton = new Button(area, SWT.PUSH);
-		gd = new GridData(SWT.FILL, SWT.CENTER, false, false);
-		selectAllButton.setLayoutData(gd);
-		selectAllButton.setText(IDEWorkbenchMessages.CleanDialog_selectAllButton);
-		selectAllButton.addSelectionListener(widgetSelectedAdapter(e -> {
-			projectNames.setAllChecked(true);
-			selection = projectNames.getCheckedElements();
-			updateEnablement();
-		}));
+		filterText.addFocusListener(new FocusListener() {
+			@Override
+			public void focusLost(FocusEvent e) {
+				if (filterText.getText().equals(IDEWorkbenchMessages.CleanDialog_typeFilterText)) {
+					filterText.setText(""); //$NON-NLS-1$
+				}
+			}
 
-		// third row
+			@Override
+			public void focusGained(FocusEvent e) {
+			}
+		});
+
+		createClearTextNew(filterTextArea);
+		showClearButton(false);
+
 		createProjectSelectionTable(area);
+		if (!alwaysCleanButton.getSelection()) {
+			setInitialFilterText();
+		}
 
-		deselectAllButton = new Button(area, SWT.PUSH);
-		gd = new GridData(SWT.FILL, SWT.TOP, false, false);
-		deselectAllButton.setLayoutData(gd);
-		deselectAllButton.setText(IDEWorkbenchMessages.CleanDialog_deselectedAllButton);
-		deselectAllButton.addSelectionListener(widgetSelectedAdapter(e -> {
-			projectNames.setAllChecked(false);
-			selection = projectNames.getCheckedElements();
-			updateEnablement();
-		}));
-
-		// fourth row
-		alwaysCleanButton = new Button(area, SWT.CHECK);
-		alwaysCleanButton.setText(IDEWorkbenchMessages.CleanDialog_alwaysCleanAllButton);
-		alwaysCleanButton.setSelection(settings.getBoolean(TOGGLE_SELECTED));
-		alwaysCleanButton.addSelectionListener(widgetSelectedAdapter(e -> updateEnablement()));
-
-		new Label(area, SWT.NONE);
-
-		// fifth row
         //only prompt for immediate build if autobuild is off
         if (!ResourcesPlugin.getWorkspace().isAutoBuilding()) {
 			SelectionListener updateEnablement = widgetSelectedAdapter(e -> updateEnablement());
@@ -273,10 +349,38 @@
             globalBuildButton.addSelectionListener(buildRadioSelected);
             projectBuildButton.addSelectionListener(buildRadioSelected);
         }
-
         return area;
     }
 
+	private static boolean useNativeSearchField(Composite composite) {
+		boolean useNativeSearchField = true;
+		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 void setInitialFilterText() {
+		filterText.setText(IDEWorkbenchMessages.CleanDialog_typeFilterText);
+		filterText.selectAll();
+		filterText.setFocus();
+	}
+
+	protected void showClearButton(boolean visible) {
+		if (clearLabel != null) {
+			clearLabel.setVisible(visible);
+			GridData layoutData = (GridData) clearLabel.getLayoutData();
+			layoutData.exclude = !visible;
+			clearLabel.getParent().requestLayout();
+		}
+	}
+
     @Override
 	protected Control createContents(Composite parent) {
     	Control contents= super.createContents(parent);
@@ -284,8 +388,8 @@
     	return contents;
     }
 
-    private void createProjectSelectionTable(Composite radioGroup) {
-        projectNames = CheckboxTableViewer.newCheckList(radioGroup, SWT.BORDER);
+	private void createProjectSelectionTable(Composite parent) {
+		projectNames = CheckboxTableViewer.newCheckList(parent, SWT.BORDER);
         projectNames.setContentProvider(new WorkbenchContentProvider());
         projectNames.setLabelProvider(new WorkbenchLabelProvider());
         projectNames.setComparator(new ResourceComparator(ResourceComparator.NAME));
@@ -297,18 +401,18 @@
                     return false;
                 }
                 IProject project = (IProject) element;
-				boolean isProjectNameMatchingPattern = project.getName().matches(filterRegexPattern);
+				boolean isProjectNameMatchingPattern = searchPattern.matches(project.getName());
 				if (!project.isAccessible() || !isProjectNameMatchingPattern) {
-                    return false;
+					if (!filterText.getText().equals(IDEWorkbenchMessages.CleanDialog_typeFilterText)) {
+						return false;
+					}
                 }
                 projectHolder[0] = project;
                 return BuildUtilities.isEnabled(projectHolder, IncrementalProjectBuilder.CLEAN_BUILD);
             }
         });
         projectNames.setInput(ResourcesPlugin.getWorkspace().getRoot());
-        GridData data = new GridData(GridData.FILL_BOTH);
-		data.horizontalSpan = 1;
-        data.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH;
+		GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
         data.heightHint = IDialogConstants.ENTRY_FIELD_WIDTH;
         projectNames.getTable().setLayoutData(data);
         projectNames.setCheckedElements(selection);
@@ -349,8 +453,6 @@
 	 */
     protected void updateEnablement() {
 		projectNames.getTable().setEnabled(!alwaysCleanButton.getSelection());
-		selectAllButton.setEnabled(!alwaysCleanButton.getSelection());
-		deselectAllButton.setEnabled(!alwaysCleanButton.getSelection());
 		filterText.setEnabled(!alwaysCleanButton.getSelection());
 
 		boolean enabled = selection.length > 0 || alwaysCleanButton.getSelection();
@@ -440,7 +542,7 @@
             settings.put(BUILD_ALL, globalBuildButton.getSelection());
         }
 
-		settings.put(TOGGLE_SELECTED, alwaysCleanButton.getSelection());
+		settings.put(TOGGLE_SELECTED, !alwaysCleanButton.getSelection());
     }
 
     /**
@@ -468,4 +570,106 @@
 	protected boolean isResizable() {
         return true;
     }
+
+	/**
+	 * Create the button that clears the text.
+	 *
+	 * @param parent
+	 *            parent <code>Composite</code> of button
+	 */
+	private void createClearTextNew(Composite parent) {
+		// only create the button if the text widget doesn't support one
+		// natively
+		if ((filterText.getStyle() & SWT.ICON_CANCEL) == 0) {
+			// add one additional column to the parent view to add space for the clear
+			// button
+			((GridLayout) parent.getLayout()).numColumns = 2;
+
+			final Image inactiveImage = JFaceResources.getImageRegistry()
+					.getDescriptor(DISABLED_CLEAR_ICON).createImage();
+			final Image activeImage = JFaceResources.getImageRegistry()
+					.getDescriptor(CLEAR_ICON).createImage();
+			final Image pressedImage = new Image(parent.getDisplay(), activeImage, SWT.IMAGE_GRAY);
+
+			final Label clearButton = new Label(parent, SWT.NONE);
+			clearButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+			clearButton.setImage(inactiveImage);
+			clearButton.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+			clearButton.setToolTipText(IDEWorkbenchMessages.CleanDialog_clearToolTip);
+			clearButton.addMouseListener(new MouseAdapter() {
+				private MouseMoveListener fMoveListener;
+
+				@Override
+				public void mouseDown(MouseEvent e) {
+					clearButton.setImage(pressedImage);
+					fMoveListener = new MouseMoveListener() {
+						private boolean fMouseInButton = true;
+
+						@Override
+						public void mouseMove(MouseEvent event) {
+							boolean mouseInButton = isMouseInButton(event);
+							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) {
+							filterText.setText(""); //$NON-NLS-1$
+							filterText.selectAll();
+							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() {
+				@Override
+				public void mouseEnter(MouseEvent e) {
+					clearButton.setImage(activeImage);
+				}
+
+				@Override
+				public void mouseExit(MouseEvent e) {
+					clearButton.setImage(inactiveImage);
+				}
+
+				@Override
+				public void mouseHover(MouseEvent e) {
+				}
+			});
+			clearButton.addDisposeListener(e -> {
+				inactiveImage.dispose();
+				activeImage.dispose();
+				pressedImage.dispose();
+			});
+			clearButton.getAccessible().addAccessibleListener(new AccessibleAdapter() {
+				@Override
+				public void getName(AccessibleEvent e) {
+					e.result = IDEWorkbenchMessages.CleanDialog_AccessibleListenerClearButton;
+				}
+			});
+			clearButton.getAccessible().addAccessibleControlListener(new AccessibleControlAdapter() {
+				@Override
+				public void getRole(AccessibleControlEvent e) {
+					e.detail = ACC.ROLE_PUSHBUTTON;
+				}
+			});
+			this.clearLabel = clearButton;
+		}
+	}
 }
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties
index 79c5a44..6514339 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties
@@ -1019,18 +1019,21 @@
 If you continue, this can cause unexpected behavior or data loss.\n\nAre you sure you want to continue with this workspace?
 IDEApplication_version_doNotWarnAgain=&Do not warn again about workspace versions
 
-CleanDialog_buildCleanAuto=Clean discards all build results and states. The selected projects will be rebuild from scratch.
+CleanDialog_buildCleanAuto=Clean discards all build results and states. The selected projects will be rebuilt from scratch.
 CleanDialog_buildCleanManual=Clean discards all build results and states.  The next time a build occurs the selected projects will be rebuilt from scratch.
 CleanDialog_title=Clean
 CleanDialog_clean_button_label=&Clean
 CleanDialog_selectAllButton=&Select All
 CleanDialog_deselectedAllButton=&Deselect All
-CleanDialog_alwaysCleanAllButton=Always clean all
+CleanDialog_alwaysCleanAllButton=Clean &all projects
 CleanDialog_buildNowButton=Start a &build immediately
 CleanDialog_globalBuildButton=Build the entire &workspace
 CleanDialog_buildSelectedProjectsButton=Build only the selected &projects
 CleanDialog_cleanSelectedTaskName=Cleaning selected projects
 CleanDialog_cleanAllTaskName=Cleaning all projects
+CleanDialog_typeFilterText=type filter text
+CleanDialog_clearToolTip=Clear
+CleanDialog_AccessibleListenerClearButton=Clear filter field
 IDEEncoding_EncodingJob=Setting encoding
 IDEEditorsPreferencePage_WorkbenchPreference_FileEditorsRelatedLink=See <a>''{0}''</a> for associating editors with file types.
 IDEEditorsPreferencePage_WorkbenchPreference_viewsRelatedLink = See <a>''{0}''</a> for appearance preferences.