001: /*******************************************************************************
002: * Copyright (c) 2005, 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.ui.text.java;
011:
012: import org.eclipse.core.runtime.Assert;
013:
014: import org.eclipse.jface.text.BadLocationException;
015: import org.eclipse.jface.text.IDocument;
016: import org.eclipse.jface.text.ITextViewer;
017:
018: /**
019: * Describes the context of an invocation of content assist in a text viewer. The context knows the
020: * document, the invocation offset and can lazily compute the identifier prefix preceding the
021: * invocation offset. It may know the viewer.
022: * <p>
023: * Subclasses may add information to their environment. For example, source code editors may provide
024: * specific context information such as an AST.
025: * </p>
026: * <p>
027: * Clients may instantiate and subclass.
028: * </p>
029: *
030: * @since 3.2
031: */
032: public class ContentAssistInvocationContext {
033:
034: /* state */
035: private final ITextViewer fViewer;
036: private final IDocument fDocument;
037: private final int fOffset;
038:
039: /* cached additional info */
040: private CharSequence fPrefix;
041:
042: /**
043: * Equivalent to
044: * {@linkplain #ContentAssistInvocationContext(ITextViewer, int) ContentAssistInvocationContext(viewer, viewer.getSelectedRange().x)}.
045: *
046: * @param viewer the text viewer that content assist is invoked in
047: */
048: public ContentAssistInvocationContext(ITextViewer viewer) {
049: this (viewer, viewer.getSelectedRange().x);
050: }
051:
052: /**
053: * Creates a new context for the given viewer and offset.
054: *
055: * @param viewer the text viewer that content assist is invoked in
056: * @param offset the offset into the viewer's document where content assist is invoked at
057: */
058: public ContentAssistInvocationContext(ITextViewer viewer, int offset) {
059: Assert.isNotNull(viewer);
060: fViewer = viewer;
061: fDocument = null;
062: fOffset = offset;
063: }
064:
065: /**
066: * Creates a new context with no viewer or invocation offset set.
067: */
068: protected ContentAssistInvocationContext() {
069: fDocument = null;
070: fViewer = null;
071: fOffset = -1;
072: }
073:
074: /**
075: * Creates a new context for the given document and offset.
076: *
077: * @param document the document that content assist is invoked in
078: * @param offset the offset into the document where content assist is invoked at
079: */
080: public ContentAssistInvocationContext(IDocument document, int offset) {
081: Assert.isNotNull(document);
082: Assert.isTrue(offset >= 0);
083: fViewer = null;
084: fDocument = document;
085: fOffset = offset;
086: }
087:
088: /**
089: * Returns the invocation offset.
090: *
091: * @return the invocation offset
092: */
093: public final int getInvocationOffset() {
094: return fOffset;
095: }
096:
097: /**
098: * Returns the viewer, <code>null</code> if not available.
099: *
100: * @return the viewer, possibly <code>null</code>
101: */
102: public final ITextViewer getViewer() {
103: return fViewer;
104: }
105:
106: /**
107: * Returns the document that content assist is invoked on, or <code>null</code> if not known.
108: *
109: * @return the document or <code>null</code>
110: */
111: public IDocument getDocument() {
112: if (fDocument == null) {
113: if (fViewer == null)
114: return null;
115: return fViewer.getDocument();
116: }
117: return fDocument;
118: }
119:
120: /**
121: * Computes the identifier (as specified by {@link Character#isJavaIdentifierPart(char)}) that
122: * immediately precedes the invocation offset.
123: *
124: * @return the prefix preceding the content assist invocation offset, <code>null</code> if
125: * there is no document
126: * @throws BadLocationException if accessing the document fails
127: */
128: public CharSequence computeIdentifierPrefix()
129: throws BadLocationException {
130: if (fPrefix == null) {
131: IDocument document = getDocument();
132: if (document == null)
133: return null;
134: int end = getInvocationOffset();
135: int start = end;
136: while (--start >= 0) {
137: if (!Character.isJavaIdentifierPart(document
138: .getChar(start)))
139: break;
140: }
141: start++;
142: fPrefix = document.get(start, end - start);
143: }
144:
145: return fPrefix;
146: }
147:
148: /**
149: * Invocation contexts are equal if they describe the same context and are of the same type.
150: * This implementation checks for <code>null</code> values and class equality. Subclasses
151: * should extend this method by adding checks for their context relevant fields (but not
152: * necessarily cached values).
153: * <p>
154: * Example:
155: *
156: * <pre>
157: * class MyContext extends ContentAssistInvocationContext {
158: * private final Object fState;
159: * private Object fCachedInfo;
160: *
161: * ...
162: *
163: * public boolean equals(Object obj) {
164: * if (!super.equals(obj))
165: * return false;
166: * MyContext other= (MyContext) obj;
167: * return fState.equals(other.fState);
168: * }
169: * }
170: * </pre>
171: *
172: * </p>
173: * <p>
174: * Subclasses should also extend {@link Object#hashCode()}.
175: * </p>
176: *
177: * @param obj {@inheritDoc}
178: * @return {@inheritDoc}
179: */
180: public boolean equals(Object obj) {
181: if (obj == null)
182: return false;
183: if (!getClass().equals(obj.getClass()))
184: return false;
185: ContentAssistInvocationContext other = (ContentAssistInvocationContext) obj;
186: return (fViewer == null && other.fViewer == null || fViewer != null
187: && fViewer.equals(other.fViewer))
188: && fOffset == other.fOffset
189: && (fDocument == null && other.fDocument == null || fDocument != null
190: && fDocument.equals(other.fDocument));
191: }
192:
193: /*
194: * @see java.lang.Object#hashCode()
195: */
196: public int hashCode() {
197: return 23459213 << 5
198: | (fViewer == null ? 0 : fViewer.hashCode() << 3)
199: | fOffset;
200: }
201: }
|