KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > texteditor > quickdiff > compare > rangedifferencer > DocLineComparator


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer;
12
13 import org.eclipse.jface.text.*;
14
15 /**
16  * Implements the <code>IRangeComparator</code> interface for lines in a document.
17  * A <code>DocLineComparator</code> is used as the input for the <code>RangeDifferencer</code>
18  * engine to perform a line oriented compare on documents.
19  * <p>
20  * A <code>DocLineComparator</code> doesn't know anything about line separators because
21  * its notion of lines is solely defined in the underlying <code>IDocument</code>.
22  */

23 public final class DocLineComparator implements IRangeComparator {
24
25     /**
26      * Document based character sequence.
27      */

28     public static class DocumentCharSequence implements CharSequence JavaDoc {
29
30         /** Document */
31         private IDocument fDocument;
32
33         /** Offset */
34         private int fOffset;
35
36         /** Length */
37         private int fLength;
38
39         /**
40          * Leave uninitialized. The document, offset and length have to be set
41          * before use.
42          */

43         public DocumentCharSequence() {
44             // do nothing
45
}
46
47         /**
48          * Initialize with the sequence of characters in the given document
49          * starting at the given offset with the given length.
50          *
51          * @param document The document
52          * @param offset The offset
53          * @param length The length
54          */

55         public DocumentCharSequence(IDocument document, int offset, int length) {
56             fDocument= document;
57             fOffset= offset;
58             fLength= length;
59         }
60
61         /*
62          * @see java.lang.CharSequence#length()
63          */

64         public int length() {
65             return fLength;
66         }
67
68         /*
69          * @see java.lang.CharSequence#charAt(int)
70          */

71         public char charAt(int index) {
72             try {
73                 return fDocument.getChar(fOffset + index);
74             } catch (BadLocationException e) {
75                 throw new IndexOutOfBoundsException JavaDoc();
76             }
77         }
78
79         /*
80          * @see java.lang.CharSequence#subSequence(int, int)
81          */

82         public CharSequence JavaDoc subSequence(int start, int end) {
83             return new DocumentCharSequence(fDocument, start, end - start);
84         }
85
86
87         /*
88          * @see java.lang.Object#hashCode()
89          */

90         public int hashCode() {
91             int hash= 0;
92             for (int i= 0, n= fLength; i < n; i++)
93                 hash= 29*hash + charAt(i);
94             return hash;
95         }
96
97
98         /*
99          * @see java.lang.Object#equals(java.lang.Object)
100          */

101         public boolean equals(Object JavaDoc obj) {
102             if (obj == this)
103                 return true;
104             if (!(obj instanceof DocumentCharSequence))
105                 return false;
106             DocumentCharSequence buffer= (DocumentCharSequence) obj;
107             int length= buffer.length();
108             if (length != fLength)
109                 return false;
110             for (int i= 0; i < length; i++)
111                 if (buffer.charAt(i) != charAt(i))
112                     return false;
113             return true;
114         }
115
116         /**
117          * Sets the document to the given.
118          *
119          * @param document the document to be set
120          */

121         public void setDocument(IDocument document) {
122             fDocument= document;
123         }
124
125         /**
126          * Sets the offset to the given value.
127          *
128          * @param offset the offset to be set
129          */

130         public void setOffset(int offset) {
131             fOffset= offset;
132         }
133
134         /**
135          * Sets the length to the given value.
136          *
137          * @param length the length to be set
138          */

139         public void setLength(int length) {
140             fLength= length;
141         }
142     }
143
144     private final IDocument fDocument;
145     private final int fLineOffset;
146     private final int fLineCount;
147     private final int fLength;
148     private final boolean fIgnoreWhiteSpace;
149     private final int fMaxOffset;
150
151
152     private boolean fSkip= false;
153     private int fLastOffset;
154     private int fLastLength;
155
156     /** Cached document character sequence */
157     private DocumentCharSequence fThisBuffer= new DocumentCharSequence();
158     /** Cached document character sequence */
159     private DocumentCharSequence fOtherBuffer= new DocumentCharSequence();
160
161     /**
162      * Creates a <code>DocLineComparator</code> for the given document range.
163      * ignoreWhiteSpace controls whether comparing lines (in method
164      * <code>rangesEqual<code>) should ignore whitespace.
165      *
166      * @param document the document from which the lines are taken
167      * @param region if non-<code>null</code> only lines within this range are taken
168      * @param ignoreWhiteSpace if <code>true</code> white space is ignored when comparing lines
169      */

170     public DocLineComparator(IDocument document, IRegion region, boolean ignoreWhiteSpace) {
171
172         fDocument= document;
173         fIgnoreWhiteSpace= ignoreWhiteSpace;
174
175         if (region != null) {
176             fLength= region.getLength();
177             int start= region.getOffset();
178             int lineOffset= 0;
179             try {
180                 lineOffset= fDocument.getLineOfOffset(start);
181             } catch (BadLocationException ex) {
182             }
183             fLineOffset= lineOffset;
184
185             fMaxOffset= start + fLength;
186
187             if (fLength == 0)
188                 fLineCount= 0;
189             else {
190                 int endLine= fDocument.getNumberOfLines();
191                 try {
192                     endLine= fDocument.getLineOfOffset(start + fLength);
193                 } catch (BadLocationException ex) {
194                 }
195                 fLineCount= endLine - fLineOffset + 1;
196             }
197
198         } else {
199             fLineOffset= 0;
200             fLength= document.getLength();
201             fLineCount= fDocument.getNumberOfLines();
202             fMaxOffset= fDocument.getLength();
203         }
204     }
205
206     /**
207      * Returns the number of lines in the document.
208      *
209      * @return number of lines
210      */

211     public int getRangeCount() {
212         return fLineCount;
213     }
214
215     /**
216      * Computes the length of line <code>line</code>.
217      *
218      * @param line the line requested
219      * @return the line length or <code>0</code> if <code>line</code> is not a valid line in the document
220      */

221     private int getLineLength(int line) {
222         if (line >= fLineCount)
223             return 0;
224         try {
225             int docLine= fLineOffset + line;
226             String JavaDoc delim= fDocument.getLineDelimiter(docLine);
227             int length= fDocument.getLineLength(docLine) - (delim == null ? 0 : delim.length());
228             if (line == fLineCount - 1) {
229                 fLastOffset= fDocument.getLineOffset(docLine);
230                 fLastLength= Math.min(length, fMaxOffset - fLastOffset);
231             } else {
232                 fLastOffset= -1;
233                 fLastLength= length;
234             }
235             return fLastLength;
236         } catch (BadLocationException e) {
237             fLastOffset= 0;
238             fLastLength= 0;
239             fSkip= true;
240             return 0;
241         }
242     }
243
244     /**
245      * Returns <code>true</code> if a line given by the first index
246      * matches a line specified by the other <code>IRangeComparator</code> and index.
247      *
248      * @param thisIndex the number of the line within this range comparator
249      * @param other the range comparator to compare this with
250      * @param otherIndex the number of the line within the other comparator
251      * @return <code>true</code> if the lines are equal
252      */

253     public boolean rangesEqual(int thisIndex, IRangeComparator other, int otherIndex) {
254
255         if (other != null && other.getClass() == getClass()) {
256             DocLineComparator dlc= (DocLineComparator) other;
257
258             if (fIgnoreWhiteSpace) {
259                 extract(thisIndex, fThisBuffer);
260                 dlc.extract(otherIndex, fOtherBuffer);
261                 return compare(fThisBuffer, fOtherBuffer);
262             }
263
264             int tlen= getLineLength(thisIndex);
265             int olen= dlc.getLineLength(otherIndex);
266             if (tlen == olen) {
267                 extract(thisIndex, fThisBuffer);
268                 dlc.extract(otherIndex, fOtherBuffer);
269                 return fThisBuffer.equals(fOtherBuffer);
270             }
271
272         }
273         return false;
274     }
275
276     /**
277      * Aborts the comparison if the number of tokens is too large.
278      *
279      * @param length the current edit distance
280      * @param max the maximal edit distance
281      * @param other the comparator with which to compare
282      * @return <code>true</code> to abort a token comparison
283      */

284     public boolean skipRangeComparison(int length, int max, IRangeComparator other) {
285         return fSkip;
286     }
287
288     //---- private methods
289

290     /**
291      * Extract a single line from the underlying document without the line separator
292      * into the given document based character sequence.
293      *
294      * @param line the number of the line to extract
295      * @param buffer the document based character sequence
296      */

297     private void extract(int line, DocumentCharSequence buffer) {
298         if (line < fLineCount) {
299             try {
300                 int docLine= fLineOffset + line;
301                 if (fLastOffset == -1)
302                     fLastOffset= fDocument.getLineOffset(docLine);
303
304                 buffer.setDocument(fDocument);
305                 buffer.setOffset(fLastOffset);
306                 buffer.setLength(fLastLength);
307                 return;
308             } catch(BadLocationException e) {
309                 fSkip= true;
310             }
311         }
312         buffer.setDocument(fDocument);
313         buffer.setOffset(0);
314         buffer.setLength(0);
315     }
316
317     private boolean compare(CharSequence JavaDoc s1, CharSequence JavaDoc s2) {
318         int l1= s1.length();
319         int l2= s2.length();
320         int c1= 0, c2= 0;
321         int i1= 0, i2= 0;
322
323         while (c1 != -1) {
324
325             c1= -1;
326             while (i1 < l1) {
327                 char c= s1.charAt(i1++);
328                 if (! Character.isWhitespace(c)) {
329                     c1= c;
330                     break;
331                 }
332             }
333
334             c2= -1;
335             while (i2 < l2) {
336                 char c= s2.charAt(i2++);
337                 if (! Character.isWhitespace(c)) {
338                     c2= c;
339                     break;
340                 }
341             }
342
343             if (c1 != c2)
344                 return false;
345         }
346         return true;
347     }
348
349 }
350
351
Popular Tags