Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 060bc54d9ce373c9be8d45c7670f2d33677c1594 (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
/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jface.text.link;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

import org.eclipse.jface.text.Assert;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.link.LinkedPosition;



/**
 * Iterator that leaps over the double occurrence of an element when switching from forward
 * to backward iteration that is shown by <code>ListIterator</code>.
 * <p>
 * Package private, only for use by LinkedModeUI.
 * </p>
 * @since 3.0
 */
class TabStopIterator {
	/**
	 * Comparator for <code>LinkedPosition</code>s. If the sequence nr. of two positions is equal, the
	 * offset is used.
	 */
	private static class SequenceComparator implements Comparator {

		/**
		 * {@inheritDoc}
		 * 
		 * <p><code>o1</code> and <code>o2</code> are required to be instances
		 * of <code>LinkedPosition</code>.</p>
		 */
		public int compare(Object o1, Object o2) {
			LinkedPosition p1= (LinkedPosition)o1;
			LinkedPosition p2= (LinkedPosition)o2;
			int i= p1.getSequenceNumber() - p2.getSequenceNumber();
			if (i != 0)
				return i;
			else
				return p1.getOffset() - p2.getOffset();
		}
		
	}
	
	/** The comparator to sort the list of positions. */
	private static final Comparator fComparator= new SequenceComparator();
	
	/** The iteration sequence. */
	private final ArrayList fList;
	/** The size of <code>fList</code>. */
	private int fSize;
	/** Index of the current element, to the first one initially. */
	private int fIndex;
	/** Cycling property. */
	private boolean fIsCycling= false;

	TabStopIterator(List positionSequence) {
		Assert.isNotNull(positionSequence);
		fList= new ArrayList(positionSequence);
		Collections.sort(fList, fComparator);
		fSize= fList.size();
		fIndex= -1;
		Assert.isTrue(fSize > 0);
	}

	boolean hasNext(LinkedPosition current) {
		return getNextIndex(current) != fSize;				
	}
	
	private int getNextIndex(LinkedPosition current) {
		if (current != null && fList.get(fIndex) != current)
			return findNext(current);
		else if (fIsCycling && fIndex == fSize - 1)
			return 0;
		else
			// default: increase
			return fIndex + 1;
	}
	
	/**
	 * Finds the closest position in the iteration set that follows after
	 * <code>current</code> and sets <code>fIndex</code> accordingly. If <code>current</code>
	 * is in the iteration set, the next in turn is chosen.
	 * 
	 * @param current the current position
	 * @return <code>true</code> if there is a next position, <code>false</code> otherwise
	 */
	private int findNext(LinkedPosition current) {
		Assert.isNotNull(current);
		// if the position is in the iteration set, jump to the next one
		int index= fList.indexOf(current);
		if (index != -1) {
			if (fIsCycling && index == fSize - 1)
				return 0;
			else
				return index + 1;
		} else {
			// find the position that follows closest to the current position
			LinkedPosition found= null;
			for (Iterator it= fList.iterator(); it.hasNext(); ) {
				LinkedPosition p= (LinkedPosition) it.next();
				if (p.offset > current.offset)
					if (found == null || found.offset > p.offset)
						found= p;
			}
			if (found != null) {
				return fList.indexOf(found);
			} else if (fIsCycling) {
				return 0;
			} else
				return fSize;
		}
	}

	boolean hasPrevious(LinkedPosition current) {
		return getPreviousIndex(current) != -1;				
	}
	
	private int getPreviousIndex(LinkedPosition current) {
		if (current != null && fList.get(fIndex) != current)
			return findPrevious(current);
		else if (fIsCycling && fIndex == 0)
			return fSize - 1;
		else
			return fIndex - 1;
	}

	/**
	 * Finds the closest position in the iteration set that precedes
	 * <code>current</code>. If <code>current</code>
	 * is in the iteration set, the previous in turn is chosen.
	 * 
	 * @param current the current position
	 * @return the index of the previous position
	 */
	private int findPrevious(LinkedPosition current) {
		Assert.isNotNull(current);
		// if the position is in the iteration set, jump to the next one
		int index= fList.indexOf(current);
		if (index != -1) {
			if (fIsCycling && index == 0)
				return fSize - 1;
			else
				return index - 1;
		} else {
			// find the position that follows closest to the current position
			LinkedPosition found= null;
			for (Iterator it= fList.iterator(); it.hasNext(); ) {
				LinkedPosition p= (LinkedPosition) it.next();
				if (p.offset < current.offset)
					if (found == null || found.offset < p.offset)
						found= p;
			}
			if (found != null) {
				return fList.indexOf(found);
			} else if (fIsCycling) {
				return fSize - 1;
			} else
				return -1;
		}
	}

	LinkedPosition next(LinkedPosition current) {
		if (!hasNext(current))
			throw new NoSuchElementException();
		else 
			return (LinkedPosition) fList.get(fIndex= getNextIndex(current));
	}

	LinkedPosition previous(LinkedPosition current) {
		if (!hasPrevious(current))
			throw new NoSuchElementException();
		else
			return (LinkedPosition) fList.get(fIndex= getPreviousIndex(current));
	}

	void setCycling(boolean mode) {
		fIsCycling= mode;
	}

	void addPosition(Position position) {
		fList.add(fSize++, position);
		Collections.sort(fList, fComparator);
	}
	
	void removePosition(Position position) {
		if (fList.remove(position))
			fSize--;
	}

	/**
	 * @return Returns the isCycling.
	 */
	boolean isCycling() {
		return fIsCycling;
	}
	
	LinkedPosition[] getPositions() {
		return (LinkedPosition[]) fList.toArray(new LinkedPosition[0]);
	}
}

Back to the top