134165: move find implementation to org.eclipse.mylyn.tasks.ui

provide find functionality for task editor

Change-Id: I14bebb0c5ff42b2ec8283cebabf4a7f5ff14cf29
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=134165
diff --git a/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/ExtensibleBugzillaTaskEditorPage.java b/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/ExtensibleBugzillaTaskEditorPage.java
index eef3173..f3efb92 100644
--- a/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/ExtensibleBugzillaTaskEditorPage.java
+++ b/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/ExtensibleBugzillaTaskEditorPage.java
@@ -13,14 +13,10 @@
 
 import java.util.Set;
 
-import org.eclipse.jface.action.IToolBarManager;
 import org.eclipse.mylyn.internal.bugzilla.ui.editor.BugzillaTaskEditorPage;
 import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPart;
 import org.eclipse.mylyn.tasks.ui.editors.TaskEditor;
 import org.eclipse.mylyn.tasks.ui.editors.TaskEditorPartDescriptor;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorSite;
-import org.eclipse.ui.actions.ActionFactory;
 
 /**
  * A bugzilla task editor page that has wiki facilities.
@@ -55,46 +51,4 @@
 		return descriptors;
 	}
 
-	/*
-	 * Find implementation. To be moved to AbstractTaskEditorPage.
-	 */
-
-	private TaskEditorFindSupport findSupport;
-
-	@Override
-	public void init(IEditorSite site, IEditorInput input) {
-		super.init(site, input);
-		findSupport = createFindSupport();
-	}
-
-	/**
-	 * Subclasses may return null to disable the find functionality.
-	 */
-	protected TaskEditorFindSupport createFindSupport() {
-		return new TaskEditorFindSupport(this);
-	}
-
-	@Override
-	public boolean canPerformAction(String actionId) {
-		if (findSupport != null && actionId.equals(ActionFactory.FIND.getId())) {
-			return true;
-		}
-		return super.canPerformAction(actionId);
-	}
-
-	@Override
-	public void doAction(String actionId) {
-		if (findSupport != null && actionId.equals(ActionFactory.FIND.getId())) {
-			findSupport.toggleFind();
-		}
-		super.doAction(actionId);
-	}
-
-	@Override
-	public void fillToolBar(IToolBarManager toolBarManager) {
-		super.fillToolBar(toolBarManager);
-		if (findSupport != null) {
-			findSupport.addFindAction(toolBarManager);
-		}
-	}
 }
diff --git a/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/Messages.java b/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/Messages.java
deleted file mode 100644
index ab81027..0000000
--- a/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/Messages.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2013 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.sandbox.ui.editors;
-
-import org.eclipse.osgi.util.NLS;
-
-public class Messages extends NLS {
-	private static final String BUNDLE_NAME = "org.eclipse.mylyn.internal.sandbox.ui.editors.messages"; //$NON-NLS-1$
-
-	public static String ExtensibleBugzillaTaskEditorPage_showNumResults;
-	static {
-		// initialize resource bundle
-		NLS.initializeMessages(BUNDLE_NAME, Messages.class);
-	}
-
-	private Messages() {
-	}
-}
diff --git a/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/TaskEditorFindSupport.java b/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/TaskEditorFindSupport.java
deleted file mode 100644
index 091eacf..0000000
--- a/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/TaskEditorFindSupport.java
+++ /dev/null
@@ -1,408 +0,0 @@
-/*******************************************************************************

- * Copyright (c) 2013 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.sandbox.ui.editors;

-

-import java.util.ArrayList;

-import java.util.List;

-

-import org.eclipse.core.runtime.Assert;

-import org.eclipse.jface.action.Action;

-import org.eclipse.jface.action.ControlContribution;

-import org.eclipse.jface.action.IToolBarManager;

-import org.eclipse.mylyn.commons.ui.CommonImages;

-import org.eclipse.mylyn.commons.workbench.forms.CommonFormUtil;

-import org.eclipse.mylyn.internal.tasks.ui.editors.RichTextEditor;

-import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorCommentPart;

-import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorCommentPart.CommentGroupViewer;

-import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorCommentPart.CommentViewer;

-import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorDescriptionPart;

-import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorPlanningPart;

-import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorSummaryPart;

-import org.eclipse.mylyn.tasks.core.data.TaskAttribute;

-import org.eclipse.mylyn.tasks.core.data.TaskData;

-import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage;

-import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPart;

-import org.eclipse.osgi.util.NLS;

-import org.eclipse.swt.SWT;

-import org.eclipse.swt.custom.StyleRange;

-import org.eclipse.swt.custom.StyledText;

-import org.eclipse.swt.events.ModifyEvent;

-import org.eclipse.swt.events.ModifyListener;

-import org.eclipse.swt.events.SelectionAdapter;

-import org.eclipse.swt.events.SelectionEvent;

-import org.eclipse.swt.graphics.Color;

-import org.eclipse.swt.layout.GridData;

-import org.eclipse.swt.layout.GridLayout;

-import org.eclipse.swt.widgets.Composite;

-import org.eclipse.swt.widgets.Control;

-import org.eclipse.swt.widgets.Display;

-import org.eclipse.swt.widgets.Text;

-import org.eclipse.ui.IWorkbenchActionConstants;

-import org.eclipse.ui.forms.IFormPart;

-import org.eclipse.ui.forms.events.HyperlinkAdapter;

-import org.eclipse.ui.forms.events.HyperlinkEvent;

-import org.eclipse.ui.forms.widgets.ExpandableComposite;

-import org.eclipse.ui.forms.widgets.FormToolkit;

-

-/**

- * Adds support for finding text to the task editor.

- * 

- * @author Jingwen Ou

- * @author Lily Guo

- * @author Sam Davis

- */

-public class TaskEditorFindSupport {

-

-	private Action toggleFindAction;

-

-	private static final Color HIGHLIGHTER_YELLOW = new Color(Display.getDefault(), 255, 238, 99);

-

-	private static final Color ERROR_NO_RESULT = new Color(Display.getDefault(), 255, 150, 150);

-

-	private final List<StyledText> styledTexts = new ArrayList<StyledText>();

-

-	private final List<CommentGroupViewer> commentGroupViewers = new ArrayList<CommentGroupViewer>();

-

-	private final AbstractTaskEditorPage taskEditorPage;;

-

-	public TaskEditorFindSupport(AbstractTaskEditorPage page) {

-		Assert.isNotNull(page);

-		this.taskEditorPage = page;

-	}

-

-	public void toggleFind() {

-		if (toggleFindAction != null) {

-			toggleFindAction.setChecked(!toggleFindAction.isChecked());

-			toggleFindAction.run();

-		}

-	}

-

-	public void addFindAction(IToolBarManager toolBarManager) {

-		if (toggleFindAction != null && toggleFindAction.isChecked()) {

-			ControlContribution findTextboxControl = new ControlContribution("Find") {

-				@Override

-				protected Control createControl(Composite parent) {

-					FormToolkit toolkit = taskEditorPage.getEditor().getHeaderForm().getToolkit();

-					final Composite findComposite = toolkit.createComposite(parent);

-

-					GridLayout findLayout = new GridLayout();

-					findLayout.marginHeight = 4;

-					findComposite.setLayout(findLayout);

-					findComposite.setBackground(null);

-

-					final Text findText = toolkit.createText(findComposite, "", SWT.FLAT);

-					findText.setLayoutData(new GridData(100, SWT.DEFAULT));

-					findText.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);

-					findText.setFocus();

-					toolkit.adapt(findText, false, false);

-

-					findText.addModifyListener(new ModifyListener() {

-						@Override

-						public void modifyText(ModifyEvent e) {

-							if (findText.getText().equals("")) {

-								clearSearchResults();

-								findText.setBackground(null);

-							}

-						}

-					});

-

-					findText.addSelectionListener(new SelectionAdapter() {

-						@Override

-						public void widgetDefaultSelected(SelectionEvent event) {

-							searchTaskEditor(findText);

-						}

-					});

-					toolkit.paintBordersFor(findComposite);

-					return findComposite;

-				}

-

-			};

-			toolBarManager.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, findTextboxControl);

-		}

-

-		if (toggleFindAction == null) {

-			toggleFindAction = new Action("", SWT.TOGGLE) {

-				@Override

-				public void run() {

-					if (!this.isChecked()) {

-						clearSearchResults();

-					}

-					taskEditorPage.getEditor().updateHeaderToolBar();

-				}

-

-			};

-			toggleFindAction.setImageDescriptor(CommonImages.FIND);

-			toggleFindAction.setToolTipText("Find");

-		}

-		toolBarManager.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, toggleFindAction);

-	}

-

-	protected void searchTaskEditor(final Text findBox) {

-		try {

-			taskEditorPage.setReflow(false);

-			findBox.setBackground(null);

-			if (findBox.getText().equals("")) {

-				return;

-			}

-			clearSearchResults();

-			String searchString = findBox.getText().toLowerCase();

-			for (IFormPart part : taskEditorPage.getManagedForm().getParts()) {

-				if (!(part instanceof AbstractTaskEditorPart)) {

-					continue;

-				}

-				Control control = ((AbstractTaskEditorPart) part).getControl();

-				if (part instanceof TaskEditorSummaryPart) {

-					if (contains(taskEditorPage.getModel().getTaskData(), TaskAttribute.SUMMARY, searchString)) {

-						gatherStyledTexts(control, styledTexts);

-					}

-				} else if (part instanceof TaskEditorPlanningPart) {

-					RichTextEditor noteEditor = ((TaskEditorPlanningPart) part).getPlanningPart().getNoteEditor();

-					if (noteEditor != null && noteEditor.getText() != null

-							&& noteEditor.getText().toLowerCase().contains(searchString)) {

-						gatherStyledTexts(control, styledTexts);

-					}

-				} else if (part instanceof TaskEditorDescriptionPart) {

-					if (contains(taskEditorPage.getModel().getTaskData(), TaskAttribute.DESCRIPTION, searchString)) {

-						gatherStyledTexts(control, styledTexts);

-					}

-				} else if (part instanceof TaskEditorCommentPart) {

-					commentGroupViewers.clear();

-					commentGroupViewers.addAll(((TaskEditorCommentPart) part).getCommentGroupViewers());

-					searchCommentPart(searchString, (TaskEditorCommentPart) part, commentGroupViewers, styledTexts);

-				}

-			}

-

-			for (StyledText styledText : styledTexts) {

-				highlightMatches(searchString, styledText);

-			}

-			if (styledTexts.isEmpty()) {

-				findBox.setBackground(ERROR_NO_RESULT);

-			}

-		} finally {

-			taskEditorPage.setReflow(true);

-		}

-		taskEditorPage.reflow();

-		findBox.setFocus();

-	}

-

-	protected static boolean contains(TaskData taskData, String attributeId, String searchString) {

-		TaskAttribute attribute = taskData.getRoot().getMappedAttribute(attributeId);

-		if (attribute != null) {

-			return attribute.getValue().toLowerCase().contains(searchString);

-		}

-		return false;

-	}

-

-//	@Override

-//	public boolean canPerformAction(String actionId) {

-//		if (actionId.equals(ActionFactory.FIND.getId())) {

-//			return true;

-//		}

-//		return super.canPerformAction(actionId);

-//	}

-//

-//

-//	@Override

-//	public void doAction(String actionId) {

-//		if (actionId.equals(ActionFactory.FIND.getId())) {

-//			if (toggleFindAction != null) {

-//				toggleFindAction.setChecked(!toggleFindAction.isChecked());

-//				toggleFindAction.run();

-//			}

-//		}

-//		super.doAction(actionId);

-//	}

-//

-//	@Override

-//	public void fillToolBar(IToolBarManager toolBarManager) {

-//		super.fillToolBar(toolBarManager);

-//		addFindAction(toolBarManager);

-//	}

-

-	private void searchCommentPart(final String searchString, final TaskEditorCommentPart part,

-			List<CommentGroupViewer> commentGroupViewers, final List<StyledText> styledTexts) {

-		TaskData taskData = taskEditorPage.getModel().getTaskData();

-		List<TaskAttribute> commentAttributes = taskData.getAttributeMapper().getAttributesByType(taskData,

-				TaskAttribute.TYPE_COMMENT);

-

-		if (!anyCommentContains(commentAttributes, searchString)) {

-			return;

-		}

-

-		if (!part.isCommentSectionExpanded()) {

-			try {

-				part.setReflow(false);

-				part.expandAllComments(false);

-			} finally {

-				part.setReflow(true);

-			}

-		}

-

-		int end = commentAttributes.size();

-		boolean expandMatchingGroup = true;

-		for (int i = commentGroupViewers.size() - 1; i >= 0; i--) {

-			final CommentGroupViewer group = commentGroupViewers.get(i);

-			List<CommentViewer> commentViewers = group.getCommentViewers();

-			int start = end - commentViewers.size();

-			List<TaskAttribute> groupAttributes = commentAttributes.subList(start, end);

-			if (expandMatchingGroup && anyCommentContains(groupAttributes, searchString)) {

-				if (!group.isExpanded()) {

-					try {

-						part.setReflow(false);

-						group.setExpanded(true);

-					} finally {

-						part.setReflow(true);

-					}

-				}

-				// once we've seen a matching group, don't expand any more groups

-				expandMatchingGroup = false;

-			}

-			final List<CommentViewer> matchingViewers = searchComments(groupAttributes, commentViewers, searchString);

-			if (!group.isRenderedInSubSection() || group.isExpanded()) {

-				try {

-					part.setReflow(false);

-					gatherStyledTexts(matchingViewers, styledTexts);

-				} finally {

-					part.setReflow(true);

-				}

-				group.clearSectionHyperlink();

-			} else if (!matchingViewers.isEmpty()) {

-				addShowMoreLink(group, matchingViewers, part, searchString, styledTexts);

-			} else {

-				group.clearSectionHyperlink();

-			}

-			end = start;

-		}

-	}

-

-	protected void addShowMoreLink(final CommentGroupViewer group, final List<CommentViewer> matchingViewers,

-			final TaskEditorCommentPart part, final String searchString, final List<StyledText> styledTexts) {

-		HyperlinkAdapter listener = new HyperlinkAdapter() {

-			@Override

-			public void linkActivated(HyperlinkEvent e) {

-				List<StyledText> commentStyledTexts = new ArrayList<StyledText>();

-				try {

-					taskEditorPage.setReflow(false);

-					part.setReflow(false);

-					group.setExpanded(true);

-					gatherStyledTexts(matchingViewers, commentStyledTexts);

-				} finally {

-					taskEditorPage.setReflow(true);

-					part.setReflow(true);

-				}

-				for (StyledText styledText : commentStyledTexts) {

-					highlightMatches(searchString, styledText);

-					styledTexts.add(styledText);

-				}

-				group.clearSectionHyperlink();

-				taskEditorPage.reflow();

-			}

-		};

-		group.createSectionHyperlink(

-				NLS.bind(Messages.ExtensibleBugzillaTaskEditorPage_showNumResults, matchingViewers.size()), listener);

-	}

-

-	private static boolean anyCommentContains(List<TaskAttribute> commentAttributes, String text) {

-		for (TaskAttribute commentAttribute : commentAttributes) {

-			if (commentContains(commentAttribute, text)) {

-				return true;

-			}

-		}

-		return false;

-	}

-

-	private static boolean commentContains(TaskAttribute commentAttribute, String searchString) {

-		TaskAttribute attribute = commentAttribute.getMappedAttribute(TaskAttribute.COMMENT_TEXT);

-		return attribute.getValue().toLowerCase().contains(searchString);

-	}

-

-	private static List<CommentViewer> searchComments(List<TaskAttribute> commentAttributes,

-			List<CommentViewer> commentViewers, String searchString) {

-		List<CommentViewer> matchingViewers = new ArrayList<TaskEditorCommentPart.CommentViewer>();

-		for (int i = 0; i < commentViewers.size(); i++) {

-			CommentViewer viewer = commentViewers.get(i);

-			if (commentContains(commentAttributes.get(i), searchString)) {

-				matchingViewers.add(viewer);

-			}

-		}

-		return matchingViewers;

-	}

-

-	protected static void gatherStyledTexts(List<CommentViewer> commentViewers, List<StyledText> styledTexts) {

-		for (CommentViewer viewer : commentViewers) {

-			try {

-				ExpandableComposite composite = (ExpandableComposite) viewer.getControl();

-				viewer.suppressSelectionChanged(true);

-				if (composite != null && !composite.isExpanded()) {

-					CommonFormUtil.setExpanded(composite, true);

-				}

-				gatherStyledTextsInComposite(composite, styledTexts);

-			} finally {

-				viewer.suppressSelectionChanged(false);

-			}

-		}

-	}

-

-	private static void gatherStyledTexts(Control control, List<StyledText> result) {

-		if (control instanceof ExpandableComposite) {

-			ExpandableComposite composite = (ExpandableComposite) control;

-			if (!composite.isExpanded()) {

-				CommonFormUtil.setExpanded(composite, true);

-			}

-			gatherStyledTextsInComposite(composite, result);

-		} else if (control instanceof Composite) {

-			gatherStyledTextsInComposite((Composite) control, result);

-		}

-	}

-

-	private static void gatherStyledTextsInComposite(Composite composite, List<StyledText> result) {

-		if (composite != null && !composite.isDisposed()) {

-			for (Control child : composite.getChildren()) {

-				if (child instanceof StyledText) {

-					result.add((StyledText) child);

-				} else if (child instanceof Composite) {

-					gatherStyledTextsInComposite((Composite) child, result);

-				}

-			}

-		}

-	}

-

-	private static void highlightMatches(String searchString, StyledText styledText) {

-		String text = styledText.getText().toLowerCase();

-		for (int index = 0; index < text.length(); index += searchString.length()) {

-			index = text.indexOf(searchString, index);

-			if (index == -1) {

-				break;

-			}

-			styledText.setStyleRange(new StyleRange(index, searchString.length(), null, HIGHLIGHTER_YELLOW));

-		}

-	}

-

-	private void clearSearchResults() {

-		for (StyledText oldText : styledTexts) {

-			List<StyleRange> otherRanges = new ArrayList<StyleRange>();

-			if (!oldText.isDisposed()) {

-				for (StyleRange styleRange : oldText.getStyleRanges()) {

-					if (styleRange.background == null || !styleRange.background.equals(HIGHLIGHTER_YELLOW)) {

-						otherRanges.add(styleRange); // preserve ranges that aren't from highlighting search results

-					}

-				}

-				oldText.setStyleRanges(otherRanges.toArray(new StyleRange[otherRanges.size()]));

-			}

-		}

-		styledTexts.clear();

-		for (CommentGroupViewer group : commentGroupViewers) {

-			group.clearSectionHyperlink();

-		}

-	}

-

-}

diff --git a/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/messages.properties b/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/messages.properties
deleted file mode 100644
index d7f690d..0000000
--- a/org.eclipse.mylyn.sandbox.ui/src/org/eclipse/mylyn/internal/sandbox/ui/editors/messages.properties
+++ /dev/null
@@ -1 +0,0 @@
-ExtensibleBugzillaTaskEditorPage_showNumResults=Show {0} more results