001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 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.ui.texteditor;
011:
012: import org.eclipse.jface.text.BadLocationException;
013: import org.eclipse.jface.text.BadPositionCategoryException;
014: import org.eclipse.jface.text.DefaultPositionUpdater;
015: import org.eclipse.jface.text.IDocument;
016: import org.eclipse.jface.text.IPositionUpdater;
017: import org.eclipse.jface.text.ITextSelection;
018: import org.eclipse.jface.text.Position;
019: import org.eclipse.jface.viewers.ISelection;
020: import org.eclipse.jface.viewers.ISelectionProvider;
021:
022: import org.eclipse.ui.IEditorPart;
023: import org.eclipse.ui.IMemento;
024: import org.eclipse.ui.INavigationLocation;
025: import org.eclipse.ui.NavigationLocation;
026:
027: /**
028: * Represents the text selection context marked for the user in the navigation history.
029: *
030: * @since 2.1
031: */
032: public class TextSelectionNavigationLocation extends NavigationLocation {
033:
034: // Memento tags and values
035: private static final String TAG_X = "x"; //$NON-NLS-1$
036: private static final String TAG_Y = "y"; //$NON-NLS-1$
037: private static final String TAG_INFO = "info"; //$NON-NLS-1$
038: private static final String INFO_DELETED = "deleted"; //$NON-NLS-1$
039: private static final String INFO_NOT_DELETED = "not_deleted"; //$NON-NLS-1$
040:
041: private static final String CATEGORY = "__navigation_" + TextSelectionNavigationLocation.class.hashCode(); //$NON-NLS-1$
042: private static final IPositionUpdater fgPositionUpdater = new DefaultPositionUpdater(
043: CATEGORY);
044:
045: private Position fPosition;
046: private IDocument fDocument;
047: private Position fSavedPosition;
048:
049: /**
050: * Creates a new text selection navigation location.
051: *
052: * @param part the text editor part
053: * @param initialize a boolean indicating whether to initialize the new instance from the current selection
054: */
055: public TextSelectionNavigationLocation(ITextEditor part,
056: boolean initialize) {
057: super (part);
058:
059: if (initialize) {
060:
061: ISelection s = part.getSelectionProvider().getSelection();
062: if (s == null || s.isEmpty())
063: return;
064:
065: ITextSelection selection = (ITextSelection) s;
066: if (selection.getOffset() == 0
067: && selection.getLength() == 0)
068: return;
069:
070: IDocument document = getDocument(part);
071: Position position = new Position(selection.getOffset(),
072: selection.getLength());
073: if (installOnDocument(document, position)) {
074: fDocument = document;
075: fPosition = position;
076: if (!part.isDirty())
077: fSavedPosition = new Position(fPosition.offset,
078: fPosition.length);
079: }
080: }
081: }
082:
083: /**
084: * Returns the text editor's document.
085: *
086: * @param part the text editor
087: * @return the document of the given text editor
088: */
089: private IDocument getDocument(ITextEditor part) {
090: IDocumentProvider provider = part.getDocumentProvider();
091: return provider.getDocument(part.getEditorInput());
092: }
093:
094: /**
095: * Installs the given position on the given document.
096: *
097: * @param document the document
098: * @param position the position
099: * @return <code>true</code> if the position could be installed
100: */
101: private boolean installOnDocument(IDocument document,
102: Position position) {
103:
104: if (document != null && position != null) {
105:
106: if (!document.containsPositionCategory(CATEGORY)) {
107: document.addPositionCategory(CATEGORY);
108: document.addPositionUpdater(fgPositionUpdater);
109: }
110:
111: try {
112: document.addPosition(CATEGORY, position);
113: return true;
114: } catch (BadLocationException e) {
115: } catch (BadPositionCategoryException e) {
116: }
117: }
118:
119: return false;
120: }
121:
122: /**
123: * Uninstalls the given position from the given document.
124: *
125: * @param document the document
126: * @param position the position
127: * @return <code>true</code> if the position could be uninstalled
128: */
129: private boolean uninstallFromDocument(IDocument document,
130: Position position) {
131:
132: if (document != null && position != null) {
133: try {
134:
135: document.removePosition(CATEGORY, position);
136:
137: Position[] category = document.getPositions(CATEGORY);
138: if (category == null || category.length == 0) {
139: document.removePositionCategory(CATEGORY);
140: document.removePositionUpdater(fgPositionUpdater);
141: }
142: return true;
143:
144: } catch (BadPositionCategoryException e) {
145: }
146: }
147:
148: return false;
149: }
150:
151: /*
152: * @see Object#toString()
153: */
154: public String toString() {
155: return "Selection<" + fPosition + ">"; //$NON-NLS-1$ //$NON-NLS-2$
156: }
157:
158: /**
159: * Tells whether this location is equal to the current
160: * location in the given text editor.
161: *
162: * @param part the text editor
163: * @return <code>true</code> if the locations are equal
164: */
165: private boolean equalsLocationOf(ITextEditor part) {
166:
167: if (fPosition == null)
168: return true;
169:
170: if (fPosition.isDeleted)
171: return false;
172:
173: ISelectionProvider provider = part.getSite()
174: .getSelectionProvider();
175: ISelection selection = provider.getSelection();
176: if (selection instanceof ITextSelection) {
177: ITextSelection textSelection = (ITextSelection) selection;
178: if (textSelection.getOffset() == fPosition.offset
179: && textSelection.getLength() == fPosition.length) {
180: String text = textSelection.getText();
181: if (text != null) {
182: try {
183: return text.equals(fDocument.get(
184: fPosition.offset, fPosition.length));
185: } catch (BadLocationException e) {
186: }
187: }
188: }
189: }
190:
191: return false;
192: }
193:
194: public void dispose() {
195: uninstallFromDocument(fDocument, fPosition);
196: fDocument = null;
197: fPosition = null;
198: fSavedPosition = null;
199: super .dispose();
200: }
201:
202: /**
203: * Releases the state of this location.
204: */
205: public void releaseState() {
206: // deactivate
207: uninstallFromDocument(fDocument, fPosition);
208: fDocument = null;
209: fPosition = null;
210: fSavedPosition = null;
211: super .releaseState();
212: }
213:
214: /**
215: * Merges the given location into this one.
216: *
217: * @param location the location to merge into this one
218: * @return <code>true<code> if merging was successful
219: */
220: public boolean mergeInto(INavigationLocation location) {
221:
222: if (location == null)
223: return false;
224:
225: if (getClass() != location.getClass())
226: return false;
227:
228: if (fPosition == null || fPosition.isDeleted)
229: return true;
230:
231: TextSelectionNavigationLocation s = (TextSelectionNavigationLocation) location;
232: if (s.fPosition == null || s.fPosition.isDeleted) {
233: uninstallFromDocument(fDocument, fPosition);
234: s.fDocument = fDocument;
235: s.fPosition = fPosition;
236: s.fSavedPosition = fSavedPosition;
237: return true;
238: }
239:
240: if (s.fDocument == fDocument) {
241: if (s.fPosition.overlapsWith(fPosition.offset,
242: fPosition.length)
243: || fPosition.offset + fPosition.length == s.fPosition.offset
244: || s.fPosition.offset + s.fPosition.length == fPosition.offset) {
245: s.fPosition.offset = fPosition.offset;
246: s.fPosition.length = fPosition.length;
247: return true;
248: }
249: }
250:
251: return false;
252: }
253:
254: /**
255: * Restores this location.
256: */
257: public void restoreLocation() {
258: if (fPosition == null || fPosition.isDeleted)
259: return;
260:
261: IEditorPart part = getEditorPart();
262: if (part instanceof ITextEditor) {
263: ITextEditor editor = (ITextEditor) getEditorPart();
264: editor.selectAndReveal(fPosition.offset, fPosition.length);
265: }
266: }
267:
268: /**
269: * Restores the object state from the given memento.
270: *
271: * @param memento the memento
272: */
273: public void restoreState(IMemento memento) {
274:
275: IEditorPart part = getEditorPart();
276: if (part instanceof ITextEditor) {
277:
278: // restore
279: fDocument = getDocument((ITextEditor) part);
280:
281: Integer offset = memento.getInteger(TAG_X);
282: Integer length = memento.getInteger(TAG_Y);
283: String deleted = memento.getString(TAG_INFO);
284:
285: if (offset != null && length != null) {
286: Position p = new Position(offset.intValue(), length
287: .intValue());
288: if (deleted != null)
289: p.isDeleted = INFO_DELETED.equals(deleted) ? true
290: : false;
291:
292: // activate
293: if (installOnDocument(fDocument, p)) {
294: fPosition = p;
295: if (!part.isDirty())
296: fSavedPosition = new Position(fPosition.offset,
297: fPosition.length);
298: }
299: }
300: }
301: }
302:
303: /**
304: * Stores the object state into the given memento.
305: *
306: * @param memento the memento
307: */
308: public void saveState(IMemento memento) {
309: if (fSavedPosition != null) {
310: memento.putInteger(TAG_X, fSavedPosition.offset);
311: memento.putInteger(TAG_Y, fSavedPosition.length);
312: memento.putString(TAG_INFO,
313: (fSavedPosition.isDeleted ? INFO_DELETED
314: : INFO_NOT_DELETED));
315: }
316: }
317:
318: /**
319: * Hook method which is called when the given editor has been saved.
320: *
321: * @param part the editor part
322: */
323: public void partSaved(IEditorPart part) {
324: // http://dev.eclipse.org/bugs/show_bug.cgi?id=25440
325: if (fPosition == null || fPosition.isDeleted())
326: fSavedPosition = null;
327: else
328: fSavedPosition = new Position(fPosition.offset,
329: fPosition.length);
330: }
331:
332: /**
333: * Updates the this location.
334: */
335: public void update() {
336: IEditorPart part = getEditorPart();
337: if (part instanceof ITextEditor) {
338: ITextEditor textEditor = (ITextEditor) getEditorPart();
339:
340: if (equalsLocationOf(textEditor))
341: return;
342:
343: ISelection s = textEditor.getSelectionProvider()
344: .getSelection();
345: if (s == null || s.isEmpty())
346: return;
347:
348: ITextSelection selection = (ITextSelection) s;
349: if (selection.getOffset() == 0
350: && selection.getLength() == 0)
351: return;
352:
353: fPosition.offset = selection.getOffset();
354: fPosition.length = selection.getLength();
355: fPosition.isDeleted = false;
356:
357: if (!part.isDirty())
358: fSavedPosition = new Position(fPosition.offset,
359: fPosition.length);
360: }
361: }
362: }
|