001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: /** C++ editor kit with appropriate document */package org.netbeans.modules.cnd.editor.cplusplus;
043:
044: import java.awt.event.ActionEvent;
045: import javax.swing.Action;
046: import javax.swing.text.BadLocationException;
047: import javax.swing.text.Caret;
048: import javax.swing.text.Document;
049: import javax.swing.text.JTextComponent;
050: import org.netbeans.api.lexer.Language;
051: import org.netbeans.cnd.api.lexer.CndLexerUtilities;
052: import org.netbeans.cnd.api.lexer.CppTokenId;
053: import org.netbeans.cnd.api.lexer.Filter;
054: import org.netbeans.editor.BaseDocument;
055: import org.netbeans.editor.Syntax;
056: import org.netbeans.editor.TokenItem;
057: import org.netbeans.editor.Utilities;
058: import org.netbeans.modules.cnd.MIMENames;
059: import org.netbeans.modules.cnd.editor.spi.cplusplus.CCSyntaxSupport;
060:
061: public class CKit extends CCKit {
062:
063: @Override
064: public String getContentType() {
065: return MIMENames.C_MIME_TYPE;
066: }
067:
068: /**
069: * Create new instance of a C syntax coloring scanner.
070: *
071: * @param doc document to operate on
072: */
073: @Override
074: public Syntax createSyntax(Document doc) {
075: return new CSyntax();
076: }
077:
078: @Override
079: protected Language<CppTokenId> getLanguage() {
080: return CppTokenId.languageC();
081: }
082:
083: @Override
084: protected Filter<CppTokenId> getFilter() {
085: return CndLexerUtilities.getStdCFilter();
086: }
087:
088: @Override
089: protected Action getCommentAction() {
090: return new CCommentAction();
091: }
092:
093: @Override
094: protected Action getUncommentAction() {
095: return new CUncommentAction();
096: }
097:
098: @Override
099: protected Action getToggleCommentAction() {
100: return new CToggleCommentAction();
101: }
102:
103: private static String START_BLOCK_COMMENT = "/*"; // NOI18N
104: private static String END_BLOCK_COMMENT = "*/"; // NOI18N
105:
106: private static String insertStartCommentString = START_BLOCK_COMMENT
107: + "\n"; // NOI18N
108: private static String insertEndCommentString = END_BLOCK_COMMENT
109: + "\n"; // NOI18N
110:
111: private static final class CCommentAction extends CommentAction {
112: private CCommentAction() {
113: // fake string
114: super ("//"); // NOI18N
115: }
116:
117: @Override
118: public void actionPerformed(ActionEvent evt,
119: JTextComponent target) {
120: doCStyleComment(target);
121: }
122:
123: private static void doCStyleComment(JTextComponent target) {
124: if (target != null) {
125: if (!target.isEditable() || !target.isEnabled()) {
126: target.getToolkit().beep();
127: return;
128: }
129: Caret caret = target.getCaret();
130: BaseDocument doc = (BaseDocument) target.getDocument();
131: try {
132: doc.atomicLock();
133: try {
134: int startPos;
135: int endPos;
136: String endString = insertEndCommentString;
137: //if (caret.isSelectionVisible()) {
138: if (Utilities.isSelectionShowing(caret)) {
139: startPos = Utilities.getRowStart(doc,
140: target.getSelectionStart());
141: endPos = target.getSelectionEnd();
142: if (endPos > 0
143: && Utilities.getRowStart(doc,
144: endPos) == endPos) {
145: endPos--;
146: }
147:
148: int lineCnt = Utilities.getRowCount(doc,
149: startPos, endPos);
150: endPos = Utilities.getRowStart(doc,
151: startPos, +lineCnt);
152: } else {
153: // selection not visible, surround only one line
154: startPos = Utilities.getRowStart(doc,
155: target.getSelectionStart());
156: endPos = Utilities.getRowStart(doc,
157: startPos, +1);
158: if (endPos == -1) {
159: endPos = doc.getLength();
160: endString = "\n"
161: + insertEndCommentString; // NOI18N
162: }
163: }
164: // insert end line
165: doc.insertString(endPos, endString, null);
166: // then start line
167: doc.insertString(startPos,
168: insertStartCommentString, null);
169: } finally {
170: doc.atomicUnlock();
171: }
172: } catch (BadLocationException e) {
173: target.getToolkit().beep();
174: }
175: }
176: }
177: }
178:
179: private static final class CUncommentAction extends UncommentAction {
180: private CUncommentAction() {
181: // fake string
182: super ("//"); // NOI18N
183: }
184:
185: @Override
186: public void actionPerformed(ActionEvent evt,
187: JTextComponent target) {
188: doCStyleUncomment(target);
189: }
190:
191: private static void doCStyleUncomment(JTextComponent target) {
192: if (target != null) {
193: if (!target.isEditable() || !target.isEnabled()) {
194: target.getToolkit().beep();
195: return;
196: }
197: Caret caret = target.getCaret();
198: BaseDocument doc = (BaseDocument) target.getDocument();
199: try {
200: doc.atomicLock();
201: try {
202: int startPos;
203: int endPos;
204: //if (caret.isSelectionVisible()) {
205: if (Utilities.isSelectionShowing(caret)) {
206: startPos = target.getSelectionStart();
207: endPos = target.getSelectionEnd();
208: if (endPos > 0
209: && Utilities.getRowStart(doc,
210: endPos) == endPos) {
211: endPos--;
212: }
213: } else {
214: // selection not visible
215: endPos = startPos = target
216: .getSelectionStart();
217: }
218: // get token inside selection
219: CCSyntaxSupport sup = (CCSyntaxSupport) Utilities
220: .getSyntaxSupport(target);
221: TokenItem item = sup.getTokenChain(startPos,
222: endPos);
223: while (item != null
224: && item.getOffset() < endPos
225: && item.getTokenID() == CCTokenContext.WHITESPACE) {
226: item = item.getNext();
227: }
228: if (item != null
229: && item.getTokenID() == CCTokenContext.BLOCK_COMMENT) {
230: int commentBlockStartOffset = item
231: .getOffset();
232: int commentBlockEndOffset = commentBlockStartOffset
233: + item.getImage().length();
234: int startLineStartPos = Utilities
235: .getRowStart(doc,
236: commentBlockStartOffset);
237: int startLineEndPos = Utilities.getRowEnd(
238: doc, startLineStartPos);
239: String startLineContent = doc.getText(
240: startLineStartPos, startLineEndPos
241: - startLineStartPos);
242: if (!START_BLOCK_COMMENT
243: .equals(startLineContent.trim())) {
244: // not only "\*" on the line => remove only "\*" itself
245: startLineStartPos = commentBlockStartOffset;
246: startLineEndPos = startLineStartPos
247: + START_BLOCK_COMMENT.length();
248: } else {
249: // remove full line with eol
250: startLineEndPos = startLineEndPos < doc
251: .getLength() - 1 ? startLineEndPos + 1
252: : doc.getLength();
253: }
254: int endLineStartPos = Utilities
255: .getRowStart(doc,
256: commentBlockEndOffset);
257: int endLineEndPos = Utilities.getRowEnd(
258: doc, endLineStartPos);
259: String endLineContent = doc.getText(
260: endLineStartPos, endLineEndPos
261: - endLineStartPos);
262: if (!END_BLOCK_COMMENT
263: .equals(endLineContent.trim())) {
264: // not only "*/" on the line => remove only "*/" itself
265: endLineEndPos = commentBlockEndOffset;
266: endLineStartPos = endLineEndPos
267: - END_BLOCK_COMMENT.length();
268: } else {
269: // remove full line with eol
270: endLineEndPos = endLineEndPos < doc
271: .getLength() - 1 ? endLineEndPos + 1
272: : doc.getLength();
273: }
274: // remove end line
275: doc.remove(endLineStartPos, endLineEndPos
276: - endLineStartPos);
277: // remove start line
278: doc
279: .remove(startLineStartPos,
280: startLineEndPos
281: - startLineStartPos);
282: }
283:
284: } finally {
285: doc.atomicUnlock();
286: }
287: } catch (BadLocationException e) {
288: target.getToolkit().beep();
289: }
290: }
291: }
292: }
293:
294: private static final class CToggleCommentAction extends
295: ToggleCommentAction {
296: private CToggleCommentAction() {
297: // fake string
298: super ("//"); // NOI18N
299: }
300:
301: @Override
302: public void actionPerformed(ActionEvent evt,
303: JTextComponent target) {
304: if (allComments(target)) {
305: CUncommentAction.doCStyleUncomment(target);
306: } else {
307: CCommentAction.doCStyleComment(target);
308: }
309: }
310:
311: private boolean allComments(JTextComponent target) {
312: Caret caret = target.getCaret();
313: BaseDocument doc = (BaseDocument) target.getDocument();
314: TokenItem item = null;
315: try {
316: doc.atomicLock();
317: try {
318: int startPos;
319: int endPos;
320: //if (caret.isSelectionVisible()) {
321: if (Utilities.isSelectionShowing(caret)) {
322: startPos = target.getSelectionStart();
323: endPos = target.getSelectionEnd();
324: if (endPos > 0
325: && Utilities.getRowStart(doc, endPos) == endPos) {
326: endPos--;
327: }
328: } else {
329: // selection not visible
330: endPos = startPos = target.getSelectionStart();
331: }
332: // get token inside selection
333: CCSyntaxSupport sup = (CCSyntaxSupport) Utilities
334: .getSyntaxSupport(target);
335: item = sup.getTokenChain(startPos, endPos);
336: while (item != null
337: && item.getOffset() < endPos
338: && (item.getTokenID() == CCTokenContext.WHITESPACE)) {
339: // all in comment means only whitespaces or block commens
340: item = item.getNext();
341: }
342: } finally {
343: doc.atomicUnlock();
344: }
345: } catch (BadLocationException e) {
346: target.getToolkit().beep();
347: }
348: return (item != null)
349: && (item.getTokenID() == CCTokenContext.BLOCK_COMMENT);
350: }
351: }
352:
353: }
|