View | Details | Raw Unified | Return to bug 140489 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/cdt/internal/ui/editor/CEditor.java (+402 lines)
Lines 15-20 Link Here
15
15
16
import java.lang.reflect.InvocationTargetException;
16
import java.lang.reflect.InvocationTargetException;
17
import java.lang.reflect.Method;
17
import java.lang.reflect.Method;
18
import java.text.CharacterIterator;
18
import java.util.Iterator;
19
import java.util.Iterator;
19
20
20
import org.eclipse.cdt.core.CCorePlugin;
21
import org.eclipse.cdt.core.CCorePlugin;
Lines 38-43 Link Here
38
import org.eclipse.cdt.internal.ui.text.CPairMatcher;
39
import org.eclipse.cdt.internal.ui.text.CPairMatcher;
39
import org.eclipse.cdt.internal.ui.text.CSourceViewerConfiguration;
40
import org.eclipse.cdt.internal.ui.text.CSourceViewerConfiguration;
40
import org.eclipse.cdt.internal.ui.text.CTextTools;
41
import org.eclipse.cdt.internal.ui.text.CTextTools;
42
import org.eclipse.cdt.internal.ui.text.CWordIterator;
43
import org.eclipse.cdt.internal.ui.text.DocumentCharacterIterator;
41
import org.eclipse.cdt.internal.ui.text.contentassist.ContentAssistPreference;
44
import org.eclipse.cdt.internal.ui.text.contentassist.ContentAssistPreference;
42
import org.eclipse.cdt.internal.ui.util.CUIHelp;
45
import org.eclipse.cdt.internal.ui.util.CUIHelp;
43
import org.eclipse.cdt.ui.CUIPlugin;
46
import org.eclipse.cdt.ui.CUIPlugin;
Lines 52-57 Link Here
52
import org.eclipse.core.runtime.Preferences;
55
import org.eclipse.core.runtime.Preferences;
53
import org.eclipse.core.runtime.content.IContentType;
56
import org.eclipse.core.runtime.content.IContentType;
54
import org.eclipse.jface.action.Action;
57
import org.eclipse.jface.action.Action;
58
import org.eclipse.jface.action.IAction;
55
import org.eclipse.jface.action.IMenuManager;
59
import org.eclipse.jface.action.IMenuManager;
56
import org.eclipse.jface.action.IStatusLineManager;
60
import org.eclipse.jface.action.IStatusLineManager;
57
import org.eclipse.jface.preference.IPreferenceStore;
61
import org.eclipse.jface.preference.IPreferenceStore;
Lines 86-91 Link Here
86
import org.eclipse.jface.viewers.SelectionChangedEvent;
90
import org.eclipse.jface.viewers.SelectionChangedEvent;
87
import org.eclipse.jface.viewers.StructuredSelection;
91
import org.eclipse.jface.viewers.StructuredSelection;
88
import org.eclipse.search.ui.actions.TextSearchGroup;
92
import org.eclipse.search.ui.actions.TextSearchGroup;
93
import org.eclipse.swt.SWT;
94
import org.eclipse.swt.custom.ST;
89
import org.eclipse.swt.custom.StyledText;
95
import org.eclipse.swt.custom.StyledText;
90
import org.eclipse.swt.graphics.Image;
96
import org.eclipse.swt.graphics.Image;
91
import org.eclipse.swt.graphics.Point;
97
import org.eclipse.swt.graphics.Point;
Lines 113-123 Link Here
113
import org.eclipse.ui.texteditor.IEditorStatusLine;
119
import org.eclipse.ui.texteditor.IEditorStatusLine;
114
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
120
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
115
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
121
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
122
import org.eclipse.ui.texteditor.IUpdate;
116
import org.eclipse.ui.texteditor.MarkerAnnotation;
123
import org.eclipse.ui.texteditor.MarkerAnnotation;
117
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
124
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
125
import org.eclipse.ui.texteditor.TextNavigationAction;
118
import org.eclipse.ui.texteditor.TextOperationAction;
126
import org.eclipse.ui.texteditor.TextOperationAction;
119
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
127
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
120
128
129
import com.ibm.icu.text.BreakIterator;
130
121
131
122
/**
132
/**
123
 * C specific text editor.
133
 * C specific text editor.
Lines 1175-1180 Link Here
1175
		return store.getBoolean(SPACES_FOR_TABS);
1185
		return store.getBoolean(SPACES_FOR_TABS);
1176
	}
1186
	}
1177
1187
1188
	/*
1189
	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#createNavigationActions()
1190
	 */
1191
	protected void createNavigationActions() {
1192
		super.createNavigationActions();
1193
1194
		final StyledText textWidget = getSourceViewer().getTextWidget();
1195
1196
		IAction action = new NavigatePreviousSubWordAction();
1197
		action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_PREVIOUS);
1198
		setAction(ITextEditorActionDefinitionIds.WORD_PREVIOUS, action);
1199
		textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_LEFT, SWT.NULL);
1200
1201
		action = new NavigateNextSubWordAction();
1202
		action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_NEXT);
1203
		setAction(ITextEditorActionDefinitionIds.WORD_NEXT, action);
1204
		textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_RIGHT, SWT.NULL);
1205
1206
		action = new SelectPreviousSubWordAction();
1207
		action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS);
1208
		setAction(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, action);
1209
		textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_LEFT, SWT.NULL);
1210
1211
		action = new SelectNextSubWordAction();
1212
		action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT);
1213
		setAction(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, action);
1214
		textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_RIGHT, SWT.NULL);
1215
	}
1216
1178
	interface ITextConverter {
1217
	interface ITextConverter {
1179
		void customizeDocumentCommand(IDocument document, DocumentCommand command);
1218
		void customizeDocumentCommand(IDocument document, DocumentCommand command);
1180
	}
1219
	}
Lines 1472-1475 Link Here
1472
		System.arraycopy(parentPrefPageIds, 0, prefPageIds, nIds, parentPrefPageIds.length);
1511
		System.arraycopy(parentPrefPageIds, 0, prefPageIds, nIds, parentPrefPageIds.length);
1473
		return prefPageIds;
1512
		return prefPageIds;
1474
	}
1513
	}
1514
1515
	/**
1516
	 * Text navigation action to navigate to the next sub-word.
1517
	 *
1518
	 * @since 3.0
1519
	 */
1520
	protected abstract class NextSubWordAction extends TextNavigationAction {
1521
1522
		protected CWordIterator fIterator = new CWordIterator();
1523
1524
		/**
1525
		 * Creates a new next sub-word action.
1526
		 *
1527
		 * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST.
1528
		 */
1529
		protected NextSubWordAction(int code) {
1530
			super(getSourceViewer().getTextWidget(), code);
1531
		}
1532
1533
		/*
1534
		 * @see org.eclipse.jface.action.IAction#run()
1535
		 */
1536
		public void run() {
1537
			// TODO Add EDITOR_SUB_WORD_NAVIGATION preference.
1538
			// Check whether sub word navigation is enabled.
1539
//			final IPreferenceStore store = getPreferenceStore();
1540
//			if (!store.getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) {
1541
//				super.run();
1542
//				return;
1543
//			}
1544
1545
			final ISourceViewer viewer = getSourceViewer();
1546
			final IDocument document = viewer.getDocument();
1547
			fIterator.setText((CharacterIterator) new DocumentCharacterIterator(document));
1548
			int position = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
1549
			if (position == -1)
1550
				return;
1551
1552
			int next = findNextPosition(position);
1553
			if (next != BreakIterator.DONE) {
1554
				setCaretPosition(next);
1555
				getTextWidget().showSelection();
1556
				fireSelectionChanged();
1557
			}
1558
1559
		}
1560
1561
		/**
1562
		 * Finds the next position after the given position.
1563
		 *
1564
		 * @param position the current position
1565
		 * @return the next position
1566
		 */
1567
		protected int findNextPosition(int position) {
1568
			ISourceViewer viewer = getSourceViewer();
1569
			int widget = -1;
1570
			while (position != BreakIterator.DONE && widget == -1) { // TODO: optimize
1571
				position = fIterator.following(position);
1572
				if (position != BreakIterator.DONE)
1573
					widget = modelOffset2WidgetOffset(viewer, position);
1574
			}
1575
			return position;
1576
		}
1577
1578
		/**
1579
		 * Sets the caret position to the sub-word boundary given with <code>position</code>.
1580
		 *
1581
		 * @param position Position where the action should move the caret
1582
		 */
1583
		protected abstract void setCaretPosition(int position);
1584
	}
1585
1586
	/**
1587
	 * Text navigation action to navigate to the next sub-word.
1588
	 *
1589
	 * @since 3.0
1590
	 */
1591
	protected class NavigateNextSubWordAction extends NextSubWordAction {
1592
1593
		/**
1594
		 * Creates a new navigate next sub-word action.
1595
		 */
1596
		public NavigateNextSubWordAction() {
1597
			super(ST.WORD_NEXT);
1598
		}
1599
1600
		/*
1601
		 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
1602
		 */
1603
		protected void setCaretPosition(final int position) {
1604
			getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
1605
		}
1606
	}
1607
1608
	/**
1609
	 * Text operation action to delete the next sub-word.
1610
	 *
1611
	 * @since 3.0
1612
	 */
1613
	protected class DeleteNextSubWordAction extends NextSubWordAction implements IUpdate {
1614
1615
		/**
1616
		 * Creates a new delete next sub-word action.
1617
		 */
1618
		public DeleteNextSubWordAction() {
1619
			super(ST.DELETE_WORD_NEXT);
1620
		}
1621
1622
		/*
1623
		 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
1624
		 */
1625
		protected void setCaretPosition(final int position) {
1626
			if (!validateEditorInputState())
1627
				return;
1628
1629
			final ISourceViewer viewer = getSourceViewer();
1630
			final int caret, length;
1631
			Point selection = viewer.getSelectedRange();
1632
			if (selection.y != 0) {
1633
				caret = selection.x;
1634
				length = selection.y;
1635
			} else {
1636
				caret = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
1637
				length = position - caret;
1638
			}
1639
1640
			try {
1641
				viewer.getDocument().replace(caret, length, ""); //$NON-NLS-1$
1642
			} catch (BadLocationException exception) {
1643
				// Should not happen
1644
			}
1645
		}
1646
1647
		/*
1648
		 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#findNextPosition(int)
1649
		 */
1650
		protected int findNextPosition(int position) {
1651
			return fIterator.following(position);
1652
		}
1653
1654
		/*
1655
		 * @see org.eclipse.ui.texteditor.IUpdate#update()
1656
		 */
1657
		public void update() {
1658
			setEnabled(isEditorInputModifiable());
1659
		}
1660
	}
1661
1662
	/**
1663
	 * Text operation action to select the next sub-word.
1664
	 *
1665
	 * @since 3.0
1666
	 */
1667
	protected class SelectNextSubWordAction extends NextSubWordAction {
1668
1669
		/**
1670
		 * Creates a new select next sub-word action.
1671
		 */
1672
		public SelectNextSubWordAction() {
1673
			super(ST.SELECT_WORD_NEXT);
1674
		}
1675
1676
		/*
1677
		 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
1678
		 */
1679
		protected void setCaretPosition(final int position) {
1680
			final ISourceViewer viewer = getSourceViewer();
1681
1682
			final StyledText text = viewer.getTextWidget();
1683
			if (text != null && !text.isDisposed()) {
1684
1685
				final Point selection = text.getSelection();
1686
				final int caret = text.getCaretOffset();
1687
				final int offset = modelOffset2WidgetOffset(viewer, position);
1688
1689
				if (caret == selection.x)
1690
					text.setSelectionRange(selection.y, offset - selection.y);
1691
				else
1692
					text.setSelectionRange(selection.x, offset - selection.x);
1693
			}
1694
		}
1695
	}
1696
1697
	/**
1698
	 * Text navigation action to navigate to the previous sub-word.
1699
	 *
1700
	 * @since 3.0
1701
	 */
1702
	protected abstract class PreviousSubWordAction extends TextNavigationAction {
1703
1704
		protected CWordIterator fIterator = new CWordIterator();
1705
1706
		/**
1707
		 * Creates a new previous sub-word action.
1708
		 *
1709
		 * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST.
1710
		 */
1711
		protected PreviousSubWordAction(final int code) {
1712
			super(getSourceViewer().getTextWidget(), code);
1713
		}
1714
1715
		/*
1716
		 * @see org.eclipse.jface.action.IAction#run()
1717
		 */
1718
		public void run() {
1719
			// TODO Add EDITOR_SUB_WORD_NAVIGATION preference.
1720
			// Check whether sub word navigation is enabled.
1721
//			final IPreferenceStore store = getPreferenceStore();
1722
//			if (!store.getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) {
1723
//				super.run();
1724
//				return;
1725
//			}
1726
1727
			final ISourceViewer viewer = getSourceViewer();
1728
			final IDocument document = viewer.getDocument();
1729
			fIterator.setText((CharacterIterator) new DocumentCharacterIterator(document));
1730
			int position = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
1731
			if (position == -1)
1732
				return;
1733
1734
			int previous = findPreviousPosition(position);
1735
			if (previous != BreakIterator.DONE) {
1736
				setCaretPosition(previous);
1737
				getTextWidget().showSelection();
1738
				fireSelectionChanged();
1739
			}
1740
1741
		}
1742
1743
		/**
1744
		 * Finds the previous position before the given position.
1745
		 *
1746
		 * @param position the current position
1747
		 * @return the previous position
1748
		 */
1749
		protected int findPreviousPosition(int position) {
1750
			ISourceViewer viewer = getSourceViewer();
1751
			int widget = -1;
1752
			while (position != BreakIterator.DONE && widget == -1) { // TODO: optimize
1753
				position = fIterator.preceding(position);
1754
				if (position != BreakIterator.DONE)
1755
					widget = modelOffset2WidgetOffset(viewer, position);
1756
			}
1757
			return position;
1758
		}
1759
1760
		/**
1761
		 * Sets the caret position to the sub-word boundary given with <code>position</code>.
1762
		 *
1763
		 * @param position Position where the action should move the caret
1764
		 */
1765
		protected abstract void setCaretPosition(int position);
1766
	}
1767
1768
	/**
1769
	 * Text navigation action to navigate to the previous sub-word.
1770
	 *
1771
	 * @since 3.0
1772
	 */
1773
	protected class NavigatePreviousSubWordAction extends PreviousSubWordAction {
1774
1775
		/**
1776
		 * Creates a new navigate previous sub-word action.
1777
		 */
1778
		public NavigatePreviousSubWordAction() {
1779
			super(ST.WORD_PREVIOUS);
1780
		}
1781
1782
		/*
1783
		 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
1784
		 */
1785
		protected void setCaretPosition(final int position) {
1786
			getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
1787
		}
1788
	}
1789
1790
	/**
1791
	 * Text operation action to delete the previous sub-word.
1792
	 *
1793
	 * @since 3.0
1794
	 */
1795
	protected class DeletePreviousSubWordAction extends PreviousSubWordAction implements IUpdate {
1796
1797
		/**
1798
		 * Creates a new delete previous sub-word action.
1799
		 */
1800
		public DeletePreviousSubWordAction() {
1801
			super(ST.DELETE_WORD_PREVIOUS);
1802
		}
1803
1804
		/*
1805
		 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
1806
		 */
1807
		protected void setCaretPosition(int position) {
1808
			if (!validateEditorInputState())
1809
				return;
1810
1811
			final int length;
1812
			final ISourceViewer viewer = getSourceViewer();
1813
			Point selection = viewer.getSelectedRange();
1814
			if (selection.y != 0) {
1815
				position = selection.x;
1816
				length = selection.y;
1817
			} else {
1818
				length = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset()) - position;
1819
			}
1820
1821
			try {
1822
				viewer.getDocument().replace(position, length, ""); //$NON-NLS-1$
1823
			} catch (BadLocationException exception) {
1824
				// Should not happen
1825
			}
1826
		}
1827
1828
		/*
1829
		 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#findPreviousPosition(int)
1830
		 */
1831
		protected int findPreviousPosition(int position) {
1832
			return fIterator.preceding(position);
1833
		}
1834
1835
		/*
1836
		 * @see org.eclipse.ui.texteditor.IUpdate#update()
1837
		 */
1838
		public void update() {
1839
			setEnabled(isEditorInputModifiable());
1840
		}
1841
	}
1842
1843
	/**
1844
	 * Text operation action to select the previous sub-word.
1845
	 *
1846
	 * @since 3.0
1847
	 */
1848
	protected class SelectPreviousSubWordAction extends PreviousSubWordAction {
1849
1850
		/**
1851
		 * Creates a new select previous sub-word action.
1852
		 */
1853
		public SelectPreviousSubWordAction() {
1854
			super(ST.SELECT_WORD_PREVIOUS);
1855
		}
1856
1857
		/*
1858
		 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
1859
		 */
1860
		protected void setCaretPosition(final int position) {
1861
			final ISourceViewer viewer = getSourceViewer();
1862
1863
			final StyledText text = viewer.getTextWidget();
1864
			if (text != null && !text.isDisposed()) {
1865
1866
				final Point selection = text.getSelection();
1867
				final int caret = text.getCaretOffset();
1868
				final int offset = modelOffset2WidgetOffset(viewer, position);
1869
1870
				if (caret == selection.x)
1871
					text.setSelectionRange(selection.y, offset - selection.y);
1872
				else
1873
					text.setSelectionRange(selection.x, offset - selection.x);
1874
			}
1875
		}
1876
	}
1475
}
1877
}
(-)src/org/eclipse/cdt/internal/ui/text/CBreakIterator.java (+425 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2006 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
 *     Sergey Prigogin, Google
11
 *******************************************************************************/
12
package org.eclipse.cdt.internal.ui.text;
13
14
import com.ibm.icu.text.BreakIterator;
15
import java.text.CharacterIterator;
16
17
import org.eclipse.jface.text.Assert;
18
19
20
/**
21
 * A C break iterator. It returns all breaks, including before and after
22
 * whitespace, and it returns all camel case breaks.
23
 * <p>
24
 * A line break may be any of "\n", "\r", "\r\n", "\n\r".
25
 * </p>
26
 *
27
 * @since 3.0
28
 */
29
public class CBreakIterator extends BreakIterator {
30
31
	/**
32
	 * A run of common characters.
33
	 */
34
	protected static abstract class Run {
35
		/** The length of this run. */
36
		protected int length;
37
38
		public Run() {
39
			init();
40
		}
41
42
		/**
43
		 * Returns <code>true</code> if this run consumes <code>ch</code>,
44
		 * <code>false</code> otherwise. If <code>true</code> is returned,
45
		 * the length of the receiver is adjusted accordingly.
46
		 *
47
		 * @param ch the character to test
48
		 * @return <code>true</code> if <code>ch</code> was consumed
49
		 */
50
		protected boolean consume(char ch) {
51
			if (isValid(ch)) {
52
				length++;
53
				return true;
54
			}
55
			return false;
56
		}
57
58
		/**
59
		 * Whether this run accepts that character; does not update state. Called
60
		 * from the default implementation of <code>consume</code>.
61
		 *
62
		 * @param ch the character to test
63
		 * @return <code>true</code> if <code>ch</code> is accepted
64
		 */
65
		protected abstract boolean isValid(char ch);
66
67
		/**
68
		 * Resets this run to the initial state.
69
		 */
70
		protected void init() {
71
			length= 0;
72
		}
73
	}
74
75
	static final class Whitespace extends Run {
76
		protected boolean isValid(char ch) {
77
			return Character.isWhitespace(ch) && ch != '\n' && ch != '\r';
78
		}
79
	}
80
81
	static final class LineDelimiter extends Run {
82
		/** State: INIT -> delimiter -> EXIT. */
83
		private char fState;
84
		private static final char INIT= '\0';
85
		private static final char EXIT= '\1';
86
87
		/*
88
		 * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#init()
89
		 */
90
		protected void init() {
91
			super.init();
92
			fState= INIT;
93
		}
94
95
		/*
96
		 * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#consume(char)
97
		 */
98
		protected boolean consume(char ch) {
99
			if (!isValid(ch) || fState == EXIT)
100
				return false;
101
102
			if (fState == INIT) {
103
				fState= ch;
104
				length++;
105
				return true;
106
			} else if (fState != ch) {
107
				fState= EXIT;
108
				length++;
109
				return true;
110
			} else {
111
				return false;
112
			}
113
		}
114
115
		protected boolean isValid(char ch) {
116
			return ch == '\n' || ch == '\r';
117
		}
118
	}
119
120
	static final class Identifier extends Run {
121
		/*
122
		 * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#isValid(char)
123
		 */
124
		protected boolean isValid(char ch) {
125
			return Character.isJavaIdentifierPart(ch);
126
		}
127
	}
128
129
	static final class CamelCaseIdentifier extends Run {
130
		/* states */
131
		private static final int S_INIT= 0;
132
		private static final int S_LOWER= 1;
133
		private static final int S_ONE_CAP= 2;
134
		private static final int S_ALL_CAPS= 3;
135
		private static final int S_UNDERSCORE= 4;
136
		private static final int S_EXIT= 5;
137
		private static final int S_EXIT_MINUS_ONE= 6;
138
139
		/* character types */
140
		private static final int K_INVALID= 0;
141
		private static final int K_LOWER= 1;
142
		private static final int K_UPPER= 2;
143
		private static final int K_UNDERSCORE= 3;
144
		private static final int K_OTHER= 4;
145
146
		private int fState;
147
148
		private final static int[][] MATRIX= new int[][] {
149
				// K_INVALID, K_LOWER,           K_UPPER,    K_UNDERSCORE, K_OTHER
150
				{  S_EXIT,    S_LOWER,           S_ONE_CAP,  S_UNDERSCORE, S_LOWER }, // S_INIT
151
				{  S_EXIT,    S_LOWER,           S_EXIT,     S_UNDERSCORE, S_LOWER }, // S_LOWER
152
				{  S_EXIT,    S_LOWER,           S_ALL_CAPS, S_UNDERSCORE, S_LOWER }, // S_ONE_CAP
153
				{  S_EXIT,    S_EXIT_MINUS_ONE,  S_ALL_CAPS, S_UNDERSCORE, S_LOWER }, // S_ALL_CAPS
154
				{  S_EXIT,    S_EXIT,            S_EXIT,     S_UNDERSCORE, S_EXIT  }, // S_UNDERSCORE
155
		};
156
157
		/*
158
		 * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#init()
159
		 */
160
		protected void init() {
161
			super.init();
162
			fState= S_INIT;
163
		}
164
165
		/*
166
		 * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#consumes(char)
167
		 */
168
		protected boolean consume(char ch) {
169
			int kind= getKind(ch);
170
			fState= MATRIX[fState][kind];
171
			switch (fState) {
172
				case S_LOWER:
173
				case S_ONE_CAP:
174
				case S_ALL_CAPS:
175
				case S_UNDERSCORE:
176
					length++;
177
					return true;
178
				case S_EXIT:
179
					return false;
180
				case S_EXIT_MINUS_ONE:
181
					length--;
182
					return false;
183
				default:
184
					Assert.isTrue(false);
185
					return false;
186
			}
187
		}
188
189
		/**
190
		 * Determines the kind of a character.
191
		 *
192
		 * @param ch the character to test
193
		 */
194
		private int getKind(char ch) {
195
			if (Character.isUpperCase(ch))
196
				return K_UPPER;
197
			if (Character.isLowerCase(ch))
198
				return K_LOWER;
199
			if (ch == '_')
200
				return K_UNDERSCORE;
201
			if (Character.isJavaIdentifierPart(ch)) // digits...
202
				return K_OTHER;
203
			return K_INVALID;
204
		}
205
206
		/*
207
		 * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#isValid(char)
208
		 */
209
		protected boolean isValid(char ch) {
210
			return Character.isJavaIdentifierPart(ch);
211
		}
212
	}
213
214
	static final class Other extends Run {
215
		/*
216
		 * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#isValid(char)
217
		 */
218
		protected boolean isValid(char ch) {
219
			return !Character.isWhitespace(ch) && !Character.isJavaIdentifierPart(ch);
220
		}
221
	}
222
223
	private static final Run WHITESPACE= new Whitespace();
224
	private static final Run DELIMITER= new LineDelimiter();
225
	private static final Run CAMELCASE= new CamelCaseIdentifier(); // new Identifier();
226
	private static final Run OTHER= new Other();
227
228
	/** The platform break iterator (word instance) used as a base. */
229
	protected final BreakIterator fIterator;
230
	/** The text we operate on. */
231
	protected CharSequence fText;
232
	/** our current position for the stateful methods. */
233
	private int fIndex;
234
235
236
	/**
237
	 * Creates a new break iterator.
238
	 */
239
	public CBreakIterator() {
240
		fIterator= BreakIterator.getWordInstance();
241
		fIndex= fIterator.current();
242
	}
243
244
	/*
245
	 * @see java.text.BreakIterator#current()
246
	 */
247
	public int current() {
248
		return fIndex;
249
	}
250
251
	/*
252
	 * @see java.text.BreakIterator#first()
253
	 */
254
	public int first() {
255
		fIndex= fIterator.first();
256
		return fIndex;
257
	}
258
259
	/*
260
	 * @see java.text.BreakIterator#following(int)
261
	 */
262
	public int following(int offset) {
263
		// work around too eager IAEs in standard implementation
264
		if (offset == getText().getEndIndex())
265
			return DONE;
266
267
		int next= fIterator.following(offset);
268
		if (next == DONE)
269
			return DONE;
270
271
		// TODO deal with complex script word boundaries
272
		// Math.min(offset + run.length, next) does not work
273
		// since BreakIterator.getWordInstance considers _ as boundaries
274
		// seems to work fine, however
275
		Run run= consumeRun(offset);
276
		return offset + run.length;
277
278
	}
279
280
	/**
281
	 * Consumes a run of characters at the limits of which we introduce a break.
282
	 * @param offset the offset to start at
283
	 * @return the run that was consumed
284
	 */
285
	private Run consumeRun(int offset) {
286
		// assert offset < length
287
288
		char ch= fText.charAt(offset);
289
		int length= fText.length();
290
		Run run= getRun(ch);
291
		while (run.consume(ch) && offset < length - 1) {
292
			offset++;
293
			ch= fText.charAt(offset);
294
		}
295
296
		return run;
297
	}
298
299
	/**
300
	 * Returns a run based on a character.
301
	 *
302
	 * @param ch the character to test
303
	 * @return the correct character given <code>ch</code>
304
	 */
305
	private Run getRun(char ch) {
306
		Run run;
307
		if (WHITESPACE.isValid(ch))
308
			run= WHITESPACE;
309
		else if (DELIMITER.isValid(ch))
310
			run= DELIMITER;
311
		else if (CAMELCASE.isValid(ch))
312
			run= CAMELCASE;
313
		else if (OTHER.isValid(ch))
314
			run= OTHER;
315
		else {
316
			Assert.isTrue(false);
317
			return null;
318
		}
319
320
		run.init();
321
		return run;
322
	}
323
324
	/*
325
	 * @see java.text.BreakIterator#getText()
326
	 */
327
	public CharacterIterator getText() {
328
		return fIterator.getText();
329
	}
330
331
	/*
332
	 * @see java.text.BreakIterator#isBoundary(int)
333
	 */
334
	public boolean isBoundary(int offset) {
335
        if (offset == getText().getBeginIndex())
336
            return true;
337
        else
338
            return following(offset - 1) == offset;
339
	}
340
341
	/*
342
	 * @see java.text.BreakIterator#last()
343
	 */
344
	public int last() {
345
		fIndex= fIterator.last();
346
		return fIndex;
347
	}
348
349
	/*
350
	 * @see java.text.BreakIterator#next()
351
	 */
352
	public int next() {
353
		fIndex= following(fIndex);
354
		return fIndex;
355
	}
356
357
	/*
358
	 * @see java.text.BreakIterator#next(int)
359
	 */
360
	public int next(int n) {
361
		return fIterator.next(n);
362
	}
363
364
	/*
365
	 * @see java.text.BreakIterator#preceding(int)
366
	 */
367
	public int preceding(int offset) {
368
		if (offset == getText().getBeginIndex())
369
			return DONE;
370
371
		if (isBoundary(offset - 1))
372
			return offset - 1;
373
374
		int previous= offset - 1;
375
		do {
376
			previous= fIterator.preceding(previous);
377
		} while (!isBoundary(previous));
378
379
		int last= DONE;
380
		while (previous < offset) {
381
			last= previous;
382
			previous= following(previous);
383
		}
384
385
		return last;
386
	}
387
388
	/*
389
	 * @see java.text.BreakIterator#previous()
390
	 */
391
	public int previous() {
392
		fIndex= preceding(fIndex);
393
		return fIndex;
394
	}
395
396
	/*
397
	 * @see java.text.BreakIterator#setText(java.lang.String)
398
	 */
399
	public void setText(String newText) {
400
		setText((CharSequence) newText);
401
	}
402
403
	/**
404
	 * Creates a break iterator given a char sequence.
405
	 * @param newText the new text
406
	 */
407
	public void setText(CharSequence newText) {
408
		fText= newText;
409
		fIterator.setText(new SequenceCharacterIterator(newText));
410
		first();
411
	}
412
413
	/*
414
	 * @see java.text.BreakIterator#setText(java.text.CharacterIterator)
415
	 */
416
	public void setText(CharacterIterator newText) {
417
		if (newText instanceof CharSequence) {
418
			fText= (CharSequence) newText;
419
			fIterator.setText(newText);
420
			first();
421
		} else {
422
			throw new UnsupportedOperationException("CharacterIterator not supported"); //$NON-NLS-1$
423
		}
424
	}
425
}
(-)src/org/eclipse/cdt/internal/ui/text/DocumentCharacterIterator.java (+222 lines)
Added Link Here
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.cdt.internal.ui.text;
12
13
import java.text.CharacterIterator;
14
15
import org.eclipse.jface.text.Assert;
16
import org.eclipse.jface.text.BadLocationException;
17
import org.eclipse.jface.text.IDocument;
18
19
20
/**
21
 * An <code>IDocument</code> based implementation of
22
 * <code>CharacterIterator</code> and <code>CharSequence</code>. Note that
23
 * the supplied document is not copied; if the document is modified during the
24
 * lifetime of a <code>DocumentCharacterIterator</code>, the methods
25
 * returning document content may not always return the same values. Also, if
26
 * accessing the document fails with a {@link BadLocationException}, any of
27
 * <code>CharacterIterator</code> methods as well as <code>charAt</code>may
28
 * return {@link CharacterIterator#DONE}.
29
 *
30
 * @since 3.0
31
 */
32
public class DocumentCharacterIterator implements CharacterIterator, CharSequence {
33
34
	private int fIndex= -1;
35
	private final IDocument fDocument;
36
	private final int fFirst;
37
	private final int fLast;
38
39
	private void invariant() {
40
		Assert.isTrue(fIndex >= fFirst);
41
		Assert.isTrue(fIndex <= fLast);
42
	}
43
44
	/**
45
	 * Creates an iterator for the entire document.
46
	 *
47
	 * @param document the document backing this iterator
48
	 */
49
	public DocumentCharacterIterator(IDocument document) {
50
		this(document, 0);
51
	}
52
53
	/**
54
	 * Creates an iterator, starting at offset <code>first</code>.
55
	 *
56
	 * @param document the document backing this iterator
57
	 * @param first the first character to consider
58
	 * @throws IllegalArgumentException if the indices are out of bounds
59
	 */
60
	public DocumentCharacterIterator(IDocument document, int first) throws IllegalArgumentException {
61
		this(document, first, document.getLength());
62
	}
63
64
	/**
65
	 * Creates an iterator for the document contents from <code>first</code>
66
	 * (inclusive) to <code>last</code> (exclusive).
67
	 *
68
	 * @param document the document backing this iterator
69
	 * @param first the first character to consider
70
	 * @param last the last character index to consider
71
	 * @throws IllegalArgumentException if the indices are out of bounds
72
	 */
73
	public DocumentCharacterIterator(IDocument document, int first, int last) throws IllegalArgumentException {
74
		if (document == null)
75
			throw new NullPointerException();
76
		if (first < 0 || first > last)
77
			throw new IllegalArgumentException();
78
		if (last > document.getLength())
79
			throw new IllegalArgumentException();
80
		fDocument= document;
81
		fFirst= first;
82
		fLast= last;
83
		fIndex= first;
84
		invariant();
85
	}
86
87
	/*
88
	 * @see java.text.CharacterIterator#first()
89
	 */
90
	public char first() {
91
		return setIndex(getBeginIndex());
92
	}
93
94
	/*
95
	 * @see java.text.CharacterIterator#last()
96
	 */
97
	public char last() {
98
		if (fFirst == fLast)
99
			return setIndex(getEndIndex());
100
		else
101
			return setIndex(getEndIndex() - 1);
102
	}
103
104
	/*
105
	 * @see java.text.CharacterIterator#current()
106
	 */
107
	public char current() {
108
		if (fIndex >= fFirst && fIndex < fLast)
109
			try {
110
				return fDocument.getChar(fIndex);
111
			} catch (BadLocationException e) {
112
				// ignore
113
			}
114
		return DONE;
115
	}
116
117
	/*
118
	 * @see java.text.CharacterIterator#next()
119
	 */
120
	public char next() {
121
		return setIndex(Math.min(fIndex + 1, getEndIndex()));
122
	}
123
124
	/*
125
	 * @see java.text.CharacterIterator#previous()
126
	 */
127
	public char previous() {
128
		if (fIndex > getBeginIndex()) {
129
			return setIndex(fIndex - 1);
130
		} else {
131
			return DONE;
132
		}
133
	}
134
135
	/*
136
	 * @see java.text.CharacterIterator#setIndex(int)
137
	 */
138
	public char setIndex(int position) {
139
		if (position >= getBeginIndex() && position <= getEndIndex())
140
			fIndex= position;
141
		else
142
			throw new IllegalArgumentException();
143
144
		invariant();
145
		return current();
146
	}
147
148
	/*
149
	 * @see java.text.CharacterIterator#getBeginIndex()
150
	 */
151
	public int getBeginIndex() {
152
		return fFirst;
153
	}
154
155
	/*
156
	 * @see java.text.CharacterIterator#getEndIndex()
157
	 */
158
	public int getEndIndex() {
159
		return fLast;
160
	}
161
162
	/*
163
	 * @see java.text.CharacterIterator#getIndex()
164
	 */
165
	public int getIndex() {
166
		return fIndex;
167
	}
168
169
	/*
170
	 * @see java.text.CharacterIterator#clone()
171
	 */
172
	public Object clone() {
173
		try {
174
			return super.clone();
175
		} catch (CloneNotSupportedException e) {
176
			throw new InternalError();
177
		}
178
	}
179
180
	/*
181
	 * @see java.lang.CharSequence#length()
182
	 */
183
	public int length() {
184
		return getEndIndex() - getBeginIndex();
185
	}
186
187
	/**
188
	 * {@inheritDoc}
189
	 * <p>
190
	 * Note that, if the document is modified concurrently, this method may
191
	 * return {@link CharacterIterator#DONE} if a {@link BadLocationException}
192
	 * was thrown when accessing the backing document.
193
	 * </p>
194
	 *
195
	 * @param index {@inheritDoc}
196
	 * @return {@inheritDoc}
197
	 */
198
	public char charAt(int index) {
199
		if (index >= 0 && index < length())
200
			try {
201
				return fDocument.getChar(getBeginIndex() + index);
202
			} catch (BadLocationException e) {
203
				// ignore and return DONE
204
				return DONE;
205
			}
206
		else
207
			throw new IndexOutOfBoundsException();
208
	}
209
210
	/*
211
	 * @see java.lang.CharSequence#subSequence(int, int)
212
	 */
213
	public CharSequence subSequence(int start, int end) {
214
		if (start < 0)
215
			throw new IndexOutOfBoundsException();
216
		if (end < start)
217
			throw new IndexOutOfBoundsException();
218
		if (end > length())
219
			throw new IndexOutOfBoundsException();
220
		return new DocumentCharacterIterator(fDocument, getBeginIndex() + start, getBeginIndex() + end);
221
	}
222
}
(-)src/org/eclipse/cdt/internal/ui/text/CWordIterator.java (+221 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2006 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.cdt.internal.ui.text;
12
13
import com.ibm.icu.text.BreakIterator;
14
import java.text.CharacterIterator;
15
16
import org.eclipse.jface.text.Assert;
17
18
19
/**
20
 * Breaks C text into word starts, also stops at line start and end. No
21
 * direction dependency.
22
 *
23
 * @since 3.0
24
 */
25
public class CWordIterator extends BreakIterator {
26
27
	/**
28
	 * The underlying java break iterator. It returns all breaks, including
29
	 * before and after every whitespace.
30
	 */
31
	private CBreakIterator fIterator;
32
	/** The current index for the stateful operations. */
33
	private int fIndex;
34
35
	/**
36
	 * Creates a new word iterator.
37
	 */
38
	public CWordIterator() {
39
		fIterator= new CBreakIterator();
40
		first();
41
	}
42
43
	/*
44
	 * @see java.text.BreakIterator#first()
45
	 */
46
	public int first() {
47
		fIndex= fIterator.first();
48
		return fIndex;
49
	}
50
51
	/*
52
	 * @see java.text.BreakIterator#last()
53
	 */
54
	public int last() {
55
		fIndex= fIterator.last();
56
		return fIndex;
57
	}
58
59
	/*
60
	 * @see java.text.BreakIterator#next(int)
61
	 */
62
	public int next(int n) {
63
		int next= 0;
64
		while (--n > 0 && next != DONE) {
65
			next= next();
66
		}
67
		return next;
68
	}
69
70
	/*
71
	 * @see java.text.BreakIterator#next()
72
	 */
73
	public int next() {
74
		fIndex= following(fIndex);
75
		return fIndex;
76
	}
77
78
	/*
79
	 * @see java.text.BreakIterator#previous()
80
	 */
81
	public int previous() {
82
		fIndex= preceding(fIndex);
83
		return fIndex;
84
	}
85
86
87
	/*
88
	 * @see java.text.BreakIterator#preceding(int)
89
	 */
90
	public int preceding(int offset) {
91
		int first= fIterator.preceding(offset);
92
		if (isWhitespace(first, offset)) {
93
			int second= fIterator.preceding(first);
94
			if (second != DONE && !isDelimiter(second, first))
95
				return second;
96
		}
97
		return first;
98
	}
99
100
	/*
101
	 * @see java.text.BreakIterator#following(int)
102
	 */
103
	public int following(int offset) {
104
		int first= fIterator.following(offset);
105
		if (eatFollowingWhitespace(offset, first)) {
106
			int second= fIterator.following(first);
107
			if (isWhitespace(first, second))
108
				return second;
109
		}
110
		return first;
111
	}
112
113
	private boolean eatFollowingWhitespace(int offset, int exclusiveEnd) {
114
		if (exclusiveEnd == DONE || offset == DONE)
115
			return false;
116
117
		if (isWhitespace(offset, exclusiveEnd))
118
			return false;
119
		if (isDelimiter(offset, exclusiveEnd))
120
			return false;
121
122
		return true;
123
	}
124
125
	/**
126
	 * Returns <code>true</code> if the given sequence into the underlying text
127
	 * represents a delimiter, <code>false</code> otherwise.
128
	 *
129
	 * @param offset the offset
130
	 * @param exclusiveEnd the end offset
131
	 * @return <code>true</code> if the given range is a delimiter
132
	 */
133
	private boolean isDelimiter(int offset, int exclusiveEnd) {
134
		if (exclusiveEnd == DONE || offset == DONE)
135
			return false;
136
137
		Assert.isTrue(offset >= 0);
138
		Assert.isTrue(exclusiveEnd <= getText().getEndIndex());
139
		Assert.isTrue(exclusiveEnd > offset);
140
141
		CharSequence seq= fIterator.fText;
142
143
		while (offset < exclusiveEnd) {
144
			char ch= seq.charAt(offset);
145
			if (ch != '\n' && ch != '\r')
146
				return false;
147
			offset++;
148
		}
149
150
		return true;
151
	}
152
153
	/**
154
	 * Returns <code>true</code> if the given sequence into the underlying text
155
	 * represents whitespace, but not a delimiter, <code>false</code> otherwise.
156
	 *
157
	 * @param offset the offset
158
	 * @param exclusiveEnd the end offset
159
	 * @return <code>true</code> if the given range is whitespace
160
	 */
161
	private boolean isWhitespace(int offset, int exclusiveEnd) {
162
		if (exclusiveEnd == DONE || offset == DONE)
163
			return false;
164
165
		Assert.isTrue(offset >= 0);
166
		Assert.isTrue(exclusiveEnd <= getText().getEndIndex());
167
		Assert.isTrue(exclusiveEnd > offset);
168
169
		CharSequence seq= fIterator.fText;
170
171
		while (offset < exclusiveEnd) {
172
			char ch= seq.charAt(offset);
173
			if (!Character.isWhitespace(ch))
174
				return false;
175
			if (ch == '\n' || ch == '\r')
176
				return false;
177
			offset++;
178
		}
179
180
		return true;
181
	}
182
183
	/*
184
	 * @see java.text.BreakIterator#current()
185
	 */
186
	public int current() {
187
		return fIndex;
188
	}
189
190
	/*
191
	 * @see java.text.BreakIterator#getText()
192
	 */
193
	public CharacterIterator getText() {
194
		return fIterator.getText();
195
	}
196
197
	/**
198
	 * Sets the text as <code>CharSequence</code>.
199
	 * @param newText the new text
200
	 */
201
	public void setText(CharSequence newText) {
202
		fIterator.setText(newText);
203
		first();
204
	}
205
206
	/*
207
	 * @see java.text.BreakIterator#setText(java.text.CharacterIterator)
208
	 */
209
	public void setText(CharacterIterator newText) {
210
		fIterator.setText(newText);
211
		first();
212
	}
213
214
	/*
215
	 * @see java.text.BreakIterator#setText(java.lang.String)
216
	 */
217
	public void setText(String newText) {
218
		setText((CharSequence) newText);
219
	}
220
221
}
(-)src/org/eclipse/cdt/internal/ui/text/SequenceCharacterIterator.java (+166 lines)
Added Link Here
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.cdt.internal.ui.text;
12
13
import java.text.CharacterIterator;
14
15
import org.eclipse.jface.text.Assert;
16
17
18
/**
19
 * A <code>CharSequence</code> based implementation of <code>CharacterIterator</code>.
20
 *
21
 * @since 3.0
22
 */
23
public class SequenceCharacterIterator implements CharacterIterator {
24
25
	private int fIndex= -1;
26
	private final CharSequence fSequence;
27
	private final int fFirst;
28
	private final int fLast;
29
30
	private void invariant() {
31
		Assert.isTrue(fIndex >= fFirst);
32
		Assert.isTrue(fIndex <= fLast);
33
	}
34
35
	/**
36
	 * Creates an iterator for the entire sequence.
37
	 *
38
	 * @param sequence the sequence backing this iterator
39
	 */
40
	public SequenceCharacterIterator(CharSequence sequence) {
41
		this(sequence, 0);
42
	}
43
44
	/**
45
	 * Creates an iterator.
46
	 *
47
	 * @param sequence the sequence backing this iterator
48
	 * @param first the first character to consider
49
	 * @throws IllegalArgumentException if the indices are out of bounds
50
	 */
51
	public SequenceCharacterIterator(CharSequence sequence, int first) throws IllegalArgumentException {
52
		this(sequence, first, sequence.length());
53
	}
54
55
	/**
56
	 * Creates an iterator.
57
	 *
58
	 * @param sequence the sequence backing this iterator
59
	 * @param first the first character to consider
60
	 * @param last the last character index to consider
61
	 * @throws IllegalArgumentException if the indices are out of bounds
62
	 */
63
	public SequenceCharacterIterator(CharSequence sequence, int first, int last) throws IllegalArgumentException {
64
		if (sequence == null)
65
			throw new NullPointerException();
66
		if (first < 0 || first > last)
67
			throw new IllegalArgumentException();
68
		if (last > sequence.length())
69
			throw new IllegalArgumentException();
70
		fSequence= sequence;
71
		fFirst= first;
72
		fLast= last;
73
		fIndex= first;
74
		invariant();
75
	}
76
77
	/*
78
	 * @see java.text.CharacterIterator#first()
79
	 */
80
	public char first() {
81
		return setIndex(getBeginIndex());
82
	}
83
84
	/*
85
	 * @see java.text.CharacterIterator#last()
86
	 */
87
	public char last() {
88
		if (fFirst == fLast)
89
			return setIndex(getEndIndex());
90
		else
91
			return setIndex(getEndIndex() - 1);
92
	}
93
94
	/*
95
	 * @see java.text.CharacterIterator#current()
96
	 */
97
	public char current() {
98
		if (fIndex >= fFirst && fIndex < fLast)
99
			return fSequence.charAt(fIndex);
100
		else
101
			return DONE;
102
	}
103
104
	/*
105
	 * @see java.text.CharacterIterator#next()
106
	 */
107
	public char next() {
108
		return setIndex(Math.min(fIndex + 1, getEndIndex()));
109
	}
110
111
	/*
112
	 * @see java.text.CharacterIterator#previous()
113
	 */
114
	public char previous() {
115
		if (fIndex > getBeginIndex()) {
116
			return setIndex(fIndex - 1);
117
		} else {
118
			return DONE;
119
		}
120
	}
121
122
	/*
123
	 * @see java.text.CharacterIterator#setIndex(int)
124
	 */
125
	public char setIndex(int position) {
126
		if (position >= getBeginIndex() && position <= getEndIndex())
127
			fIndex= position;
128
		else
129
			throw new IllegalArgumentException();
130
131
		invariant();
132
		return current();
133
	}
134
135
	/*
136
	 * @see java.text.CharacterIterator#getBeginIndex()
137
	 */
138
	public int getBeginIndex() {
139
		return fFirst;
140
	}
141
142
	/*
143
	 * @see java.text.CharacterIterator#getEndIndex()
144
	 */
145
	public int getEndIndex() {
146
		return fLast;
147
	}
148
149
	/*
150
	 * @see java.text.CharacterIterator#getIndex()
151
	 */
152
	public int getIndex() {
153
		return fIndex;
154
	}
155
156
	/*
157
	 * @see java.text.CharacterIterator#clone()
158
	 */
159
	public Object clone() {
160
		try {
161
			return super.clone();
162
		} catch (CloneNotSupportedException e) {
163
			throw new InternalError();
164
		}
165
	}
166
}

Return to bug 140489