{"thread":{"id":"13007","subject":"[EGIT PATCH 1/3] FindToolbar port to the new history page.","startedAt":"2008-04-06T21:41:49Z","lastAt":"2008-04-07T05:19:08Z","messageCount":2,"participants":["Roger C. Soares","Shawn O. Pearce"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"73773","messageId":"1207518109-4174-1-git-send-email-rogersoares@intelinet.com.br","threadId":"13007","inReplyTo":null,"subject":"[EGIT PATCH 1/3] FindToolbar port to the new history page.","fromName":"Roger C. Soares","fromEmail":"rogersoares@intelinet.com.br","sentAt":"2008-04-06T21:41:49Z","receivedAt":"2008-04-06T21:41:49Z","isPatch":true,"sender":{"key":"rogersoares@intelinet.com.br","avatar":null},"body":"This is a port from the find toolbar to the new history page.\nIt is replacing the current highlight flag in order to have the\nfind feature back but most of the code from the toolbar shall be\nreplaced to make use of the new infrastructure added into jgit\n(RevFlag and RevFilter).\n\nSigned-off-by: Roger C. Soares <rogersoares@intelinet.com.br>\n---\nHi Shawn,\n\nI'm reseding the toolbar port with the fixes for the items you mentioned.\nIt's on top of 009f11e2c8971b6053, don't know if it would have been better\nto rebase it, just let me know.\n\nPatch 3/3 is something I've come up to remove the Map hit in the paint\nmethod. As you said you were going to revisit the jgit API soon I didn't\nwant to do something too elaborated that will be dumped soon. I'm\nmanipulating RevFlags directly from the find toolbar, so if you don't\nlike just ignore it.\n\n[]s,\nRoger.\n\n\n .../src/org/spearce/egit/ui/UIText.java            |   23 +\n .../egit/ui/internal/history/CommitGraphTable.java |   24 +-\n .../egit/ui/internal/history/FindResults.java      |  185 ++++++++\n .../egit/ui/internal/history/FindToolbar.java      |  460 ++++++++++++++++++++\n .../ui/internal/history/FindToolbarThread.java     |  233 ++++++++++\n .../egit/ui/internal/history/GitHistoryPage.java   |   65 +++-\n .../src/org/spearce/egit/ui/uitext.properties      |   12 +\n 7 files changed, 981 insertions(+), 21 deletions(-)\n create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindResults.java\n create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindToolbar.java\n create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindToolbarThread.java\n\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java\nindex 6421b6c..dbe0df1 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java\n@@ -72,6 +72,29 @@ public class UIText extends NLS {\n \tpublic static String HistoryPage_refreshJob;\n \n \t/** */\n+\tpublic static String HistoryPage_findbar_findTooltip;\n+\t/** */\n+\tpublic static String HistoryPage_findbar_find;\n+\t/** */\n+\tpublic static String HistoryPage_findbar_next;\n+\t/** */\n+\tpublic static String HistoryPage_findbar_previous;\n+\t/** */\n+\tpublic static String HistoryPage_findbar_ignorecase;\n+\t/** */\n+\tpublic static String HistoryPage_findbar_commit;\n+\t/** */\n+\tpublic static String HistoryPage_findbar_comments;\n+\t/** */\n+\tpublic static String HistoryPage_findbar_author;\n+\t/** */\n+\tpublic static String HistoryPage_findbar_committer;\n+\t/** */\n+\tpublic static String HistoryPage_findbar_exceeded;\n+\t/** */\n+\tpublic static String HistoryPage_findbar_notFound;\n+\n+\t/** */\n \tpublic static String HistoryPreferencePage_title;\n \n \t/** */\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/CommitGraphTable.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/CommitGraphTable.java\nindex 6559d64..1b1d16b 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/CommitGraphTable.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/CommitGraphTable.java\n@@ -49,7 +49,6 @@ import org.spearce.egit.ui.UIPreferences;\n import org.spearce.egit.ui.UIText;\n import org.spearce.jgit.revplot.PlotCommit;\n import org.spearce.jgit.revwalk.RevCommit;\n-import org.spearce.jgit.revwalk.RevFlag;\n \n class CommitGraphTable {\n \tprivate static Font highlightFont() {\n@@ -81,13 +80,13 @@ class CommitGraphTable {\n \n \tprivate SWTCommitList allCommits;\n \n-\tprivate RevFlag highlight;\n+\tprivate FindResults findResults;\n \n \tCommitGraphTable(final Composite parent) {\n \t\tnFont = Activator.getFont(UIPreferences.THEME_CommitGraphNormalFont);\n \t\thFont = highlightFont();\n \n-\t\tfinal Table rawTable = new Table(parent, SWT.MULTI | SWT.H_SCROLL\n+\t\tTable rawTable = new Table(parent, SWT.MULTI | SWT.H_SCROLL\n \t\t\t\t| SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);\n \t\trawTable.setHeaderVisible(true);\n \t\trawTable.setLinesVisible(false);\n@@ -159,10 +158,10 @@ class CommitGraphTable {\n \t\t\t\tnew Transfer[] { TextTransfer.getInstance() }, DND.CLIPBOARD);\n \t}\n \n-\tvoid setInput(final RevFlag hFlag, final SWTCommitList list,\n+\tvoid setInput(final FindResults fResults, final SWTCommitList list,\n \t\t\tfinal SWTCommit[] asArray) {\n \t\tfinal SWTCommitList oldList = allCommits;\n-\t\thighlight = hFlag;\n+\t\tfindResults = fResults;\n \t\tallCommits = list;\n \t\ttable.setInput(asArray);\n \t\tif (asArray != null && asArray.length > 0) {\n@@ -211,8 +210,10 @@ class CommitGraphTable {\n \t}\n \n \tvoid doPaint(final Event event) {\n-\t\tfinal RevCommit c = (RevCommit) ((TableItem) event.item).getData();\n-\t\tif (highlight != null && c.has(highlight))\n+\t\tTableItem ti = (TableItem) event.item;\n+\t\tfinal RevCommit c = (RevCommit) ti.getData();\n+\t\tif (findResults != null\n+\t\t\t\t&& findResults.isFoundAt(table.getTable().indexOf(ti)))\n \t\t\tevent.gc.setFont(hFont);\n \t\telse\n \t\t\tevent.gc.setFont(nFont);\n@@ -232,4 +233,13 @@ class CommitGraphTable {\n \t\tfinal int texty = (event.height - textsz.y) / 2;\n \t\tevent.gc.drawString(txt, event.x, event.y + texty);\n \t}\n+\n+\t/**\n+\t * Returns the SWT Table that backs this CommitGraphTable.\n+\t *\n+\t * @return Table the SWT Table\n+\t */\n+\tpublic Table getTable() {\n+\t\treturn table.getTable();\n+\t}\n }\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindResults.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindResults.java\nnew file mode 100644\nindex 0000000..49ee4fc\n--- /dev/null\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindResults.java\n@@ -0,0 +1,185 @@\n+/*\n+ *  Copyright (C) 2008  Roger C. Soares\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU Lesser General Public\n+ *  License, version 2.1, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  Lesser General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU Lesser General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.egit.ui.internal.history;\n+\n+import java.util.Arrays;\n+import java.util.Iterator;\n+import java.util.LinkedHashMap;\n+import java.util.Map;\n+\n+/**\n+ * Results for the find toolbar. This object stores the rows in the history\n+ * table that contain a match to a given pattern.\n+ *\n+ * @see FindToolbar\n+ * @see FindToolbarThread\n+ */\n+public class FindResults {\n+\tprivate Map<Integer, Integer> matchesMap = new LinkedHashMap<Integer, Integer>();\n+\n+\tInteger[] keysArray;\n+\n+\tprivate int matchesCount;\n+\n+\t/**\n+\t * Returns if the index in the history table matches the find pattern.\n+\t *\n+\t * @param index\n+\t *            history table item index.\n+\t * @return boolean <code>true</code> if the history table\n+\t *         <code>index</code> contains a match to the find pattern,\n+\t *         <code>false</code> otherwise\n+\t */\n+\tpublic synchronized boolean isFoundAt(int index) {\n+\t\treturn matchesMap.containsKey(Integer.valueOf(index));\n+\t}\n+\n+\t/**\n+\t * Returns the first table item index after <code>index</code> that\n+\t * contains a match to the find pattern.\n+\t *\n+\t * @param index\n+\t *            the history table item index\n+\t * @return the index after <code>index</code> that contains a match.\n+\t *         Returns -1 if there isn't a match after <code>index</code>\n+\t */\n+\tpublic synchronized int getIndexAfter(int index) {\n+\t\tInteger[] matches = getkeysArray();\n+\t\tint sres = Arrays.binarySearch(matches, Integer.valueOf(index));\n+\t\tif (sres >= 0 && sres != matches.length - 1) {\n+\t\t\treturn matches[sres + 1].intValue();\n+\t\t} else if (sres < 0) {\n+\t\t\tsres = -sres - 1;\n+\t\t\tif (sres < matches.length) {\n+\t\t\t\treturn matches[sres].intValue();\n+\t\t\t}\n+\t\t}\n+\n+\t\treturn -1;\n+\t}\n+\n+\t/**\n+\t * Returns the first table item index before <code>index</code> that\n+\t * contains a match to the find pattern.\n+\t *\n+\t * @param index\n+\t *            the history table item index\n+\t * @return the index before <code>index</code> that contains a match.\n+\t *         Returns -1 if there isn't a match before <code>index</code>\n+\t */\n+\tpublic synchronized int getIndexBefore(int index) {\n+\t\tInteger[] matches = getkeysArray();\n+\t\tint sres = Arrays.binarySearch(matches, Integer.valueOf(index));\n+\t\tif (sres >= 0 && sres != 0) {\n+\t\t\treturn matches[sres - 1].intValue();\n+\t\t} else if (sres < -1) {\n+\t\t\tsres = -sres;\n+\t\t\treturn matches[sres - 2].intValue();\n+\t\t}\n+\n+\t\treturn -1;\n+\t}\n+\n+\t/**\n+\t * Returns the first table item index that contains a match to the find\n+\t * pattern.\n+\t *\n+\t * @return the first index that contains a match. Returns -1 if there isn't\n+\t *         any match\n+\t */\n+\tpublic synchronized int getFirstIndex() {\n+\t\tIterator iter = matchesMap.keySet().iterator();\n+\t\tif (iter.hasNext()) {\n+\t\t\treturn ((Integer) iter.next()).intValue();\n+\t\t}\n+\n+\t\treturn -1;\n+\t}\n+\n+\t/**\n+\t * Returns the last table item index that contains a match to the find\n+\t * pattern.\n+\t *\n+\t * @return the last index that contains a match. Returns -1 if there isn't\n+\t *         any match\n+\t */\n+\tpublic synchronized int getLastIndex() {\n+\t\tInteger[] matches = getkeysArray();\n+\t\tif (matches.length > 0) {\n+\t\t\treturn matches[matches.length - 1].intValue();\n+\t\t}\n+\n+\t\treturn -1;\n+\t}\n+\n+\t/**\n+\t * Returns the index in the matches list for the history table item\n+\t * <code>index</code>.\n+\t *\n+\t * @param index\n+\t *            the history table item index\n+\t * @return the position of the <code>index</code> in the total matches\n+\t *         list. Returns -1 if <code>index</code> doesn't contain a match\n+\t */\n+\tpublic synchronized int getMatchNumberFor(int index) {\n+\t\tInteger ix = matchesMap.get(Integer.valueOf(index));\n+\t\tif (ix != null) {\n+\t\t\treturn ix.intValue();\n+\t\t}\n+\n+\t\treturn -1;\n+\t}\n+\n+\t/**\n+\t * @return int\n+\t */\n+\tpublic int size() {\n+\t\treturn matchesCount;\n+\t}\n+\n+\t/**\n+\t * Cleans the find results. All match item indexes are removed.\n+\t */\n+\tpublic synchronized void clear() {\n+\t\tmatchesMap.clear();\n+\t\tkeysArray = null;\n+\t\tmatchesCount = 0;\n+\t}\n+\n+\t/**\n+\t * Adds a history table item index (<code>matchIx</code>) to the find\n+\t * results matches list.\n+\t *\n+\t * @param matchIx\n+\t *            the history table item index that matches a find pattern.\n+\t */\n+\tpublic synchronized void add(int matchIx) {\n+\t\tmatchesMap.put(Integer.valueOf(matchIx), Integer\n+\t\t\t\t.valueOf(++matchesCount));\n+\t\tkeysArray = null;\n+\t}\n+\n+\tprivate Integer[] getkeysArray() {\n+\t\tif (keysArray == null) {\n+\t\t\tkeysArray = matchesMap.keySet().toArray(\n+\t\t\t\t\tnew Integer[matchesMap.size()]);\n+\t\t}\n+\n+\t\treturn keysArray;\n+\t}\n+\n+}\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindToolbar.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindToolbar.java\nnew file mode 100644\nindex 0000000..dbd0774\n--- /dev/null\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindToolbar.java\n@@ -0,0 +1,460 @@\n+/*\n+ *  Copyright (C) 2008  Roger C. Soares\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU Lesser General Public\n+ *  License, version 2.1, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  Lesser General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU Lesser General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.egit.ui.internal.history;\n+\n+import java.util.ArrayList;\n+import java.util.List;\n+\n+import org.eclipse.core.runtime.Preferences;\n+import org.eclipse.swt.SWT;\n+import org.eclipse.swt.events.KeyAdapter;\n+import org.eclipse.swt.events.KeyEvent;\n+import org.eclipse.swt.events.ModifyEvent;\n+import org.eclipse.swt.events.ModifyListener;\n+import org.eclipse.swt.events.SelectionAdapter;\n+import org.eclipse.swt.events.SelectionEvent;\n+import org.eclipse.swt.graphics.Color;\n+import org.eclipse.swt.graphics.Image;\n+import org.eclipse.swt.graphics.Point;\n+import org.eclipse.swt.graphics.RGB;\n+import org.eclipse.swt.graphics.Rectangle;\n+import org.eclipse.swt.layout.GridData;\n+import org.eclipse.swt.layout.GridLayout;\n+import org.eclipse.swt.widgets.Button;\n+import org.eclipse.swt.widgets.Composite;\n+import org.eclipse.swt.widgets.Display;\n+import org.eclipse.swt.widgets.Event;\n+import org.eclipse.swt.widgets.Label;\n+import org.eclipse.swt.widgets.Listener;\n+import org.eclipse.swt.widgets.Menu;\n+import org.eclipse.swt.widgets.MenuItem;\n+import org.eclipse.swt.widgets.ProgressBar;\n+import org.eclipse.swt.widgets.Table;\n+import org.eclipse.swt.widgets.Text;\n+import org.eclipse.swt.widgets.ToolBar;\n+import org.eclipse.swt.widgets.ToolItem;\n+import org.eclipse.swt.widgets.Widget;\n+import org.spearce.egit.ui.Activator;\n+import org.spearce.egit.ui.UIIcons;\n+import org.spearce.egit.ui.UIPreferences;\n+import org.spearce.egit.ui.UIText;\n+\n+/**\n+ * A toolbar for the history page.\n+ *\n+ * @see FindToolbarThread\n+ * @see FindResults\n+ * @see GitHistoryPage\n+ */\n+public class FindToolbar extends Composite {\n+\tprivate Color errorBackgroundColor;\n+\n+\t/**\n+\t * The results (matches) of the current find operation.\n+\t */\n+\tpublic final FindResults findResults = new FindResults();\n+\n+\tprivate Preferences prefs = Activator.getDefault().getPluginPreferences();\n+\n+\tprivate List<Listener> eventList = new ArrayList<Listener>();\n+\n+\tprivate Image nextIcon;\n+\n+\tprivate Image previousIcon;\n+\n+\tprivate Table historyTable;\n+\n+\tprivate SWTCommit[] fileRevisions;\n+\n+\tprivate Text patternField;\n+\n+\tprivate Button nextButton;\n+\n+\tprivate Button previousButton;\n+\n+\tprivate Label currentPositionLabel;\n+\n+\tprivate ProgressBar progressBar;\n+\n+\tprivate String lastErrorPattern;\n+\n+\t/**\n+\t * Creates the toolbar.\n+\t *\n+\t * @param parent\n+\t *            the parent widget\n+\t */\n+\tpublic FindToolbar(Composite parent) {\n+\t\tsuper(parent, SWT.NULL);\n+\t\tcreateToolbar();\n+\t}\n+\n+\tprivate void createToolbar() {\n+\t\terrorBackgroundColor = new Color(getDisplay(), new RGB(255, 150, 150));\n+\t\tnextIcon = UIIcons.ELCL16_NEXT.createImage();\n+\t\tpreviousIcon = UIIcons.ELCL16_PREVIOUS.createImage();\n+\n+\t\tGridLayout findLayout = new GridLayout();\n+\t\tfindLayout.marginHeight = 2;\n+\t\tfindLayout.marginWidth = 2;\n+\t\tfindLayout.numColumns = 8;\n+\t\tsetLayout(findLayout);\n+\t\tsetLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));\n+\n+\t\tLabel findLabel = new Label(this, SWT.NULL);\n+\t\tfindLabel.setText(UIText.HistoryPage_findbar_find);\n+\n+\t\tpatternField = new Text(this, SWT.SEARCH);\n+\t\tGridData findTextData = new GridData(SWT.FILL, SWT.FILL, true, false);\n+\t\tfindTextData.minimumWidth = 50;\n+\t\tpatternField.setLayoutData(findTextData);\n+\t\tpatternField.setText(\"\");\n+\t\tpatternField.setTextLimit(100);\n+\n+\t\tnextButton = new Button(this, SWT.HORIZONTAL);\n+\t\tnextButton.setImage(nextIcon);\n+\t\tnextButton.setText(UIText.HistoryPage_findbar_next);\n+\n+\t\tpreviousButton = new Button(this, SWT.HORIZONTAL);\n+\t\tpreviousButton.setImage(previousIcon);\n+\t\tpreviousButton.setText(UIText.HistoryPage_findbar_previous);\n+\n+\t\tfinal ToolBar toolBar = new ToolBar(this, SWT.FLAT);\n+\t\tnew ToolItem(toolBar, SWT.SEPARATOR);\n+\n+\t\tfinal ToolItem prefsItem = new ToolItem(toolBar, SWT.DROP_DOWN);\n+\t\tfinal Menu prefsMenu = new Menu(this.getShell(), SWT.POP_UP);\n+\t\tfinal MenuItem caseItem = new MenuItem(prefsMenu, SWT.CHECK);\n+\t\tcaseItem.setText(UIText.HistoryPage_findbar_ignorecase);\n+\t\tnew MenuItem(prefsMenu, SWT.SEPARATOR);\n+\t\tfinal MenuItem commitIdItem = new MenuItem(prefsMenu, SWT.CHECK);\n+\t\tcommitIdItem.setText(UIText.HistoryPage_findbar_commit);\n+\t\tfinal MenuItem commentsItem = new MenuItem(prefsMenu, SWT.CHECK);\n+\t\tcommentsItem.setText(UIText.HistoryPage_findbar_comments);\n+\t\tfinal MenuItem authorItem = new MenuItem(prefsMenu, SWT.CHECK);\n+\t\tauthorItem.setText(UIText.HistoryPage_findbar_author);\n+\t\tfinal MenuItem committerItem = new MenuItem(prefsMenu, SWT.CHECK);\n+\t\tcommitterItem.setText(UIText.HistoryPage_findbar_committer);\n+\n+\t\tprefsItem.addListener(SWT.Selection, new Listener() {\n+\t\t\tpublic void handleEvent(Event event) {\n+\t\t\t\tif (event.detail == SWT.ARROW) {\n+\t\t\t\t\tRectangle itemBounds = prefsItem.getBounds();\n+\t\t\t\t\tPoint point = toolBar.toDisplay(itemBounds.x, itemBounds.y\n+\t\t\t\t\t\t\t+ itemBounds.height);\n+\t\t\t\t\tprefsMenu.setLocation(point);\n+\t\t\t\t\tprefsMenu.setVisible(true);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t});\n+\n+\t\tcurrentPositionLabel = new Label(this, SWT.NULL);\n+\t\tGridData totalLabelData = new GridData();\n+\t\ttotalLabelData.horizontalAlignment = SWT.FILL;\n+\t\ttotalLabelData.grabExcessHorizontalSpace = true;\n+\t\tcurrentPositionLabel.setLayoutData(totalLabelData);\n+\t\tcurrentPositionLabel.setAlignment(SWT.RIGHT);\n+\t\tcurrentPositionLabel.setText(\"\");\n+\n+\t\tprogressBar = new ProgressBar(this, SWT.HORIZONTAL);\n+\t\tGridData findProgressBarData = new GridData();\n+\t\tfindProgressBarData.heightHint = 12;\n+\t\tfindProgressBarData.widthHint = 35;\n+\t\tprogressBar.setLayoutData(findProgressBarData);\n+\t\tprogressBar.setMinimum(0);\n+\t\tprogressBar.setMaximum(100);\n+\n+\t\tfinal FindToolbar thisToolbar = this;\n+\t\tpatternField.addModifyListener(new ModifyListener() {\n+\t\t\tpublic void modifyText(ModifyEvent e) {\n+\t\t\t\tfinal FindToolbarThread finder = new FindToolbarThread();\n+\t\t\t\tfinder.pattern = ((Text) e.getSource()).getText();\n+\t\t\t\tfinder.fileRevisions = fileRevisions;\n+\t\t\t\tfinder.toolbar = thisToolbar;\n+\t\t\t\tfinder.ignoreCase = caseItem.getSelection();\n+\t\t\t\tfinder.findInCommitId = commitIdItem.getSelection();\n+\t\t\t\tfinder.findInComments = commentsItem.getSelection();\n+\t\t\t\tfinder.findInAuthor = authorItem.getSelection();\n+\t\t\t\tfinder.findInCommitter = committerItem.getSelection();\n+\t\t\t\tgetDisplay().timerExec(200, new Runnable() {\n+\t\t\t\t\tpublic void run() {\n+\t\t\t\t\t\tfinder.start();\n+\t\t\t\t\t}\n+\t\t\t\t});\n+\t\t\t}\n+\t\t});\n+\n+\t\tfinal Listener findButtonsListener = new Listener() {\n+\t\t\tpublic void handleEvent(Event event) {\n+\t\t\t\tif (patternField.getText().length() > 0\n+\t\t\t\t\t\t&& findResults.size() == 0) {\n+\t\t\t\t\t// If the toolbar was cleared and has a pattern typed,\n+\t\t\t\t\t// then we redo the find with the new table data.\n+\t\t\t\t\tfinal FindToolbarThread finder = new FindToolbarThread();\n+\t\t\t\t\tfinder.pattern = patternField.getText();\n+\t\t\t\t\tfinder.fileRevisions = fileRevisions;\n+\t\t\t\t\tfinder.toolbar = thisToolbar;\n+\t\t\t\t\tfinder.ignoreCase = caseItem.getSelection();\n+\t\t\t\t\tfinder.findInCommitId = commitIdItem.getSelection();\n+\t\t\t\t\tfinder.findInComments = commentsItem.getSelection();\n+\t\t\t\t\tfinder.findInAuthor = authorItem.getSelection();\n+\t\t\t\t\tfinder.findInCommitter = committerItem.getSelection();\n+\t\t\t\t\tfinder.start();\n+\t\t\t\t\tpatternField.setSelection(0, 0);\n+\t\t\t\t} else {\n+\t\t\t\t\tint currentIx = historyTable.getSelectionIndex();\n+\t\t\t\t\tint newIx = -1;\n+\t\t\t\t\tif (event.widget == nextButton) {\n+\t\t\t\t\t\tnewIx = findResults.getIndexAfter(currentIx);\n+\t\t\t\t\t\tif (newIx == -1) {\n+\t\t\t\t\t\t\tnewIx = findResults.getFirstIndex();\n+\t\t\t\t\t\t}\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\tnewIx = findResults.getIndexBefore(currentIx);\n+\t\t\t\t\t\tif (newIx == -1) {\n+\t\t\t\t\t\t\tnewIx = findResults.getLastIndex();\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t\tsendEvent(event.widget, newIx);\n+\n+\t\t\t\t\tString current = null;\n+\t\t\t\t\tint currentValue = findResults.getMatchNumberFor(newIx);\n+\t\t\t\t\tif (currentValue == -1) {\n+\t\t\t\t\t\tcurrent = \"-\";\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\tcurrent = String.valueOf(currentValue);\n+\t\t\t\t\t}\n+\t\t\t\t\tcurrentPositionLabel.setText(current + \"/\"\n+\t\t\t\t\t\t\t+ findResults.size());\n+\t\t\t\t}\n+\t\t\t}\n+\t\t};\n+\t\tnextButton.addListener(SWT.Selection, findButtonsListener);\n+\t\tpreviousButton.addListener(SWT.Selection, findButtonsListener);\n+\n+\t\tpatternField.addKeyListener(new KeyAdapter() {\n+\t\t\tprivate Event event = new Event();\n+\n+\t\t\t@Override\n+\t\t\tpublic void keyPressed(KeyEvent e) {\n+\t\t\t\tif (e.keyCode == SWT.ARROW_DOWN) {\n+\t\t\t\t\tif (nextButton.isEnabled()) {\n+\t\t\t\t\t\tevent.widget = nextButton;\n+\t\t\t\t\t\tfindButtonsListener.handleEvent(event);\n+\t\t\t\t\t}\n+\t\t\t\t} else if (e.keyCode == SWT.ARROW_UP) {\n+\t\t\t\t\tif (previousButton.isEnabled()) {\n+\t\t\t\t\t\tevent.widget = previousButton;\n+\t\t\t\t\t\tfindButtonsListener.handleEvent(event);\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t}\n+\t\t});\n+\n+\t\tcaseItem.addSelectionListener(new SelectionAdapter() {\n+\t\t\tpublic void widgetSelected(SelectionEvent e) {\n+\t\t\t\tprefs.setValue(UIPreferences.FINDTOOLBAR_IGNORE_CASE, caseItem\n+\t\t\t\t\t\t.getSelection());\n+\t\t\t\tActivator.getDefault().savePluginPreferences();\n+\t\t\t\tclear();\n+\t\t\t}\n+\t\t});\n+\t\tcaseItem.setSelection(prefs\n+\t\t\t\t.getBoolean(UIPreferences.FINDTOOLBAR_IGNORE_CASE));\n+\n+\t\tcommitIdItem.addSelectionListener(new SelectionAdapter() {\n+\t\t\tpublic void widgetSelected(SelectionEvent e) {\n+\t\t\t\tprefs.setValue(UIPreferences.FINDTOOLBAR_COMMIT_ID,\n+\t\t\t\t\t\tcommitIdItem.getSelection());\n+\t\t\t\tActivator.getDefault().savePluginPreferences();\n+\t\t\t\tclear();\n+\t\t\t}\n+\t\t});\n+\t\tcommitIdItem.setSelection(prefs\n+\t\t\t\t.getBoolean(UIPreferences.FINDTOOLBAR_COMMIT_ID));\n+\n+\t\tcommentsItem.addSelectionListener(new SelectionAdapter() {\n+\t\t\tpublic void widgetSelected(SelectionEvent e) {\n+\t\t\t\tprefs.setValue(UIPreferences.FINDTOOLBAR_COMMENTS, commentsItem\n+\t\t\t\t\t\t.getSelection());\n+\t\t\t\tActivator.getDefault().savePluginPreferences();\n+\t\t\t\tclear();\n+\t\t\t}\n+\t\t});\n+\t\tcommentsItem.setSelection(prefs\n+\t\t\t\t.getBoolean(UIPreferences.FINDTOOLBAR_COMMENTS));\n+\n+\t\tauthorItem.addSelectionListener(new SelectionAdapter() {\n+\t\t\tpublic void widgetSelected(SelectionEvent e) {\n+\t\t\t\tprefs.setValue(UIPreferences.FINDTOOLBAR_AUTHOR, authorItem\n+\t\t\t\t\t\t.getSelection());\n+\t\t\t\tActivator.getDefault().savePluginPreferences();\n+\t\t\t\tclear();\n+\t\t\t}\n+\t\t});\n+\t\tauthorItem.setSelection(prefs\n+\t\t\t\t.getBoolean(UIPreferences.FINDTOOLBAR_AUTHOR));\n+\n+\t\tcommitterItem.addSelectionListener(new SelectionAdapter() {\n+\t\t\tpublic void widgetSelected(SelectionEvent e) {\n+\t\t\t\tprefs.setValue(UIPreferences.FINDTOOLBAR_COMMITTER,\n+\t\t\t\t\t\tcommitterItem.getSelection());\n+\t\t\t\tActivator.getDefault().savePluginPreferences();\n+\t\t\t\tclear();\n+\t\t\t}\n+\t\t});\n+\t\tcommitterItem.setSelection(prefs\n+\t\t\t\t.getBoolean(UIPreferences.FINDTOOLBAR_COMMITTER));\n+\t}\n+\n+\t@Override\n+\tpublic void dispose() {\n+\t\terrorBackgroundColor.dispose();\n+\t\tnextIcon.dispose();\n+\t\tpreviousIcon.dispose();\n+\t\tsuper.dispose();\n+\t}\n+\n+\t/**\n+\t * Sets the table that will have its selected items changed by this toolbar.\n+\t * Sets the list to be searched.\n+\t *\n+\t * @param historyTable\n+\t * @param commitArray\n+\t */\n+\tpublic void setInput(final Table historyTable, final SWTCommit[] commitArray) {\n+\t\tthis.fileRevisions = commitArray;\n+\t\tthis.historyTable = historyTable;\n+\t}\n+\n+\tvoid progressUpdate(int percent) {\n+\t\tint total = findResults.size();\n+\t\tcurrentPositionLabel.setText(\"-/\" + total);\n+\t\tcurrentPositionLabel.setForeground(null);\n+\t\tif (total > 0) {\n+\t\t\tnextButton.setEnabled(true);\n+\t\t\tpreviousButton.setEnabled(true);\n+\t\t\tpatternField.setBackground(null);\n+\t\t} else {\n+\t\t\tnextButton.setEnabled(false);\n+\t\t\tpreviousButton.setEnabled(false);\n+\t\t}\n+\t\tprogressBar.setSelection(percent);\n+\t\thistoryTable.clearAll();\n+\t}\n+\n+\tvoid findCompletionUpdate(String pattern, boolean overflow) {\n+\t\tint total = findResults.size();\n+\t\tif (total > 0) {\n+\t\t\tif (overflow) {\n+\t\t\t\tcurrentPositionLabel\n+\t\t\t\t\t\t.setText(UIText.HistoryPage_findbar_exceeded + \" 1/\"\n+\t\t\t\t\t\t\t\t+ total);\n+\t\t\t} else {\n+\t\t\t\tcurrentPositionLabel.setText(\"1/\" + total);\n+\t\t\t}\n+\t\t\tint ix = findResults.getFirstIndex();\n+\t\t\tsendEvent(null, ix);\n+\n+\t\t\tpatternField.setBackground(null);\n+\t\t\tnextButton.setEnabled(true);\n+\t\t\tpreviousButton.setEnabled(true);\n+\t\t\tlastErrorPattern = null;\n+\t\t} else {\n+\t\t\tif (pattern.length() > 0) {\n+\t\t\t\tpatternField.setBackground(errorBackgroundColor);\n+\t\t\t\tcurrentPositionLabel\n+\t\t\t\t\t\t.setText(UIText.HistoryPage_findbar_notFound);\n+\t\t\t\t// Don't keep beeping every time if the user is deleting\n+\t\t\t\t// a long not found pattern\n+\t\t\t\tif (lastErrorPattern == null\n+\t\t\t\t\t\t|| (lastErrorPattern != null && !lastErrorPattern\n+\t\t\t\t\t\t\t\t.startsWith(pattern))) {\n+\t\t\t\t\tgetDisplay().beep();\n+\t\t\t\t\tnextButton.setEnabled(false);\n+\t\t\t\t\tpreviousButton.setEnabled(false);\n+\t\t\t\t}\n+\t\t\t\tlastErrorPattern = pattern;\n+\t\t\t} else {\n+\t\t\t\tpatternField.setBackground(null);\n+\t\t\t\tcurrentPositionLabel.setText(\"\");\n+\t\t\t\tnextButton.setEnabled(false);\n+\t\t\t\tpreviousButton.setEnabled(false);\n+\t\t\t\tlastErrorPattern = null;\n+\t\t\t}\n+\t\t}\n+\t\tprogressBar.setSelection(0);\n+\t\thistoryTable.clearAll();\n+\n+\t\tif (overflow) {\n+\t\t\tDisplay display = getDisplay();\n+\t\t\tcurrentPositionLabel.setForeground(display\n+\t\t\t\t\t.getSystemColor(SWT.COLOR_RED));\n+\t\t\tdisplay.beep();\n+\t\t} else {\n+\t\t\tcurrentPositionLabel.setForeground(null);\n+\t\t}\n+\t}\n+\n+\t/**\n+\t * Clears the toolbar.\n+\t */\n+\tpublic void clear() {\n+\t\tpatternField.setBackground(null);\n+\t\tif (patternField.getText().length() > 0) {\n+\t\t\tpatternField.selectAll();\n+\t\t\tnextButton.setEnabled(true);\n+\t\t\tpreviousButton.setEnabled(true);\n+\t\t} else {\n+\t\t\tnextButton.setEnabled(false);\n+\t\t\tpreviousButton.setEnabled(false);\n+\t\t}\n+\t\tcurrentPositionLabel.setText(\"\");\n+\t\tprogressBar.setSelection(0);\n+\t\tlastErrorPattern = null;\n+\n+\t\tfindResults.clear();\n+\t\tif (historyTable != null) {\n+\t\t\thistoryTable.clearAll();\n+\t\t}\n+\n+\t\tFindToolbarThread.updateGlobalThreadIx();\n+\t}\n+\n+\tprivate void sendEvent(Widget widget, int index) {\n+\t\tEvent event = new Event();\n+\t\tevent.type = SWT.Selection;\n+\t\tevent.index = index;\n+\t\tevent.widget = widget;\n+\t\tevent.data = fileRevisions[index];\n+\t\tfor (Listener listener : eventList) {\n+\t\t\tlistener.handleEvent(event);\n+\t\t}\n+\t}\n+\n+\t/**\n+\t * Adds a selection event listener. The toolbar generates events when it\n+\t * selects an item in the history table\n+\t *\n+\t * @param listener\n+\t *            the listener that will receive the event\n+\t */\n+\tpublic void addSelectionListener(Listener listener) {\n+\t\teventList.add(listener);\n+\t}\n+\n+}\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindToolbarThread.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindToolbarThread.java\nnew file mode 100644\nindex 0000000..95a545a\n--- /dev/null\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/FindToolbarThread.java\n@@ -0,0 +1,233 @@\n+/*\n+ *  Copyright (C) 2008  Roger C. Soares\n+ *\n+ *  This library is free software; you can redistribute it and/or\n+ *  modify it under the terms of the GNU Lesser General Public\n+ *  License, version 2.1, as published by the Free Software Foundation.\n+ *\n+ *  This library is distributed in the hope that it will be useful,\n+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *  Lesser General Public License for more details.\n+ *\n+ *  You should have received a copy of the GNU Lesser General Public\n+ *  License along with this library; if not, write to the Free Software\n+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n+ */\n+package org.spearce.egit.ui.internal.history;\n+\n+/**\n+ * This class executes the search function for the find toolbar. Only one thread\n+ * is executed at a time.\n+ * <p>\n+ * This class maintains a <code>globalThreadIx</code> internal variable that\n+ * is incremented for each new thread started and the current running thread\n+ * constantly checks this variable. If the current thread has the same value as\n+ * <code>globalThreadIx</code> it continues executing, if it has a lower value\n+ * it means that a more recent search needs to be done and the current isn't\n+ * necessary any more, so the current thread returns.\n+ * </p>\n+ * <p>\n+ * To avoid consuming all the memory in the system, this class limits the\n+ * maximum results it stores.\n+ * </p>\n+ *\n+ * @see FindToolbar\n+ * @see FindResults\n+ */\n+public class FindToolbarThread extends Thread {\n+\n+\tprivate static final Object EXEC_LOCK = new Object();\n+\n+\tprivate static final int MAX_RESULTS = 20000;\n+\n+\tString pattern;\n+\n+\tSWTCommit[] fileRevisions;\n+\n+\tFindToolbar toolbar;\n+\n+\tboolean ignoreCase;\n+\n+\tboolean findInCommitId;\n+\n+\tboolean findInComments;\n+\n+\tboolean findInAuthor;\n+\n+\tboolean findInCommitter;\n+\n+\tprivate volatile static int globalThreadIx = 0;\n+\n+\tprivate int currentThreadIx;\n+\n+\t/**\n+\t * Creates a new object and increments the internal\n+\t * <code>globalThreadIx</code> variable causing any earlier running thread\n+\t * to return.\n+\t */\n+\tpublic FindToolbarThread() {\n+\t\tsuper(\"history_find_thread\" + ++globalThreadIx);\n+\t\tcurrentThreadIx = globalThreadIx;\n+\t}\n+\n+\tpublic void run() {\n+\t\tsynchronized (EXEC_LOCK) {\n+\t\t\texecFind();\n+\t\t}\n+\t}\n+\n+\tprivate void execFind() {\n+\t\t// If it isn't the last event, just ignore it.\n+\t\tif (currentThreadIx < globalThreadIx) {\n+\t\t\treturn;\n+\t\t}\n+\n+\t\tFindResults findResults = toolbar.findResults;\n+\t\tfindResults.clear();\n+\n+\t\tboolean maxResultsOverflow = false;\n+\t\tif (pattern.length() > 0 && fileRevisions != null) {\n+\t\t\tString findPattern = pattern;\n+\t\t\tif (ignoreCase) {\n+\t\t\t\tfindPattern = pattern.toLowerCase();\n+\t\t\t}\n+\n+\t\t\tlong lastUIUpdate = System.currentTimeMillis();\n+\n+\t\t\tint totalRevisions = fileRevisions.length;\n+\t\t\tint totalMatches = 0;\n+\t\t\tboolean notFound = true;\n+\t\t\tfor (int i = 0; i < totalRevisions; i++) {\n+\t\t\t\t// If a new find event was generated, ends the current thread.\n+\t\t\t\tif (toolbar.getDisplay().isDisposed()\n+\t\t\t\t\t\t|| currentThreadIx < globalThreadIx) {\n+\t\t\t\t\treturn;\n+\t\t\t\t}\n+\n+\t\t\t\t// Updates the toolbar with in process info.\n+\t\t\t\tif (System.currentTimeMillis() - lastUIUpdate > 500) {\n+\t\t\t\t\tfinal int percentage = (int) (((i + 1F) / totalRevisions) * 100);\n+\t\t\t\t\ttoolbar.getDisplay().asyncExec(new Runnable() {\n+\t\t\t\t\t\tpublic void run() {\n+\t\t\t\t\t\t\tif (toolbar.isDisposed()) {\n+\t\t\t\t\t\t\t\treturn;\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\ttoolbar.progressUpdate(percentage);\n+\t\t\t\t\t\t}\n+\t\t\t\t\t});\n+\t\t\t\t\tlastUIUpdate = System.currentTimeMillis();\n+\t\t\t\t}\n+\n+\t\t\t\t// Finds for the pattern in the revision history.\n+\t\t\t\tnotFound = true;\n+\t\t\t\tSWTCommit revision = fileRevisions[i];\n+\n+\t\t\t\tif (findInCommitId) {\n+\t\t\t\t\tString contentId = revision.getId().toString();\n+\t\t\t\t\tif (contentId != null) {\n+\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\tcontentId = contentId.toLowerCase();\n+\t\t\t\t\t\t}\n+\t\t\t\t\t\tif (contentId.indexOf(findPattern) != -1) {\n+\t\t\t\t\t\t\ttotalMatches++;\n+\t\t\t\t\t\t\tfindResults.add(i);\n+\t\t\t\t\t\t\tnotFound = false;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\n+\t\t\t\tif (findInComments && notFound) {\n+\t\t\t\t\tString comment = revision.getFullMessage();\n+\t\t\t\t\tif (comment != null) {\n+\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\tcomment = comment.toLowerCase();\n+\t\t\t\t\t\t}\n+\t\t\t\t\t\tif (comment.indexOf(findPattern) != -1) {\n+\t\t\t\t\t\t\ttotalMatches++;\n+\t\t\t\t\t\t\tfindResults.add(i);\n+\t\t\t\t\t\t\tnotFound = false;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\n+\t\t\t\tif (findInAuthor && notFound) {\n+\t\t\t\t\tString author = revision.getAuthorIdent().getName();\n+\t\t\t\t\tif (author != null) {\n+\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\tauthor = author.toLowerCase();\n+\t\t\t\t\t\t}\n+\t\t\t\t\t\tif (author.indexOf(findPattern) != -1) {\n+\t\t\t\t\t\t\ttotalMatches++;\n+\t\t\t\t\t\t\tfindResults.add(i);\n+\t\t\t\t\t\t\tnotFound = false;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t\tif (notFound) {\n+\t\t\t\t\t\tString email = revision.getAuthorIdent()\n+\t\t\t\t\t\t\t\t.getEmailAddress();\n+\t\t\t\t\t\tif (email != null) {\n+\t\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\t\temail = email.toLowerCase();\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\tif (email.indexOf(findPattern) != -1) {\n+\t\t\t\t\t\t\t\ttotalMatches++;\n+\t\t\t\t\t\t\t\tfindResults.add(i);\n+\t\t\t\t\t\t\t\tnotFound = false;\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\n+\t\t\t\tif (findInCommitter && notFound) {\n+\t\t\t\t\tString committer = revision.getCommitterIdent().getName();\n+\t\t\t\t\tif (committer != null) {\n+\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\tcommitter = committer.toLowerCase();\n+\t\t\t\t\t\t}\n+\t\t\t\t\t\tif (committer.indexOf(findPattern) != -1) {\n+\t\t\t\t\t\t\ttotalMatches++;\n+\t\t\t\t\t\t\tfindResults.add(i);\n+\t\t\t\t\t\t\tnotFound = false;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t\tif (notFound) {\n+\t\t\t\t\t\tString email = revision.getCommitterIdent()\n+\t\t\t\t\t\t\t\t.getEmailAddress();\n+\t\t\t\t\t\tif (email != null) {\n+\t\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\t\temail = email.toLowerCase();\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\tif (email.indexOf(findPattern) != -1) {\n+\t\t\t\t\t\t\t\ttotalMatches++;\n+\t\t\t\t\t\t\t\tfindResults.add(i);\n+\t\t\t\t\t\t\t\tnotFound = false;\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\n+\t\t\t\tif (totalMatches == MAX_RESULTS) {\n+\t\t\t\t\tmaxResultsOverflow = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t}\n+\n+\t\t// Updates the toolbar with the result find info.\n+\t\tfinal boolean overflow = maxResultsOverflow;\n+\t\ttoolbar.getDisplay().syncExec(new Runnable() {\n+\t\t\tpublic void run() {\n+\t\t\t\tif (toolbar.isDisposed()) {\n+\t\t\t\t\treturn;\n+\t\t\t\t}\n+\t\t\t\ttoolbar.findCompletionUpdate(pattern, overflow);\n+\t\t\t}\n+\t\t});\n+\t}\n+\n+\tstatic void updateGlobalThreadIx() {\n+\t\t++globalThreadIx;\n+\t}\n+}\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java\nindex 3b6d1c9..0a3e3b8 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java\n@@ -29,6 +29,7 @@ import org.eclipse.jface.action.Action;\n import org.eclipse.jface.action.IAction;\n import org.eclipse.jface.action.IContributionItem;\n import org.eclipse.jface.action.IMenuManager;\n+import org.eclipse.jface.action.IToolBarManager;\n import org.eclipse.jface.action.MenuManager;\n import org.eclipse.jface.action.Separator;\n import org.eclipse.jface.text.ITextOperationTarget;\n@@ -46,6 +47,8 @@ import org.eclipse.swt.layout.GridData;\n import org.eclipse.swt.layout.GridLayout;\n import org.eclipse.swt.widgets.Composite;\n import org.eclipse.swt.widgets.Control;\n+import org.eclipse.swt.widgets.Event;\n+import org.eclipse.swt.widgets.Listener;\n import org.eclipse.team.ui.history.HistoryPage;\n import org.eclipse.ui.IActionBars;\n import org.eclipse.ui.IPartListener;\n@@ -59,13 +62,13 @@ import org.eclipse.ui.progress.IWorkbenchSiteProgressService;\n import org.spearce.egit.core.ResourceList;\n import org.spearce.egit.core.project.RepositoryMapping;\n import org.spearce.egit.ui.Activator;\n+import org.spearce.egit.ui.UIIcons;\n import org.spearce.egit.ui.UIPreferences;\n import org.spearce.egit.ui.UIText;\n import org.spearce.jgit.lib.AnyObjectId;\n import org.spearce.jgit.lib.Repository;\n import org.spearce.jgit.revplot.PlotCommit;\n import org.spearce.jgit.revwalk.RevCommit;\n-import org.spearce.jgit.revwalk.RevFlag;\n import org.spearce.jgit.revwalk.RevSort;\n import org.spearce.jgit.revwalk.filter.RevFilter;\n import org.spearce.jgit.treewalk.TreeWalk;\n@@ -85,6 +88,8 @@ public class GitHistoryPage extends HistoryPage {\n \n \tprivate static final String SPLIT_INFO = UIPreferences.RESOURCEHISTORY_REV_SPLIT;\n \n+\tprivate static final String SHOW_FIND_TOOLBAR = UIPreferences.RESOURCEHISTORY_SHOW_FINDTOOLBAR;\n+\n \tprivate static final String POPUP_ID = \"org.spearce.egit.ui.historyPageContributions\";\n \n \t/**\n@@ -147,6 +152,9 @@ public class GitHistoryPage extends HistoryPage {\n \t/** Viewer displaying file difference implied by {@link #graph}'s commit. */\n \tprivate CommitFileDiffViewer fileViewer;\n \n+\t/** Toolbar to find commits in the history view. */\n+\tprivate FindToolbar findToolbar;\n+\n \t/** Our context menu manager for the entire page. */\n \tprivate MenuManager popupMgr;\n \n@@ -157,14 +165,6 @@ public class GitHistoryPage extends HistoryPage {\n \tprivate SWTWalk currentWalk;\n \n \t/**\n-\t * Highlight flag that can be applied to commits to make them stand out.\n-\t * <p>\n-\t * Allocated at the same time as {@link #currentWalk}. If the walk\n-\t * rebuilds, so must this flag.\n-\t */\n-\tprivate RevFlag highlightFlag;\n-\n-\t/**\n \t * List of paths we used to limit {@link #currentWalk}; null if no paths.\n \t * <p>\n \t * Note that a change in this list requires that {@link #currentWalk} and\n@@ -197,12 +197,14 @@ public class GitHistoryPage extends HistoryPage {\n \t\trevInfoSplit = new SashForm(graphDetailSplit, SWT.HORIZONTAL);\n \t\tcommentViewer = new CommitMessageViewer(revInfoSplit);\n \t\tfileViewer = new CommitFileDiffViewer(revInfoSplit);\n+\t\tfindToolbar = new FindToolbar(ourControl);\n \n \t\tlayoutSashForm(graphDetailSplit, SPLIT_GRAPH);\n \t\tlayoutSashForm(revInfoSplit, SPLIT_INFO);\n \n \t\tpopupMgr = new MenuManager(POPUP_ID);\n \t\tattachCommitSelectionChanged();\n+\t\tcreateLocalToolbarActions();\n \t\tcreateStandardActions();\n \t\tcreateViewMenu();\n \n@@ -248,6 +250,7 @@ public class GitHistoryPage extends HistoryPage {\n \tprivate void layout() {\n \t\tfinal boolean showComment = prefs.getBoolean(SHOW_COMMENT);\n \t\tfinal boolean showFiles = prefs.getBoolean(SHOW_FILES);\n+\t\tfinal boolean showFindToolbar = prefs.getBoolean(SHOW_FIND_TOOLBAR);\n \n \t\tif (showComment && showFiles) {\n \t\t\tgraphDetailSplit.setMaximizedControl(null);\n@@ -261,6 +264,13 @@ public class GitHistoryPage extends HistoryPage {\n \t\t} else if (!showComment && !showFiles) {\n \t\t\tgraphDetailSplit.setMaximizedControl(graph.getControl());\n \t\t}\n+\t\tif (showFindToolbar) {\n+\t\t\t((GridData) findToolbar.getLayoutData()).heightHint = SWT.DEFAULT;\n+\t\t} else {\n+\t\t\t((GridData) findToolbar.getLayoutData()).heightHint = 0;\n+\t\t\tfindToolbar.clear();\n+\t\t}\n+\t\tourControl.layout();\n \t}\n \n \tprivate void attachCommitSelectionChanged() {\n@@ -288,6 +298,32 @@ public class GitHistoryPage extends HistoryPage {\n \t\t\t\t\t\tgraph.selectCommit(c);\n \t\t\t\t\t}\n \t\t\t\t});\n+\t\tfindToolbar.addSelectionListener(new Listener() {\n+\t\t\tpublic void handleEvent(Event event) {\n+\t\t\t\tgraph.selectCommit((RevCommit) event.data);\n+\t\t\t}\n+\t\t});\n+\t}\n+\n+\tprivate void createLocalToolbarActions() {\n+\t\tfinal IToolBarManager barManager = getSite().getActionBars()\n+\t\t\t\t.getToolBarManager();\n+\t\tIAction a;\n+\n+\t\ta = createFindToolbarAction();\n+\t\tbarManager.add(a);\n+\t}\n+\n+\tprivate IAction createFindToolbarAction() {\n+\t\tfinal IAction r = new Action(\"Fi\", UIIcons.ELCL16_FIND) {\n+\t\t\tpublic void run() {\n+\t\t\t\tprefs.setValue(SHOW_FIND_TOOLBAR, isChecked());\n+\t\t\t\tlayout();\n+\t\t\t}\n+\t\t};\n+\t\tr.setChecked(prefs.getBoolean(SHOW_FIND_TOOLBAR));\n+\t\tr.setToolTipText(UIText.HistoryPage_findbar_findTooltip);\n+\t\treturn r;\n \t}\n \n \tprivate void createViewMenu() {\n@@ -470,7 +506,6 @@ public class GitHistoryPage extends HistoryPage {\n \t\t\t\t|| pathChange(pathFilters, paths)) {\n \t\t\tcurrentWalk = new SWTWalk(db);\n \t\t\tcurrentWalk.sort(RevSort.COMMIT_TIME_DESC, true);\n-\t\t\thighlightFlag = currentWalk.newFlag(\"highlight\");\n \t\t} else {\n \t\t\tcurrentWalk.reset();\n \t\t}\n@@ -500,7 +535,8 @@ public class GitHistoryPage extends HistoryPage {\n \t\t\tfileWalker.setFilter(TreeFilter.ANY_DIFF);\n \t\t}\n \t\tfileViewer.setTreeWalk(fileWalker);\n-\t\tgraph.setInput(highlightFlag, null, null);\n+\t\tfindToolbar.clear();\n+\t\tgraph.setInput(findToolbar.findResults, null, null);\n \n \t\tfinal SWTCommitList list;\n \t\tlist = new SWTCommitList(graph.getControl().getDisplay());\n@@ -539,7 +575,6 @@ public class GitHistoryPage extends HistoryPage {\n \t\t\t//\n \t\t\tjob = null;\n \t\t\tcurrentWalk = null;\n-\t\t\thighlightFlag = null;\n \t\t\tpathFilters = null;\n \t\t}\n \t}\n@@ -571,8 +606,10 @@ public class GitHistoryPage extends HistoryPage {\n \n \t\tgraph.getControl().getDisplay().asyncExec(new Runnable() {\n \t\t\tpublic void run() {\n-\t\t\t\tif (!graph.getControl().isDisposed() && job == j)\n-\t\t\t\t\tgraph.setInput(highlightFlag, list, asArray);\n+\t\t\t\tif (!graph.getControl().isDisposed() && job == j) {\n+\t\t\t\t\tgraph.setInput(findToolbar.findResults, list, asArray);\n+\t\t\t\t\tfindToolbar.setInput(graph.getTable(), asArray);\n+\t\t\t\t}\n \t\t\t}\n \t\t});\n \t}\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties b/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties\nindex 9672a0d..ef9ebee 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties\n@@ -39,6 +39,18 @@ HistoryPage_dateColumn=Date\n HistoryPage_pathnameColumn=Path\n HistoryPage_refreshJob=Reading history from Git\n \n+HistoryPage_findbar_findTooltip=Find\n+HistoryPage_findbar_find=Find:\n+HistoryPage_findbar_next=next\n+HistoryPage_findbar_previous=previous\n+HistoryPage_findbar_ignorecase=Ignore case\n+HistoryPage_findbar_commit=Commit\n+HistoryPage_findbar_comments=Comments\n+HistoryPage_findbar_author=Author\n+HistoryPage_findbar_committer=Committer\n+HistoryPage_findbar_exceeded=Results limit exceeded\n+HistoryPage_findbar_notFound=String not found\n+\n HistoryPreferencePage_title=Git\n \n WindowCachePreferencePage_title=Git Window Cache\n-- \n1.5.4.1\n"},{"id":"73796","messageId":"20080407051908.GS10274@spearce.org","threadId":"13007","inReplyTo":"1207518109-4174-1-git-send-email-rogersoares@intelinet.com.br","subject":"Re: [EGIT PATCH 1/3] FindToolbar port to the new history page.","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-04-07T05:19:08Z","receivedAt":"2008-04-07T05:19:08Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"\"Roger C. Soares\" <rogersoares@intelinet.com.br> wrote:\n> This is a port from the find toolbar to the new history page.\n> It is replacing the current highlight flag in order to have the\n> find feature back but most of the code from the toolbar shall be\n> replaced to make use of the new infrastructure added into jgit\n> (RevFlag and RevFilter).\n...\n> I'm reseding the toolbar port with the fixes for the items you mentioned.\n> It's on top of 009f11e2c8971b6053, don't know if it would have been better\n> to rebase it, just let me know.\n\nWell, I just rebased my entire tree, and then plopped your four\npatches (these three plus 009f) on top of it.  So no need to rebase.\nThere was a very minor merge conflict, easily fixed, no worries.\n\n> Patch 3/3 is something I've come up to remove the Map hit in the paint\n> method. As you said you were going to revisit the jgit API soon I didn't\n> want to do something too elaborated that will be dumped soon. I'm\n> manipulating RevFlags directly from the find toolbar, so if you don't\n> like just ignore it.\n\nIts better.  I'd like to be able to use more of RevFilter in the\nsearch, but as you pointed out support isn't all there yet.\n\nI'm taking in this series as is.  We can improve on it further later.\n\nThanks.\n\n-- \nShawn.\n"}]}