{"thread":{"id":"11788","subject":"[EGIT PATCH] History page find toolbar.","startedAt":"2008-01-29T21:39:50Z","lastAt":"2008-01-30T21:20:28Z","messageCount":2,"participants":["Roger C. Soares","Robin Rosenberg"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"66856","messageId":"1201642790-18508-1-git-send-email-rogersoares@intelinet.com.br","threadId":"11788","inReplyTo":null,"subject":"[EGIT PATCH] History page find toolbar.","fromName":"Roger C. Soares","fromEmail":"rogersoares@intelinet.com.br","sentAt":"2008-01-29T21:39:50Z","receivedAt":"2008-01-29T21:39:50Z","isPatch":true,"sender":{"key":"rogersoares@intelinet.com.br","avatar":null},"body":"Signed-off-by: Roger C. Soares <rogersoares@intelinet.com.br>\n---\nHi Robin,\n\nRe-sending the patch.\n\n[]s,\nRoger.\n\n\n org.spearce.egit.ui/icons/elcl16/find.gif          |  Bin 0 -> 546 bytes\n org.spearce.egit.ui/icons/elcl16/next.gif          |  Bin 0 -> 353 bytes\n org.spearce.egit.ui/icons/elcl16/previous.gif      |  Bin 0 -> 352 bytes\n .../src/org/spearce/egit/ui/FindResults.java       |  184 ++++++++\n .../src/org/spearce/egit/ui/FindToolbar.java       |  442 ++++++++++++++++++++\n .../src/org/spearce/egit/ui/FindToolbarThread.java |  245 +++++++++++\n .../src/org/spearce/egit/ui/GitHistoryPage.java    |   97 ++++-\n .../egit/ui/PluginPreferenceInitializer.java       |    6 +\n .../src/org/spearce/egit/ui/UIIcons.java           |   10 +\n .../src/org/spearce/egit/ui/UIPreferences.java     |   12 +\n 10 files changed, 984 insertions(+), 12 deletions(-)\n create mode 100644 org.spearce.egit.ui/icons/elcl16/find.gif\n create mode 100644 org.spearce.egit.ui/icons/elcl16/next.gif\n create mode 100644 org.spearce.egit.ui/icons/elcl16/previous.gif\n create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/FindResults.java\n create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/FindToolbar.java\n create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/FindToolbarThread.java\n\ndiff --git a/org.spearce.egit.ui/icons/elcl16/find.gif b/org.spearce.egit.ui/icons/elcl16/find.gif\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..eba31f7545aaa9ae6917ee49fdc99f8252fd2f1e\nGIT binary patch\nliteral 546\nzcmZ?wbhEHb6krfwI2OoI>F>~#m)BXC(^Zt+Rg}|Hl+{^U++9}G)Y;M4Giy#~)4Z<6\nz&WSU6rY-KBwq(lm36o|moIPXqyje3A%xzdQuVTgg!UYSbFI_Tq{j!pc%S#un+PZB`\nz!<J36_H3WBe*59AJGN}zd2rXR4SV;j*|z7%uD!c<?>}(l;M!wHwx2$_{LrzJ2aa7h\nzb$sKcbK5RnI(O;v`Ab)>UA=nl^7UI+Z$7wr^Va>l7jE5qaO>WqyZ0a7dGPqo!zcG1\nzK6&)$_M^v79zK5l?Af!&&tE-${`%>QS1(??c=_ht%Qx@ezkB`e!>4y2KY#l4>C2Zd\nz-@knR{PpXXZ{NRt|NisWZy@;h@8AEy1QdU=Fmf@}Gw3h?0Vqxw*y|hWo0?l%TXZC(\nzr6o1mnq}4OJUl&3MEkVWodV_r_`8a<2^;$@UFIue-70S5vu?e&fl{lOx%>7VZn}!C\nz{Q52j4m!*0wW_F^I-GK_cjV~f(KIx(w6GEo>Z|AFQ&5)T6!hZ0WveA;6j;y2z<R5V\nVg@O5fD-#3zmlih0pKXl{)&N)1Y_<RZ\n\nliteral 0\nHcmV?d00001\n\ndiff --git a/org.spearce.egit.ui/icons/elcl16/next.gif b/org.spearce.egit.ui/icons/elcl16/next.gif\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..cd84203b6b1081fde08c2c9fc89733c318ffe83d\nGIT binary patch\nliteral 353\nzcmZ?wbhEHb6krfwSZc_yEL&iCj=+jMfz<_qs|$qI7748>7F=H{w7yh$W4Z9Aa^Z~?\nz!ka3Dw^RX<$o3kMZM7mh>O^+di|lF?-Q6g<r%7yYi`ehG&A;z={kh-u`{Cr@kAP^(\nzpGTAbJeu<R>HI%W=l^~-{|^woT>a<enm=!M{`q+P@5f_*f#jFV|Gr%Q`}OkQANT+L\nzy!ZFli+{gf{`>vnKPf=*pP+M5YGO%hib8p2Nrr;Er*8m*;!hSvE(UuB9R?r(d6a=I\nz^T7N94;`ucX-l4ZY&npy?)s#kt8EsGzUn`ev^7F_ZOYWBl}b?^FI${!xAach^Ta|;\nzf{QKlNW97?7Y_Mm1qCGqMFn|wS2kHWDLENwX*pJRW{Fvn5|S(-OyY~gnWF3&7cnk#\nMVqjRk%#pzw044ms4gdfE\n\nliteral 0\nHcmV?d00001\n\ndiff --git a/org.spearce.egit.ui/icons/elcl16/previous.gif b/org.spearce.egit.ui/icons/elcl16/previous.gif\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..a53606bdb5b8ba72b35e9ab8d90e33cad92ca15a\nGIT binary patch\nliteral 352\nzcmZ?wbhEHb6krfwSZc_yEL&iCj=+jMfz<_qs|$qI7748>7F=H{w7yh$W4Z9Aa^Z~?\nz!ka3Dw^RX<$o3kMZM7mh>O^+di|lF?-Q6g<r%7yYi`ehG&A;z={kh-u`{Cr@kAP^(\nzpGTAbJeu<R>HI%W=l^~-{|^woT>a<enm=!M{`q+P@5f_*f#jFV|Gr%Q`}OkQANT+L\nzy!ZFli+{gf{`>vnKPf=*pP+M5YGO%hib8p2Nrr;Er*8m*;!hSvE(UuB9R?r(d6a=I\nz<G}m^4;`sih65KRcEm89UU=Z8hzt9S9Ja}dGQ6_=#}41jv1wI$beOHtWr4tpVg)q`\nzF1E}g@hYF(c~zTL`2y_))YLUJ_}hiFHMO+_+eLJAbajN=MGXw}^hMjn<}Va$w-;Nz\nKVr9D{gEasd9K1CE\n\nliteral 0\nHcmV?d00001\n\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/FindResults.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/FindResults.java\nnew file mode 100644\nindex 0000000..d3005fe\n--- /dev/null\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/FindResults.java\n@@ -0,0 +1,184 @@\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;\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(new Integer(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, new Integer(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, new Integer(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(new Integer(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(new Integer(matchIx), new Integer(++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/FindToolbar.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/FindToolbar.java\nnew file mode 100644\nindex 0000000..310032a\n--- /dev/null\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/FindToolbar.java\n@@ -0,0 +1,442 @@\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;\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.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.eclipse.team.core.history.IFileRevision;\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+\tPreferences prefs = Activator.getDefault().getPluginPreferences();\n+\n+\tList<Listener> eventList = new ArrayList<Listener>();\n+\n+\tprivate Image nextIcon;\n+\n+\tprivate Image previousIcon;\n+\n+\tTable historyTable;\n+\n+\tList<IFileRevision> fileRevisions;\n+\n+\tText patternField;\n+\n+\tButton nextButton;\n+\n+\tButton previousButton;\n+\n+\tLabel currentPositionLabel;\n+\n+\tProgressBar 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(\"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(\"next\");\n+\n+\t\tpreviousButton = new Button(this, SWT.HORIZONTAL);\n+\t\tpreviousButton.setImage(previousIcon);\n+\t\tpreviousButton.setText(\"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(\"Ignore case\");\n+\t\tnew MenuItem(prefsMenu, SWT.SEPARATOR);\n+\t\tfinal MenuItem commitIdItem = new MenuItem(prefsMenu, SWT.CHECK);\n+\t\tcommitIdItem.setText(\"Revision\");\n+\t\tfinal MenuItem commentsItem = new MenuItem(prefsMenu, SWT.CHECK);\n+\t\tcommentsItem.setText(\"Comments\");\n+\t\tfinal MenuItem authorItem = new MenuItem(prefsMenu, SWT.CHECK);\n+\t\tauthorItem.setText(\"Author\");\n+\t\tfinal MenuItem committerItem = new MenuItem(prefsMenu, SWT.CHECK);\n+\t\tcommitterItem.setText(\"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\tDisplay.getDefault().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\tListener 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\thistoryTable.setSelection(newIx);\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\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, committerItem\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\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 * \n+\t * @param historyTable\n+\t *            the history page <code>Table</code>\n+\t */\n+\tpublic void setHistoryTable(Table historyTable) {\n+\t\tthis.historyTable = historyTable;\n+\t}\n+\n+\t/**\n+\t * Sets the list to be searched.\n+\t * \n+\t * @param fileRevisions\n+\t *            the revision list to be searched\n+\t */\n+\tpublic void setFileRevisions(List<IFileRevision> fileRevisions) {\n+\t\tthis.fileRevisions = fileRevisions;\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.setText(\"Results limit exceed 1/\" + 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\thistoryTable.setSelection(ix);\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.setText(\"String not found\");\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\tDisplay.getDefault().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 = Display.getCurrent();\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+\t/* private */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\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/FindToolbarThread.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/FindToolbarThread.java\nnew file mode 100644\nindex 0000000..20083f4\n--- /dev/null\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/FindToolbarThread.java\n@@ -0,0 +1,245 @@\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;\n+\n+import java.util.List;\n+\n+import org.eclipse.swt.widgets.Display;\n+import org.eclipse.team.core.history.IFileRevision;\n+import org.spearce.egit.core.internal.mapping.GitCommitFileRevision;\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 int MAX_RESULTS = 20000;\n+\n+\tString pattern;\n+\n+\tList<IFileRevision> 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 static Display display = Display.getDefault();\n+\n+\tprivate 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\texecFind(currentThreadIx, fileRevisions, pattern, toolbar, ignoreCase,\n+\t\t\t\tfindInCommitId, findInComments, findInAuthor, findInCommitter);\n+\t}\n+\n+\tprivate synchronized static void execFind(int threadIx,\n+\t\t\tList<IFileRevision> fileRevisions, final String pattern,\n+\t\t\tfinal FindToolbar toolbar, boolean ignoreCase,\n+\t\t\tboolean findInCommitId, boolean findInComments,\n+\t\t\tboolean findInAuthor, boolean findInCommitter) {\n+\t\t// If it isn't the last event, just ignore it.\n+\t\tif (threadIx < 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.size();\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 (display.isDisposed() || threadIx < 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\tdisplay.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\tIFileRevision fileRevision = fileRevisions.get(i);\n+\t\t\t\tif (fileRevision instanceof GitCommitFileRevision) {\n+\t\t\t\t\tGitCommitFileRevision revision = (GitCommitFileRevision) fileRevision;\n+\n+\t\t\t\t\tif (findInCommitId) {\n+\t\t\t\t\t\tString contentId = revision.getContentIdentifier();\n+\t\t\t\t\t\tif (contentId != null) {\n+\t\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\t\tcontentId = contentId.toLowerCase();\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\tif (contentId.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+\n+\t\t\t\t\tif (findInComments && notFound) {\n+\t\t\t\t\t\tString comment = revision.getComment();\n+\t\t\t\t\t\tif (comment != null) {\n+\t\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\t\tcomment = comment.toLowerCase();\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\tif (comment.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+\n+\t\t\t\t\tif (findInAuthor && notFound) {\n+\t\t\t\t\t\tString author = revision.getCommit().getAuthor()\n+\t\t\t\t\t\t\t\t.getName();\n+\t\t\t\t\t\tif (author != null) {\n+\t\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\t\tauthor = author.toLowerCase();\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\tif (author.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\tif (notFound) {\n+\t\t\t\t\t\t\tString email = revision.getCommit().getAuthor()\n+\t\t\t\t\t\t\t\t\t.getEmailAddress();\n+\t\t\t\t\t\t\tif (email != null) {\n+\t\t\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\t\t\temail = email.toLowerCase();\n+\t\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\t\tif (email.indexOf(findPattern) != -1) {\n+\t\t\t\t\t\t\t\t\ttotalMatches++;\n+\t\t\t\t\t\t\t\t\tfindResults.add(i);\n+\t\t\t\t\t\t\t\t\tnotFound = false;\n+\t\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\n+\t\t\t\t\tif (findInCommitter && notFound) {\n+\t\t\t\t\t\tString committer = revision.getCommit().getCommitter()\n+\t\t\t\t\t\t\t\t.getName();\n+\t\t\t\t\t\tif (committer != null) {\n+\t\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\t\tcommitter = committer.toLowerCase();\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\tif (committer.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\tif (notFound) {\n+\t\t\t\t\t\t\tString email = revision.getCommit().getCommitter()\n+\t\t\t\t\t\t\t\t\t.getEmailAddress();\n+\t\t\t\t\t\t\tif (email != null) {\n+\t\t\t\t\t\t\t\tif (ignoreCase) {\n+\t\t\t\t\t\t\t\t\temail = email.toLowerCase();\n+\t\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\t\tif (email.indexOf(findPattern) != -1) {\n+\t\t\t\t\t\t\t\t\ttotalMatches++;\n+\t\t\t\t\t\t\t\t\tfindResults.add(i);\n+\t\t\t\t\t\t\t\t\tnotFound = false;\n+\t\t\t\t\t\t\t\t}\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+\t\t}\n+\n+\t\t// Updates the toolbar with the result find info.\n+\t\tfinal boolean overflow = maxResultsOverflow;\n+\t\tdisplay.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/GitHistoryPage.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/GitHistoryPage.java\nindex 289331c..5cdbcea 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/GitHistoryPage.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/GitHistoryPage.java\n@@ -18,6 +18,7 @@ package org.spearce.egit.ui;\n \n import java.io.IOException;\n import java.text.SimpleDateFormat;\n+import java.util.Collections;\n import java.util.Date;\n import java.util.HashMap;\n import java.util.List;\n@@ -60,6 +61,8 @@ import org.eclipse.swt.events.MouseEvent;\n import org.eclipse.swt.events.MouseMoveListener;\n import org.eclipse.swt.events.SelectionAdapter;\n import org.eclipse.swt.events.SelectionEvent;\n+import org.eclipse.swt.graphics.Font;\n+import org.eclipse.swt.graphics.FontData;\n import org.eclipse.swt.graphics.Point;\n import org.eclipse.swt.layout.GridData;\n import org.eclipse.swt.layout.GridLayout;\n@@ -111,9 +114,12 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \tprivate static final String PREF_SHOWALLFOLDERVERSIONS = \"org.spearce.egit.ui.githistorypage.showallfolderversions\";\n \t/* private */static final SimpleDateFormat DATETIME_FORMAT = new SimpleDateFormat(\"yyyy-MM-dd HH:mm\");\n \t/* private */static final SimpleDateFormat DATETIMETZ_FORMAT = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss z\");\n+\t/* private */Font BANNER_FONT_BOLD;\n \n+\tprivate Composite parentComposite;\n \tprivate SashForm localComposite;\n \tprivate SashForm revisionInfoComposite;\n+\t/* private */FindToolbar findToolbar;\n \n \t/* private */Preferences prefs = Activator.getDefault().getPluginPreferences();\n \n@@ -124,6 +130,7 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \t/* private */IAction toggleRevDetailAction;\n \t/* private */IAction toggleRevCommentAction;\n \t/* private */IAction toggleTooltipsAction;\n+\t/* private */IAction findAction;\n \n \t/* private */Table table;\n \tprivate MouseMoveListener tableMouseMoveListener;\n@@ -162,16 +169,35 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \t}\n \n \tpublic void createControl(Composite parent) {\n-\t\tlocalComposite = new SashForm(parent, SWT.VERTICAL);\n-\n-\t\tGridLayout layout = new GridLayout();\n-\t\tlayout.marginHeight = 0;\n-\t\tlayout.marginWidth = 0;\n-\t\tlocalComposite.setLayout(layout);\n+\t\tFont bannerFont = JFaceResources.getBannerFont();\n+\t\tBANNER_FONT_BOLD = new Font(parent.getDisplay(), \n+\t\t\t\tnew FontData(bannerFont.getFontData()[0].getName(), bannerFont.getFontData()[0].getHeight(), SWT.BOLD));\n+\n+\t\tparentComposite = new Composite(parent, SWT.NULL);\n+\t\tGridLayout parentLayout = new GridLayout();\n+\t\tparentLayout.marginHeight = 0;\n+\t\tparentLayout.marginWidth = 0;\n+\t\tparentLayout.verticalSpacing = 0;\n+\t\tparentComposite.setLayout(parentLayout);\n+\t\tGridData parentData = new GridData(SWT.FILL, SWT.FILL, true, true);\n+\t\tparentComposite.setLayoutData(parentData);\n+\n+\t\tlocalComposite = new SashForm(parentComposite, SWT.VERTICAL);\n \t\tGridData data = new GridData(SWT.FILL, SWT.FILL, true, true);\n-\t\tdata.grabExcessVerticalSpace = true;\n \t\tlocalComposite.setLayoutData(data);\n \n+\t\tfindToolbar = new FindToolbar(parentComposite);\n+\t\tfindToolbar.addSelectionListener(new Listener() {\n+\t\t\tpublic void handleEvent(Event event) {\n+\t\t\t\tcleanRevisionInfoTextViewers();\n+\t\t\t\tint ix = table.getSelectionIndex();\n+\t\t\t\tIFileRevision revision = fileRevisions.get(ix);\n+\t\t\t\tif(revision instanceof GitCommitFileRevision) {\n+\t\t\t\t\tsetRevisionInfoTextViewers((GitCommitFileRevision) revision);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t});\n+\n \t\tcreateTable(localComposite);\n \n \t\trevisionInfoComposite = new SashForm(localComposite, SWT.HORIZONTAL);\n@@ -278,6 +304,18 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \t\tResourcesPlugin.getWorkspace().addResourceChangeListener(\n \t\t\t\tresourceListener, IResourceChangeEvent.POST_CHANGE);\n \n+\t\tfindAction = new Action(\"Fi\", UIIcons.ELCL16_FIND) {\n+\t\t\tpublic void run() {\n+\t\t\t\tshowHideFindToolbar();\n+\t\t\t\tprefs.setValue(UIPreferences.RESOURCEHISTORY_SHOW_FINDTOOLBAR, findAction.isChecked());\n+\t\t\t\tActivator.getDefault().savePluginPreferences();\n+\t\t\t}\n+\t\t};\n+\t\tfindAction.setToolTipText(\"Find\");\n+\t\tfindAction.setChecked(prefs.getBoolean(UIPreferences.RESOURCEHISTORY_SHOW_FINDTOOLBAR));\n+\t\tgetSite().getActionBars().getToolBarManager()\n+\t\t\t\t.add(findAction);\n+\n \t\tAction showAllRepoVersionsAction = new Action(\"R\") {\n \t\t\tpublic void run() {\n \t\t\t\tsetShowAllRepoVersions(isChecked());\n@@ -378,6 +416,7 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \t\tactionBars.updateActionBars();\n \t\tupdateResourceHistoryComposites();\n \t\tupdateShowTooltips();\n+\t\tshowHideFindToolbar();\n \n \t\tlocalComposite.setWeights(new int[] {65, 35});\n \t\trevisionInfoComposite.setWeights(new int[] {40, 60});\n@@ -420,6 +459,18 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \t\t}\n \t}\n \n+\t/* private */void showHideFindToolbar() {\n+\t\tboolean showFindToobar = findAction.isChecked();\n+\n+\t\tif(showFindToobar) {\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\tparentComposite.layout();\n+\t}\n+\n \t/* private */boolean isShowAllRepoVersions() {\n \t\treturn showAllRepoVersions;\n \t}\n@@ -735,7 +786,7 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \t\treturn sb.toString();\n \t}\n \n-\t/* private */void cleanRevisionInfoTextViewers() {\n+\tvoid cleanRevisionInfoTextViewers() {\n \t\tif(revDetailTextViewer != null && revCommentTextViewer != null) {\n \t\t\trevDetailTextViewer.setDocument(new Document(\"\"));\n \t\t\trevCommentTextViewer.setDocument(new Document(\"\"));\n@@ -756,6 +807,8 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \t\tGridData data = new GridData(SWT.FILL, SWT.FILL, true, true);\n \t\ttable.setLayoutData(data);\n \t\ttable.setData(\"HEAD\");\n+\t\tfindToolbar.setHistoryTable(table);\n+\t\tfindToolbar.clear();\n \t\ttable.addListener(SWT.SetData, new Listener() {\n \t\t\tpublic void handleEvent(Event event) {\n \t\t\t\ttry {\n@@ -780,7 +833,12 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \t\t\t\t\t\telse\n \t\t\t\t\t\t\titem.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY));\n \t\t\t\t\t}\n-\t\t\t\t\titem.setFont(0,JFaceResources.getBannerFont());\n+\n+\t\t\t\t\tif (findToolbar.findResults.isFoundAt(event.index)) {\n+\t\t\t\t\t\titem.setFont(BANNER_FONT_BOLD);\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\titem.setFont(0,JFaceResources.getBannerFont());\n+\t\t\t\t\t}\n \t\t\t\t} catch (Throwable b) {\n \t\t\t\t\tb.printStackTrace();\n \t\t\t\t}\n@@ -992,7 +1050,16 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \t\t\t\t\t\t\t\t-1,\n \t\t\t\t\t\t\t\tmonitor,\n \t\t\t\t\t\t\t\tisShowAllRepoVersions());\n-\t\t\t\tfileRevisions = fileHistoryFor.getFileRevisionsList();\n+\t\t\t\tfileRevisions = Collections.synchronizedList(fileHistoryFor.getFileRevisionsList());\n+\t\t\t\tfindToolbar.setFileRevisions(fileRevisions);\n+\t\t\t\tDisplay.getDefault().syncExec(new Runnable() {\n+\t\t\t\t\tpublic void run() {\n+\t\t\t\t\t\tif (findToolbar.isDisposed()) {\n+\t\t\t\t\t\t\treturn;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t\tfindToolbar.clear();\n+\t\t\t\t\t}\n+\t\t\t\t});\n \t\t\t\tfinal Map fnewappliedPatches = newappliedPatches;\n \t\t\t\tfinal Map<ObjectId,Tag[]> ftags = newtags;\n \t\n@@ -1118,11 +1185,11 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \t}\n \n \tpublic Control getControl() {\n-\t\treturn localComposite;\n+\t\treturn parentComposite;\n \t}\n \n \tpublic void setFocus() {\n-\t\tlocalComposite.setFocus();\n+\t\tparentComposite.setFocus();\n \t}\n \n \tpublic String getDescription() {\n@@ -1218,4 +1285,10 @@ public class GitHistoryPage extends HistoryPage implements IAdaptable,\n \t\treturn result.toString();\n \t}\n \n+\t@Override\n+\tpublic void dispose() {\n+\t\tBANNER_FONT_BOLD.dispose();\n+\t\tsuper.dispose();\n+\t}\n+\n }\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/PluginPreferenceInitializer.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/PluginPreferenceInitializer.java\nindex ab89bec..ecb79b8 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/PluginPreferenceInitializer.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/PluginPreferenceInitializer.java\n@@ -41,6 +41,12 @@ public class PluginPreferenceInitializer extends AbstractPreferenceInitializer {\n \t\tprefs.setDefault(UIPreferences.RESOURCEHISTORY_SHOW_REV_DETAIL, true);\n \t\tprefs.setDefault(UIPreferences.RESOURCEHISTORY_SHOW_REV_COMMENT, true);\n \t\tprefs.setDefault(UIPreferences.RESOURCEHISTORY_SHOW_TOOLTIPS, false);\n+\n+\t\tprefs.setDefault(UIPreferences.FINDTOOLBAR_IGNORE_CASE, true);\n+\t\tprefs.setDefault(UIPreferences.FINDTOOLBAR_COMMIT_ID, true);\n+\t\tprefs.setDefault(UIPreferences.FINDTOOLBAR_COMMENTS, true);\n+\t\tprefs.setDefault(UIPreferences.FINDTOOLBAR_AUTHOR, false);\n+\t\tprefs.setDefault(UIPreferences.FINDTOOLBAR_COMMITTER, false);\n \t}\n \n }\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIIcons.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIIcons.java\nindex bc3706a..881265d 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIIcons.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIIcons.java\n@@ -40,6 +40,13 @@ public class UIIcons {\n \t/** Decoration for tracked resources that we want to ignore changes in. */\n \tpublic static final ImageDescriptor OVR_ASSUMEVALID;\n \n+\t/** Find icon */\n+\tpublic static final ImageDescriptor ELCL16_FIND;\n+\t/** Next arrow icon */\n+\tpublic static final ImageDescriptor ELCL16_NEXT;\n+\t/** Previous arrow icon */\n+\tpublic static final ImageDescriptor ELCL16_PREVIOUS;\n+\n \tprivate static final URL base;\n \n \tstatic {\n@@ -49,6 +56,9 @@ public class UIIcons {\n \t\tOVR_SHARED = map(\"ovr/shared.gif\");\n \t\tOVR_CONFLICT = map(\"ovr/conflict.gif\");\n \t\tOVR_ASSUMEVALID = map(\"ovr/assumevalid.gif\");\n+\t\tELCL16_FIND = map(\"elcl16/find.gif\");\n+\t\tELCL16_NEXT = map(\"elcl16/next.gif\");\n+\t\tELCL16_PREVIOUS = map(\"elcl16/previous.gif\");\n \t}\n \n \tprivate static ImageDescriptor map(final String icon) {\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIPreferences.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIPreferences.java\nindex 900023a..cb9443b 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIPreferences.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIPreferences.java\n@@ -29,4 +29,16 @@ public class UIPreferences {\n \tpublic final static String RESOURCEHISTORY_SHOW_REV_COMMENT = \"resourcehistory_show_rev_comment\";\n \t/** */\n \tpublic final static String RESOURCEHISTORY_SHOW_TOOLTIPS = \"resourcehistory_show_tooltips\";\n+\t/** */\n+\tpublic final static String RESOURCEHISTORY_SHOW_FINDTOOLBAR = \"resourcehistory_show_findtoolbar\";\n+\t/** */\n+\tpublic final static String FINDTOOLBAR_IGNORE_CASE = \"findtoolbar_ignore_case\";\n+\t/** */\n+\tpublic final static String FINDTOOLBAR_COMMIT_ID = \"findtoolbar_commit_id\";\n+\t/** */\n+\tpublic final static String FINDTOOLBAR_COMMENTS = \"findtoolbar_comments\";\n+\t/** */\n+\tpublic final static String FINDTOOLBAR_AUTHOR = \"findtoolbar_author\";\n+\t/** */\n+\tpublic final static String FINDTOOLBAR_COMMITTER = \"findtoolbar_committer\";\n }\n-- \n1.5.3.7\n"},{"id":"66930","messageId":"200801302220.29166.robin.rosenberg@dewire.com","threadId":"11788","inReplyTo":"1201642790-18508-1-git-send-email-rogersoares@intelinet.com.br","subject":"Re: [EGIT PATCH] History page find toolbar.","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2008-01-30T21:20:28Z","receivedAt":"2008-01-30T21:20:28Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"tisdagen den 29 januari 2008 skrev Roger C. Soares:\n> Signed-off-by: Roger C. Soares <rogersoares@intelinet.com.br>\n> ---\n> Hi Robin,\n> \n> Re-sending the patch.\n> \n\nThanks - Excellent! - Pushed.\n\n-- robin\n"}]}