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: package org.netbeans.modules.cnd.editor.fortran;
043:
044: import java.io.Writer;
045: import java.io.IOException;
046: import java.io.CharArrayWriter;
047: import java.util.ArrayList;
048:
049: import java.awt.event.ActionEvent;
050:
051: import javax.swing.JEditorPane;
052: import javax.swing.Action;
053: import javax.swing.text.Caret;
054: import javax.swing.text.Position;
055: import javax.swing.text.Document;
056: import javax.swing.text.JTextComponent;
057: import javax.swing.text.TextAction;
058: import javax.swing.text.BadLocationException;
059:
060: import org.netbeans.editor.*;
061: import org.netbeans.editor.ext.*;
062:
063: import org.netbeans.modules.editor.*;
064: import org.netbeans.modules.cnd.MIMENames;
065:
066: /**
067: * Fortran editor kit with appropriate document
068: */
069:
070: public class FKit extends NbEditorKit {
071:
072: @Override
073: public String getContentType() {
074: return MIMENames.FORTRAN_MIME_TYPE;
075: }
076:
077: @Override
078: public void install(JEditorPane c) {
079: super .install(c);
080: }
081:
082: @Override
083: public Document createDefaultDocument() {
084: BaseDocument doc = new NbEditorDocument(this .getClass());
085: // Force '\n' as write line separator // !!! move to initDocument()
086: doc.putProperty(BaseDocument.WRITE_LINE_SEPARATOR_PROP,
087: BaseDocument.LS_LF);
088: return doc;
089: }
090:
091: /** Create new instance of syntax coloring scanner
092: * @param doc document to operate on. It can be null in the cases the syntax
093: * creation is not related to the particular document
094: */
095: @Override
096: public Syntax createSyntax(Document doc) {
097: return new FSyntax();
098: }
099:
100: /** Create the formatter appropriate for this kit */
101: @Override
102: public Formatter createFormatter() {
103: return new FFormatter(this .getClass());
104: }
105:
106: @Override
107: protected Action[] createActions() {
108: int arraySize = 2;
109: int numAddClasses = 0;
110: if (actionClasses != null) {
111: numAddClasses = actionClasses.size();
112: arraySize += numAddClasses;
113: }
114: Action[] fortranActions = new Action[arraySize];
115: int index = 0;
116: if (actionClasses != null) {
117: for (int i = 0; i < numAddClasses; i++) {
118: Class c = actionClasses.get(i);
119: try {
120: fortranActions[index] = (Action) c.newInstance();
121: } catch (java.lang.InstantiationException e) {
122: e.printStackTrace();
123: } catch (java.lang.IllegalAccessException e) {
124: e.printStackTrace();
125: }
126: index++;
127: }
128: }
129: fortranActions[index++] = new FDefaultKeyTypedAction();
130: fortranActions[index++] = new FFormatAction();
131: return TextAction.augmentList(super .createActions(),
132: fortranActions);
133: }
134:
135: /** Holds action classes to be created as part of createAction.
136: This allows dependent modules to add editor actions to this
137: kit on startup.
138: */
139: private static ArrayList<Class> actionClasses = null;
140:
141: public static void addActionClass(Class action) {
142: if (actionClasses == null) {
143: actionClasses = new ArrayList<Class>(2);
144: }
145: actionClasses.add(action);
146: }
147:
148: @Override
149: protected void updateActions() {
150: super .updateActions();
151: addSystemActionMapping(formatAction, FFormatAction.class);
152: }
153:
154: public static class FFormatAction extends BaseAction {
155:
156: public FFormatAction() {
157: super (BaseKit.formatAction, MAGIC_POSITION_RESET
158: | UNDO_MERGE_RESET);
159: putValue("helpID", FFormatAction.class.getName()); // NOI18N
160: }
161:
162: public void actionPerformed(ActionEvent evt,
163: JTextComponent target) {
164: if (target != null) {
165:
166: if (!target.isEditable() || !target.isEnabled()) {
167: target.getToolkit().beep();
168: return;
169: }
170:
171: Caret caret = target.getCaret();
172: BaseDocument doc = (BaseDocument) target.getDocument();
173:
174: doc.atomicLock();
175: try {
176: int caretLine = Utilities.getLineOffset(doc, caret
177: .getDot());
178: int startPos;
179: Position endPosition;
180: if (caret.isSelectionVisible()) {
181: startPos = target.getSelectionStart();
182: endPosition = doc.createPosition(target
183: .getSelectionEnd());
184: } else {
185: startPos = 0;
186: endPosition = doc.createPosition(doc
187: .getLength());
188: }
189: int pos = startPos;
190:
191: while (pos < endPosition.getOffset()) {
192: int stopPos = endPosition.getOffset();
193:
194: CharArrayWriter cw = new CharArrayWriter();
195: Writer w = doc.getFormatter().createWriter(doc,
196: pos, cw);
197: w.write(doc.getChars(pos, stopPos - pos));
198: w.close();
199: String out = new String(cw.toCharArray());
200: doc.remove(pos, stopPos - pos);
201: doc.insertString(pos, out, null);
202: pos += out.length(); // go to the end of the area inserted
203: }
204:
205: // Restore the line
206: pos = Utilities.getRowStartFromLineOffset(doc,
207: caretLine);
208: if (pos >= 0) {
209: caret.setDot(pos);
210: }
211: } catch (BadLocationException e) {
212: if (System.getProperty("netbeans.debug.exceptions") != null) { // NOI18N
213: e.printStackTrace();
214: }
215: } catch (IOException e) {
216: if (System.getProperty("netbeans.debug.exceptions") != null) { // NOI18N
217: e.printStackTrace();
218: }
219: } finally {
220: doc.atomicUnlock();
221: }
222: }
223: }
224: }
225:
226: public static class FDefaultKeyTypedAction extends
227: ExtDefaultKeyTypedAction {
228:
229: /** Check and possibly popup, hide or refresh the completion */
230: @Override
231: protected void checkCompletion(JTextComponent target,
232: String typedText) {
233: Completion completion = ExtUtilities.getCompletion(target);
234: if (completion != null && typedText.length() > 0) {
235: if (!completion.isPaneVisible()) { // pane not visible yet
236: if (completion.isAutoPopupEnabled()) {
237: boolean pop = false;
238: switch (typedText.charAt(0)) {
239: case ' ':
240: int dotPos = target.getCaret().getDot();
241: BaseDocument doc = (BaseDocument) target
242: .getDocument();
243:
244: if (dotPos >= 2) { // last char before inserted space
245: int pos = Math.max(dotPos - 5, 0);
246: try {
247: String txtBeforeSpace = doc
248: .getText(pos, dotPos - pos);
249: if (txtBeforeSpace.endsWith("new ")) { // NOI18N
250: //XXX && !Character.isCCIdentifierPart(txtBeforeSpace.charAt(0))) {
251: pop = true;
252: } else if (txtBeforeSpace
253: .endsWith(", ")) { // NOI18N
254: pop = true;
255: }
256: } catch (BadLocationException e) {
257: }
258: }
259: break;
260:
261: case '.':
262: case ',':
263: pop = true;
264: break;
265:
266: }
267:
268: if (pop) {
269: completion.popup(true);
270: } else {
271: completion.cancelRequest();
272: }
273: }
274:
275: } else { // the pane is already visible
276: switch (typedText.charAt(0)) {
277: case '=':
278: case '{':
279: case ';':
280: completion.setPaneVisible(false);
281: break;
282:
283: default:
284: completion.refresh(true);
285: break;
286: }
287: }
288: }
289: }
290: } // end class FDefaultKeyTypedAction
291: }
|