Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 3b49dfc1816d19ae7126554f2780f4ae078b66ab (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/*******************************************************************************
 * Copyright (C) 2008, Roger C. Soares <rogersoares@intelinet.com.br>
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *******************************************************************************/
package org.eclipse.egit.ui.internal.history;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevObject;

/**
 * Results for the find toolbar. This object stores the rows in the history
 * table that contain a match to a given pattern.
 *
 * @see FindToolbar
 * @see FindToolbarJob
 */
public class FindResults {
	private Map<Integer, Integer> matchesMap = new LinkedHashMap<>();

	private List<RevObject> revObjList = new ArrayList<>();

	Integer[] keysArray;

	private int matchesCount;

	private RevFlag highlight;

	private boolean overflow;

	private final CopyOnWriteArrayList<IFindListener> listeners = new CopyOnWriteArrayList<>();

	/**
	 * Adds the given listener to be notified when search results are added or
	 * the results are cleared. Has no effect if the listener is already
	 * registered.
	 *
	 * @param listener
	 *            to add
	 */
	public void addFindListener(IFindListener listener) {
		listeners.addIfAbsent(listener);
	}

	/**
	 * Removes the given listener if it was registered.
	 *
	 * @param listener
	 *            to remove
	 */
	public void removeFindListener(IFindListener listener) {
		listeners.remove(listener);
	}

	/**
	 * Returns if the index in the history table matches the find pattern.
	 *
	 * @param index
	 *            history table item index.
	 * @return boolean <code>true</code> if the history table <code>index</code>
	 *         contains a match to the find pattern, <code>false</code>
	 *         otherwise
	 */
	public synchronized boolean isFoundAt(int index) {
		return matchesMap.containsKey(Integer.valueOf(index));
	}

	/**
	 * Returns the first table item index after <code>index</code> that
	 * contains a match to the find pattern.
	 *
	 * @param index
	 *            the history table item index
	 * @return the index after <code>index</code> that contains a match.
	 *         Returns -1 if there isn't a match after <code>index</code>
	 */
	public synchronized int getIndexAfter(int index) {
		Integer[] matches = getkeysArray();
		int sres = Arrays.binarySearch(matches, Integer.valueOf(index));
		if (sres >= 0 && sres != matches.length - 1) {
			return matches[sres + 1].intValue();
		} else if (sres < 0) {
			sres = -sres - 1;
			if (sres < matches.length) {
				return matches[sres].intValue();
			}
		}

		return -1;
	}

	/**
	 * Returns the first table item index before <code>index</code> that
	 * contains a match to the find pattern.
	 *
	 * @param index
	 *            the history table item index
	 * @return the index before <code>index</code> that contains a match.
	 *         Returns -1 if there isn't a match before <code>index</code>
	 */
	public synchronized int getIndexBefore(int index) {
		Integer[] matches = getkeysArray();
		int sres = Arrays.binarySearch(matches, Integer.valueOf(index));
		if (sres >= 0 && sres != 0) {
			return matches[sres - 1].intValue();
		} else if (sres < -1) {
			sres = -sres;
			return matches[sres - 2].intValue();
		}

		return -1;
	}

	/**
	 * Returns the first table item index that contains a match to the find
	 * pattern.
	 *
	 * @return the first index that contains a match. Returns -1 if there isn't
	 *         any match
	 */
	public synchronized int getFirstIndex() {
		Iterator iter = matchesMap.keySet().iterator();
		if (iter.hasNext()) {
			return ((Integer) iter.next()).intValue();
		}

		return -1;
	}

	/**
	 * Returns the last table item index that contains a match to the find
	 * pattern.
	 *
	 * @return the last index that contains a match. Returns -1 if there isn't
	 *         any match
	 */
	public synchronized int getLastIndex() {
		Integer[] matches = getkeysArray();
		if (matches.length > 0) {
			return matches[matches.length - 1].intValue();
		}

		return -1;
	}

	/**
	 * Returns the index in the matches list for the history table item
	 * <code>index</code>.
	 *
	 * @param index
	 *            the history table item index
	 * @return the position of the <code>index</code> in the total matches
	 *         list. Returns -1 if <code>index</code> doesn't contain a match
	 */
	public synchronized int getMatchNumberFor(int index) {
		Integer ix = matchesMap.get(Integer.valueOf(index));
		if (ix != null) {
			return ix.intValue();
		}

		return -1;
	}

	/**
	 * @return int
	 */
	public int size() {
		return matchesCount;
	}

	/**
	 * Cleans the find results. All match item indexes are removed.
	 */
	public synchronized void clear() {
		if (highlight != null) {
			for (RevObject o : revObjList) {
				o.remove(highlight);
			}
		}
		matchesMap.clear();
		revObjList.clear();
		keysArray = null;
		boolean hadItems = matchesCount > 0;
		matchesCount = 0;
		if (hadItems) {
			for (IFindListener listener : listeners) {
				listener.cleared();
			}
		}
	}

	/**
	 * Adds a history table item index (<code>matchIx</code>) to the find
	 * results matches list.
	 *
	 * @param matchIx
	 *            the history table item index that matches a find pattern.
	 * @param revObj
	 *            The RevObject that will have the highlight tag set.
	 */
	public synchronized void add(int matchIx, RevObject revObj) {
		matchesMap.put(Integer.valueOf(matchIx), Integer
				.valueOf(++matchesCount));
		revObjList.add(revObj);
		revObj.add(highlight);
		keysArray = null;
		for (IFindListener listener : listeners) {
			listener.itemAdded(matchIx, revObj);
		}
	}

	private Integer[] getkeysArray() {
		if (keysArray == null) {
			keysArray = matchesMap.keySet().toArray(
					new Integer[matchesMap.size()]);
		}

		return keysArray;
	}

	synchronized void setHighlightFlag(RevFlag hFlag) {
		if (highlight != null) {
			clear();
		}
		this.highlight = hFlag;
	}

	synchronized void setOverflow() {
		overflow = true;
	}

	synchronized boolean isOverflow() {
		return overflow;
	}
}

Back to the top