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.actions;
011:
012: import java.util.LinkedList;
013: import java.util.List;
014: import java.util.ResourceBundle;
015:
016: import org.eclipse.core.runtime.Assert;
017:
018: import org.eclipse.jface.text.BadLocationException;
019: import org.eclipse.jface.text.BadPartitioningException;
020: import org.eclipse.jface.text.IDocument;
021: import org.eclipse.jface.text.IDocumentExtension3;
022: import org.eclipse.jface.text.ITextSelection;
023: import org.eclipse.jface.text.ITypedRegion;
024:
025: import org.eclipse.ui.texteditor.ITextEditor;
026:
027: import org.eclipse.jdt.ui.text.IJavaPartitions;
028:
029: /**
030: * Action that encloses the editor's current selection with Java block comment terminators
031: * (<code>/*</code> and <code>*/</code>).
032: *
033: * @since 3.0
034: */
035: public class AddBlockCommentAction extends BlockCommentAction {
036:
037: /**
038: * Creates a new instance.
039: *
040: * @param bundle the resource bundle
041: * @param prefix a prefix to be prepended to the various resource keys
042: * (described in <code>ResourceAction</code> constructor), or
043: * <code>null</code> if none
044: * @param editor the text editor
045: */
046: public AddBlockCommentAction(ResourceBundle bundle, String prefix,
047: ITextEditor editor) {
048: super (bundle, prefix, editor);
049: }
050:
051: /*
052: * @see org.eclipse.jdt.internal.ui.actions.BlockCommentAction#runInternal(org.eclipse.jface.text.ITextSelection, org.eclipse.jface.text.IDocumentExtension3, org.eclipse.jdt.internal.ui.actions.BlockCommentAction.Edit.EditFactory)
053: */
054: protected void runInternal(ITextSelection selection,
055: IDocumentExtension3 docExtension, Edit.EditFactory factory)
056: throws BadLocationException, BadPartitioningException {
057: int selectionOffset = selection.getOffset();
058: int selectionEndOffset = selectionOffset
059: + selection.getLength();
060: List edits = new LinkedList();
061: ITypedRegion partition = docExtension.getPartition(
062: IJavaPartitions.JAVA_PARTITIONING, selectionOffset,
063: false);
064:
065: handleFirstPartition(partition, edits, factory, selectionOffset);
066:
067: while (partition.getOffset() + partition.getLength() < selectionEndOffset) {
068: partition = handleInteriorPartition(partition, edits,
069: factory, docExtension);
070: }
071:
072: handleLastPartition(partition, edits, factory,
073: selectionEndOffset);
074:
075: executeEdits(edits);
076: }
077:
078: /**
079: * Handle the partition under the start offset of the selection.
080: *
081: * @param partition the partition under the start of the selection
082: * @param edits the list of edits to later execute
083: * @param factory the factory for edits
084: * @param offset the start of the selection, which must lie inside
085: * <code>partition</code>
086: */
087: private void handleFirstPartition(ITypedRegion partition,
088: List edits, Edit.EditFactory factory, int offset)
089: throws BadLocationException {
090:
091: int partOffset = partition.getOffset();
092: String partType = partition.getType();
093:
094: Assert.isTrue(partOffset <= offset, "illegal partition"); //$NON-NLS-1$
095:
096: // first partition: mark start of comment
097: if (partType == IDocument.DEFAULT_CONTENT_TYPE) {
098: // Java code: right where selection starts
099: edits.add(factory.createEdit(offset, 0, getCommentStart()));
100: } else if (isSpecialPartition(partType)) {
101: // special types: include the entire partition
102: edits.add(factory.createEdit(partOffset, 0,
103: getCommentStart()));
104: } // javadoc: no mark, will only start after comment
105:
106: }
107:
108: /**
109: * Handles partition boundaries within the selection. The end of the current
110: * partition and the start of the next partition are examined for whether
111: * they contain comment tokens that interfere with the created comment.
112: * <p>
113: * Comment tokens are removed from interior multi-line comments. Javadoc
114: * comments are left as is; instead, multi-line comment tokens are inserted
115: * before and after Javadoc partitions to ensure that the entire selected
116: * area is commented.
117: * </p>
118: * <p>
119: * The next partition is returned.
120: * </p>
121: *
122: * @param partition the current partition
123: * @param edits the list of edits to add to
124: * @param factory the edit factory
125: * @param docExtension the document to get the partitions from
126: * @return the next partition after the current
127: * @throws BadLocationException if accessing the document fails - this can
128: * only happen if the document gets modified concurrently
129: * @throws BadPartitioningException if the document does not have a Java
130: * partitioning
131: */
132: private ITypedRegion handleInteriorPartition(
133: ITypedRegion partition, List edits,
134: Edit.EditFactory factory, IDocumentExtension3 docExtension)
135: throws BadPartitioningException, BadLocationException {
136:
137: // end of previous partition
138: String partType = partition.getType();
139: int partEndOffset = partition.getOffset()
140: + partition.getLength();
141: int tokenLength = getCommentStart().length();
142:
143: boolean wasJavadoc = false; // true if the previous partition is javadoc
144:
145: if (partType == IJavaPartitions.JAVA_DOC) {
146:
147: wasJavadoc = true;
148:
149: } else if (partType == IJavaPartitions.JAVA_MULTI_LINE_COMMENT) {
150:
151: // already in a comment - remove ending mark
152: edits.add(factory.createEdit(partEndOffset - tokenLength,
153: tokenLength, "")); //$NON-NLS-1$
154:
155: }
156:
157: // advance to next partition
158: partition = docExtension
159: .getPartition(IJavaPartitions.JAVA_PARTITIONING,
160: partEndOffset, false);
161: partType = partition.getType();
162:
163: // start of next partition
164: if (wasJavadoc) {
165:
166: // if previous was javadoc, and the current one is not a comment,
167: // then add a block comment start
168: if (partType == IDocument.DEFAULT_CONTENT_TYPE
169: || isSpecialPartition(partType)) {
170: edits.add(factory.createEdit(partition.getOffset(), 0,
171: getCommentStart()));
172: }
173:
174: } else { // !wasJavadoc
175:
176: if (partType == IJavaPartitions.JAVA_DOC) {
177: // if next is javadoc, end block comment before
178: edits.add(factory.createEdit(partition.getOffset(), 0,
179: getCommentEnd()));
180: } else if (partType == IJavaPartitions.JAVA_MULTI_LINE_COMMENT) {
181: // already in a comment - remove startToken
182: edits.add(factory.createEdit(partition.getOffset(),
183: getCommentStart().length(), "")); //$NON-NLS-1$
184: }
185: }
186:
187: return partition;
188: }
189:
190: /**
191: * Handles the partition under the end of the selection. For normal java
192: * code, the comment end token is inserted at the selection end; if the
193: * selection ends inside a special (i.e. string, character, line comment)
194: * partition, the entire partition is included inside the comment.
195: *
196: * @param partition the partition under the selection end offset
197: * @param edits the list of edits to add to
198: * @param factory the edit factory
199: * @param endOffset the end offset of the selection
200: */
201: private void handleLastPartition(ITypedRegion partition,
202: List edits, Edit.EditFactory factory, int endOffset)
203: throws BadLocationException {
204:
205: String partType = partition.getType();
206:
207: if (partType == IDocument.DEFAULT_CONTENT_TYPE) {
208: // normal java: end comment where selection ends
209: edits
210: .add(factory.createEdit(endOffset, 0,
211: getCommentEnd()));
212: } else if (isSpecialPartition(partType)) {
213: // special types: consume entire partition
214: edits.add(factory.createEdit(partition.getOffset()
215: + partition.getLength(), 0, getCommentEnd()));
216: }
217:
218: }
219:
220: /**
221: * Returns whether <code>partType</code> is special, i.e. a Java
222: * <code>String</code>,<code>Character</code>, or
223: * <code>Line End Comment</code> partition.
224: *
225: * @param partType the partition type to check
226: * @return <code>true</code> if <code>partType</code> is special,
227: * <code>false</code> otherwise
228: */
229: private boolean isSpecialPartition(String partType) {
230: return partType == IJavaPartitions.JAVA_CHARACTER
231: || partType == IJavaPartitions.JAVA_STRING
232: || partType == IJavaPartitions.JAVA_SINGLE_LINE_COMMENT;
233: }
234:
235: /*
236: * @see org.eclipse.jdt.internal.ui.actions.BlockCommentAction#validSelection(org.eclipse.jface.text.ITextSelection)
237: */
238: protected boolean isValidSelection(ITextSelection selection) {
239: return selection != null && !selection.isEmpty()
240: && selection.getLength() > 0;
241: }
242:
243: }
|