001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.ui.javaeditor.selectionactions;
011:
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.List;
015:
016: import org.eclipse.core.runtime.Assert;
017:
018: import org.eclipse.jface.action.Action;
019: import org.eclipse.jface.text.ITextSelection;
020:
021: import org.eclipse.ui.IEditorInput;
022: import org.eclipse.ui.PlatformUI;
023: import org.eclipse.ui.texteditor.IUpdate;
024:
025: import org.eclipse.jdt.core.IInitializer;
026: import org.eclipse.jdt.core.IJavaElement;
027: import org.eclipse.jdt.core.IMember;
028: import org.eclipse.jdt.core.ISourceRange;
029: import org.eclipse.jdt.core.ISourceReference;
030: import org.eclipse.jdt.core.IType;
031: import org.eclipse.jdt.core.JavaModelException;
032: import org.eclipse.jdt.core.ToolFactory;
033: import org.eclipse.jdt.core.compiler.IScanner;
034: import org.eclipse.jdt.core.compiler.ITerminalSymbols;
035: import org.eclipse.jdt.core.compiler.InvalidInputException;
036:
037: import org.eclipse.jdt.internal.corext.SourceRange;
038:
039: import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
040: import org.eclipse.jdt.internal.ui.JavaPlugin;
041: import org.eclipse.jdt.internal.ui.javaeditor.IClassFileEditorInput;
042: import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
043:
044: public class GoToNextPreviousMemberAction extends Action implements
045: IUpdate {
046:
047: public static final String NEXT_MEMBER = "GoToNextMember"; //$NON-NLS-1$
048: public static final String PREVIOUS_MEMBER = "GoToPreviousMember"; //$NON-NLS-1$
049: private JavaEditor fEditor;
050: private boolean fIsGotoNext;
051:
052: public static GoToNextPreviousMemberAction newGoToNextMemberAction(
053: JavaEditor editor) {
054: String text = SelectionActionMessages.GotoNextMember_label;
055: return new GoToNextPreviousMemberAction(editor, text, true);
056: }
057:
058: public static GoToNextPreviousMemberAction newGoToPreviousMemberAction(
059: JavaEditor editor) {
060: String text = SelectionActionMessages.GotoPreviousMember_label;
061: return new GoToNextPreviousMemberAction(editor, text, false);
062: }
063:
064: private GoToNextPreviousMemberAction(JavaEditor editor,
065: String text, boolean isGotoNext) {
066: super (text);
067: Assert.isNotNull(editor);
068: fEditor = editor;
069: fIsGotoNext = isGotoNext;
070: update();
071: if (isGotoNext)
072: PlatformUI.getWorkbench().getHelpSystem().setHelp(this ,
073: IJavaHelpContextIds.GOTO_NEXT_MEMBER_ACTION);
074: else
075: PlatformUI.getWorkbench().getHelpSystem().setHelp(this ,
076: IJavaHelpContextIds.GOTO_PREVIOUS_MEMBER_ACTION);
077: }
078:
079: /*
080: * This constructor is for testing purpose only.
081: */
082: public GoToNextPreviousMemberAction(boolean isSelectNext) {
083: super (""); //$NON-NLS-1$
084: fIsGotoNext = isSelectNext;
085: }
086:
087: public void update() {
088: boolean enabled = false;
089: ISourceReference ref = getSourceReference();
090: if (ref != null) {
091: ISourceRange range;
092: try {
093: range = ref.getSourceRange();
094: enabled = range != null && range.getLength() > 0;
095: } catch (JavaModelException e) {
096: // enabled= false;
097: }
098: }
099: setEnabled(enabled);
100: }
101:
102: /* (non-JavaDoc)
103: * Method declared in IAction.
104: */
105: public final void run() {
106: ITextSelection selection = getTextSelection();
107: ISourceRange newRange = getNewSelectionRange(
108: createSourceRange(selection), null);
109: // Check if new selection differs from current selection
110: if (selection.getOffset() == newRange.getOffset()
111: && selection.getLength() == newRange.getLength())
112: return;
113: fEditor.selectAndReveal(newRange.getOffset(), newRange
114: .getLength());
115: }
116:
117: private IType[] getTypes() throws JavaModelException {
118: IEditorInput input = fEditor.getEditorInput();
119: if (input instanceof IClassFileEditorInput) {
120: return new IType[] { ((IClassFileEditorInput) input)
121: .getClassFile().getType() };
122: } else {
123: return JavaPlugin.getDefault().getWorkingCopyManager()
124: .getWorkingCopy(input).getAllTypes();
125: }
126: }
127:
128: private ISourceReference getSourceReference() {
129: IEditorInput input = fEditor.getEditorInput();
130: if (input instanceof IClassFileEditorInput) {
131: return ((IClassFileEditorInput) input).getClassFile();
132: } else {
133: return JavaPlugin.getDefault().getWorkingCopyManager()
134: .getWorkingCopy(input);
135: }
136: }
137:
138: private ITextSelection getTextSelection() {
139: return (ITextSelection) fEditor.getSelectionProvider()
140: .getSelection();
141: }
142:
143: public ISourceRange getNewSelectionRange(
144: ISourceRange oldSourceRange, IType[] types) {
145: try {
146: if (types == null)
147: types = getTypes();
148: Integer[] offsetArray = createOffsetArray(types);
149: if (offsetArray.length == 0)
150: return oldSourceRange;
151: Arrays.sort(offsetArray);
152: Integer oldOffset = new Integer(oldSourceRange.getOffset());
153: int index = Arrays.binarySearch(offsetArray, oldOffset);
154:
155: if (fIsGotoNext)
156: return createNewSourceRange(getNextOffset(index,
157: offsetArray, oldOffset));
158: else
159: return createNewSourceRange(getPreviousOffset(index,
160: offsetArray, oldOffset));
161:
162: } catch (JavaModelException e) {
163: JavaPlugin.log(e); //dialog would be too heavy here
164: return oldSourceRange;
165: }
166: }
167:
168: private static Integer getPreviousOffset(int index,
169: Integer[] offsetArray, Integer oldOffset) {
170: if (index == -1)
171: return oldOffset;
172: if (index == 0)
173: return offsetArray[0];
174: if (index > 0)
175: return offsetArray[index - 1];
176: Assert.isTrue(index < -1);
177: int absIndex = Math.abs(index);
178: return offsetArray[absIndex - 2];
179: }
180:
181: private static Integer getNextOffset(int index,
182: Integer[] offsetArray, Integer oldOffset) {
183: if (index == -1)
184: return offsetArray[0];
185:
186: if (index == 0) {
187: if (offsetArray.length != 1)
188: return offsetArray[1];
189: else
190: return offsetArray[0];
191: }
192: if (index > 0) {
193: if (index == offsetArray.length - 1)
194: return oldOffset;
195: return offsetArray[index + 1];
196: }
197: Assert.isTrue(index < -1);
198: int absIndex = Math.abs(index);
199: if (absIndex > offsetArray.length)
200: return oldOffset;
201: else
202: return offsetArray[absIndex - 1];
203: }
204:
205: private static ISourceRange createNewSourceRange(Integer offset) {
206: return new SourceRange(offset.intValue(), 0);
207: }
208:
209: private static Integer[] createOffsetArray(IType[] types)
210: throws JavaModelException {
211: List result = new ArrayList();
212: for (int i = 0; i < types.length; i++) {
213: IType iType = types[i];
214: addOffset(result, iType.getNameRange().getOffset());
215: addOffset(result, iType.getSourceRange().getOffset()
216: + iType.getSourceRange().getLength());
217: addMemberOffsetList(result, iType.getMethods());
218: addMemberOffsetList(result, iType.getFields());
219: addMemberOffsetList(result, iType.getInitializers());
220: }
221: return (Integer[]) result.toArray(new Integer[result.size()]);
222: }
223:
224: private static void addMemberOffsetList(List result,
225: IMember[] members) throws JavaModelException {
226: for (int i = 0; i < members.length; i++) {
227: addOffset(result, getOffset(members[i]));
228: }
229: }
230:
231: private static int getOffset(IMember iMember)
232: throws JavaModelException {
233: //special case
234: if (iMember.getElementType() == IJavaElement.INITIALIZER)
235: return firstOpeningBraceOffset((IInitializer) iMember);
236:
237: if (iMember.getNameRange() != null
238: && iMember.getNameRange().getOffset() >= 0)
239: return iMember.getNameRange().getOffset();
240: return iMember.getSourceRange().getOffset();
241: }
242:
243: private static int firstOpeningBraceOffset(IInitializer iInitializer)
244: throws JavaModelException {
245: try {
246: IScanner scanner = ToolFactory.createScanner(false, false,
247: false, false);
248: scanner.setSource(iInitializer.getSource().toCharArray());
249: int token = scanner.getNextToken();
250: while (token != ITerminalSymbols.TokenNameEOF
251: && token != ITerminalSymbols.TokenNameLBRACE)
252: token = scanner.getNextToken();
253: if (token == ITerminalSymbols.TokenNameLBRACE)
254: return iInitializer.getSourceRange().getOffset()
255: + scanner.getCurrentTokenStartPosition()
256: + scanner.getRawTokenSource().length;
257: return iInitializer.getSourceRange().getOffset();
258: } catch (InvalidInputException e) {
259: return iInitializer.getSourceRange().getOffset();
260: }
261: }
262:
263: //-- private helper methods
264:
265: private static ISourceRange createSourceRange(ITextSelection ts) {
266: return new SourceRange(ts.getOffset(), ts.getLength());
267: }
268:
269: private static void addOffset(List result, int offset) {
270: if (offset >= 0)
271: result.add(new Integer(offset));
272: }
273: }
|