KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > gsf > GsfEditorKitFactory


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.gsf;
20
21 import java.awt.Cursor JavaDoc;
22 import java.awt.event.ActionEvent JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.List JavaDoc;
26 import javax.swing.Action JavaDoc;
27 import javax.swing.JEditorPane JavaDoc;
28 import javax.swing.JEditorPane JavaDoc;
29 import javax.swing.JMenu JavaDoc;
30 import javax.swing.JMenuItem JavaDoc;
31 import javax.swing.KeyStroke JavaDoc;
32 import javax.swing.text.BadLocationException JavaDoc;
33 import javax.swing.text.Caret JavaDoc;
34 import javax.swing.text.Document JavaDoc;
35 import javax.swing.text.Document JavaDoc;
36 import javax.swing.text.JTextComponent JavaDoc;
37 import javax.swing.text.JTextComponent JavaDoc;
38 import javax.swing.text.Keymap JavaDoc;
39 import javax.swing.text.Position JavaDoc;
40 import javax.swing.text.TextAction JavaDoc;
41 import org.netbeans.api.gsf.BracketCompletion;
42 import org.netbeans.api.gsf.CancellableTask;
43 import org.netbeans.api.gsf.FormattingPreferences;
44 import org.netbeans.api.gsf.OffsetRange;
45 import org.netbeans.api.gsf.GsfTokenId;
46 import org.netbeans.api.gsf.GsfLanguage;
47 import org.netbeans.api.gsf.ParserResult;
48 import org.netbeans.api.lexer.Token;
49 import org.netbeans.api.lexer.TokenHierarchy;
50 import org.netbeans.api.lexer.TokenSequence;
51 import org.netbeans.api.retouche.source.CompilationController;
52 import org.netbeans.api.retouche.source.Phase;
53 import org.netbeans.api.retouche.source.Source;
54 import org.netbeans.editor.BaseAction;
55 import org.netbeans.editor.BaseAction;
56 import org.netbeans.editor.BaseDocument;
57 import org.netbeans.editor.BaseKit;
58 import org.netbeans.editor.BaseKit.InsertBreakAction;
59 import org.netbeans.editor.Formatter;
60 import org.netbeans.editor.GuardedDocument;
61 import org.netbeans.editor.GuardedException;
62 import org.netbeans.editor.Settings;
63 import org.netbeans.editor.SettingsNames;
64 import org.netbeans.editor.Syntax;
65 import org.netbeans.editor.SyntaxSupport;
66 import org.netbeans.editor.SyntaxUpdateTokens;
67 import org.netbeans.editor.TokenContextPath;
68 import org.netbeans.editor.TokenID;
69 import org.netbeans.editor.Utilities;
70 import org.netbeans.editor.ext.Completion;
71 import org.netbeans.editor.ext.ExtEditorUI;
72 import org.netbeans.editor.ext.ExtEditorUI;
73 import org.netbeans.editor.ext.ExtKit;
74 import org.netbeans.editor.ext.ExtKit.ExtDefaultKeyTypedAction;
75 import org.netbeans.editor.ext.ExtKit.ExtDeleteCharAction;
76 import org.netbeans.editor.ext.ExtKit.GotoDeclarationAction;
77 import org.netbeans.editor.ext.ExtSyntaxSupport;
78 import org.netbeans.editor.ext.ExtSyntaxSupport;
79 import org.netbeans.editor.ext.ExtSyntaxSupport;
80 import org.netbeans.lib.editor.codetemplates.api.CodeTemplateManager;
81 import org.netbeans.modules.editor.NbEditorKit;
82 import org.netbeans.modules.editor.NbEditorKit.NbGenerateGoToPopupAction;
83 import org.netbeans.modules.editor.retouche.InstantRenameAction;
84 import org.netbeans.modules.gsf.GsfDocument;
85 import org.netbeans.modules.gsf.Language;
86 import org.netbeans.modules.gsf.Language;
87 import org.netbeans.modules.gsf.Language;
88 import org.netbeans.modules.retouche.editor.GsfFormatter;
89 import org.netbeans.modules.retouche.editor.hyperlink.GoToSupport;
90 import org.openide.awt.Mnemonics;
91 import org.openide.filesystems.FileObject;
92 import org.openide.loaders.DataObject;
93 import org.openide.util.Exceptions;
94 import org.openide.util.NbBundle;
95
96
97 /**
98  * This class represents a generic Editor Kit which is shared by a number of different
99  * languages. The EditorKit is an innerclass, because its superclass (BaseKit) calls
100  * getContentType() as part of its constructor. Our getContentType implementation
101  * relies on accessing one of the fields passed in to our constructor; but when the
102  * super constructor is calling getContentType(), our own constructor has not yet been
103  * called. This is worked around by having an outer class which holds the field
104  * we need at constructor time (langauge).
105  *
106  * @author Tor Norbye
107  * @author Jan Jancura
108  */

109 public class GsfEditorKitFactory {
110     private final static boolean PRETTY_PRINT_AVAILABLE = Boolean.getBoolean("ruby.prettyprint");
111
112     public static final String JavaDoc selectNextElementAction = "select-element-next"; //NOI18N
113
public static final String JavaDoc selectPreviousElementAction = "select-element-previous"; //NOI18N
114

115     Language language;
116     String JavaDoc mimeType;
117
118     public GsfEditorKitFactory(Language language) {
119         assert language != null;
120         this.language = language;
121         this.mimeType = language.getMimeType();
122     }
123
124     /**
125      * Return the actual kit. This is necessary because NbEditorKit's constructor
126      * winds up calling getContentType(), before we've actually had a chance to
127      * construct our own editor kit (where getContentType() depends on construction
128      * of the object. The trick is to use an outer class, construct that first, and
129      *
130      */

131     public GsfEditorKit kit() {
132         LanguageRegistry registry = LanguageRegistry.getInstance();
133
134         return new GsfEditorKit();
135     }
136
137     private static Language getLanguage(BaseDocument doc) {
138         String JavaDoc mimeType = (String JavaDoc)doc.getProperty("mimeType");
139
140         if (mimeType != null) {
141             return LanguageRegistry.getInstance().getLanguageByMimeType(mimeType);
142         }
143
144         return null;
145     }
146
147     private FileObject getFileObject(Document JavaDoc doc) {
148         DataObject od = (DataObject)doc.getProperty(Document.StreamDescriptionProperty);
149
150         return (od != null) ? od.getPrimaryFile() : null;
151     }
152     
153     /**
154      * Returns true if bracket completion is enabled in options.
155      */

156     private static boolean completionSettingEnabled() {
157         //return ((Boolean)Settings.getValue(GsfEditorKit.class, JavaSettingsNames.PAIR_CHARACTERS_COMPLETION)).booleanValue();
158
return true;
159     }
160
161     public class GsfEditorKit extends NbEditorKit {
162         String JavaDoc mimeType;
163
164         public GsfEditorKit() {
165             Settings.setValue(GsfEditorKit.class, SettingsNames.CODE_FOLDING_ENABLE, Boolean.TRUE);
166             this.mimeType = language.getMimeType();
167         }
168
169         public String JavaDoc getContentType() {
170             return language.getMimeType();
171         }
172
173         // @Override
174
// public String updateColoringName(String coloringName) {
175
// return coloringName;
176
// }
177
public Document JavaDoc createDefaultDocument() {
178             Document JavaDoc doc = new GsfDocument(this.getClass(), language);
179
180             doc.putProperty("mimeType", mimeType); //NOI18N
181

182             return doc;
183         }
184         
185         public SyntaxSupport createSyntaxSupport(BaseDocument doc) {
186             return new ExtSyntaxSupport(doc) {
187             
188                 public int[] findMatchingBlock(int offset, boolean simpleSearch)
189                         throws BadLocationException JavaDoc {
190                     // Do parenthesis matching, if applicable
191
BracketCompletion bracketCompletion = language.getBracketCompletion();
192                     if (bracketCompletion != null) {
193                         OffsetRange range = bracketCompletion.findMatching(getDocument(), offset/*, simpleSearch*/);
194                         if (range == OffsetRange.NONE) {
195                             return null;
196                         } else {
197                             return new int[] { range.getStart(), range.getEnd() };
198                         }
199                     }
200                     
201                     return null;
202                 }
203             };
204         }
205
206         
207
208         protected void initDocument(BaseDocument doc) {
209             // doc.addLayer(new JavaDrawLayerFactory.JavaLayer(),
210
// JavaDrawLayerFactory.JAVA_LAYER_VISIBILITY);
211
// doc.addDocumentListener(new JavaDrawLayerFactory.LParenWatcher());
212

213             // Support for custom code folding markers on line comment lines
214
//doc.putProperty(SyntaxUpdateTokens.class,
215
// new SyntaxUpdateTokens() {
216
// private List tokenList = new ArrayList();
217
//
218
// public void syntaxUpdateStart() {
219
// tokenList.clear();
220
// }
221
//
222
// public List syntaxUpdateEnd() {
223
// return tokenList;
224
// }
225
//
226
// public void syntaxUpdateToken(TokenID id, TokenContextPath contextPath,
227
// int offset, int length) {
228
// if (GsfTokenId.LINE_COMMENT == id) {
229
// tokenList.add(new TokenInfo(id, contextPath, offset, length));
230
// }
231
// }
232
// });
233

234             // XXX This appears in JavaKit, not sure why, but doing it just in case.
235
//do not ask why, fire bug in the IZ:
236
CodeTemplateManager.get(doc);
237         }
238
239         @Override JavaDoc
240         public Completion createCompletion(ExtEditorUI extEditorUI) {
241             //return new GenericCompletion(extEditorUI);
242
return null;
243         }
244
245         /** Create the formatter appropriate for this kit */
246         @Override JavaDoc
247         public Formatter createFormatter() {
248             throw new RuntimeException JavaDoc("Not yet implemented");
249
250             // return new GsfFormatter(this.getClass(), language, doc);
251
}
252
253         @Override JavaDoc
254         public void install(JEditorPane JavaDoc c) {
255             super.install(c);
256         }
257
258         @Override JavaDoc
259         public void deinstall(JEditorPane JavaDoc c) {
260             super.deinstall(c);
261         }
262
263         @Override JavaDoc
264         public Object JavaDoc clone() {
265             return new GsfEditorKit();
266         }
267
268         @Override JavaDoc
269         protected Action JavaDoc[] createActions() {
270             GsfLanguage gsfLanguage = language.getGsfLanguage();
271
272             ArrayList JavaDoc<Action JavaDoc> actions = new ArrayList JavaDoc(10);
273
274             actions.add(new GsfDefaultKeyTypedAction());
275             actions.add(new GsfInsertBreakAction());
276             actions.add(new GsfDeleteCharAction(deletePrevCharAction, false));
277
278             String JavaDoc lineCommentPrefix = (gsfLanguage != null) ? gsfLanguage.getLineCommentPrefix() : null;
279
280             if (lineCommentPrefix != null) {
281                 actions.add(new CommentAction(lineCommentPrefix));
282                 actions.add(new UncommentAction(lineCommentPrefix));
283             }
284
285             actions.add(new InstantRenameAction());
286             actions.add(new PrettyPrintAction());
287             actions.add(new GenericGoToDeclarationAction());
288             actions.add(new GenericGenerateGoToPopupAction());
289
290             actions.add(new SelectCodeElementAction(selectNextElementAction, true));
291             actions.add(new SelectCodeElementAction(selectPreviousElementAction, false));
292
293
294             return TextAction.augmentList(super.createActions(),
295                 actions.toArray(new Action JavaDoc[actions.size()]));
296         }
297         
298         public class PrettyPrintAction extends BaseAction {
299
300             static final long serialVersionUID =-1L;
301             public PrettyPrintAction() {
302                 super("pretty-print",
303                       ABBREV_RESET | MAGIC_POSITION_RESET | UNDO_MERGE_RESET);
304             }
305             
306             @Override JavaDoc
307             public boolean isEnabled() {
308                 return PRETTY_PRINT_AVAILABLE;
309             }
310
311             public void actionPerformed(ActionEvent JavaDoc evt, JTextComponent JavaDoc target) {
312                 if (target != null) {
313                     if (!target.isEditable() || !target.isEnabled()) {
314                         target.getToolkit().beep();
315                         return;
316                     }
317
318                     final BaseDocument doc = (BaseDocument)target.getDocument();
319                     FileObject fo = getFileObject(doc);
320                     if (fo == null) {
321                         target.getToolkit().beep();
322                         return;
323                     }
324
325                     // Set hourglass cursor
326
Cursor JavaDoc origCursor = target.getCursor();
327                     target.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
328
329                     try {
330                         Source js = Source.forFileObject(fo);
331                         final String JavaDoc[] result = new String JavaDoc[1];
332
333                         js.runUserActionTask(new CancellableTask<CompilationController>() {
334                             public void cancel() {
335                             }
336
337                             public void run(CompilationController controller)
338                                 throws Exception JavaDoc {
339                                 if (controller.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0) {
340                                     return;
341                                 }
342
343                                 FormattingPreferences preferences = new GsfFormatter.GenericFormattingPreferences(language.getFormatter().indentSize());
344                                 ParserResult result = controller.getParserResult();
345                                 language.getFormatter().reformat(doc, result, preferences);
346                                 Language language = controller.getLanguage();
347                             }
348                         }, true);
349                     } catch (IOException JavaDoc ioe) {
350                         Exceptions.printStackTrace(ioe);
351                     } finally {
352                         target.setCursor(origCursor);
353                     }
354                 }
355             }
356             
357             @Override JavaDoc
358             protected Class JavaDoc getShortDescriptionBundleClass() {
359                 return PrettyPrintAction.class;
360             }
361         }
362
363         public class GsfDefaultKeyTypedAction extends ExtDefaultKeyTypedAction {
364             @Override JavaDoc
365             protected void insertString(BaseDocument doc, int dotPos, Caret JavaDoc caret, String JavaDoc str,
366                 boolean overwrite) throws BadLocationException JavaDoc {
367                 if (completionSettingEnabled()) {
368                     Language language = getLanguage(doc);
369
370                     if (language != null) {
371                         BracketCompletion bracketCompletion = language.getBracketCompletion();
372
373                         if (bracketCompletion != null) {
374                             // TODO - check if we're in a comment etc. and if so, do nothing
375
boolean handled =
376                                 bracketCompletion.beforeCharInserted(doc, dotPos, caret,
377                                     str.charAt(0));
378
379                             if (!handled) {
380                                 super.insertString(doc, dotPos, caret, str, overwrite);
381                                 handled = bracketCompletion.afterCharInserted(doc, dotPos, caret,
382                                         str.charAt(0));
383                             }
384
385                             return;
386                         }
387                     }
388                 }
389
390                 super.insertString(doc, dotPos, caret, str, overwrite);
391             }
392
393             @Override JavaDoc
394             protected void replaceSelection(JTextComponent JavaDoc target, int dotPos, Caret JavaDoc caret,
395                 String JavaDoc str, boolean overwrite) throws BadLocationException JavaDoc {
396                 char insertedChar = str.charAt(0);
397                 Document JavaDoc document = target.getDocument();
398
399                 if (document instanceof BaseDocument) {
400                     BaseDocument doc = (BaseDocument)document;
401
402                     if (completionSettingEnabled()) {
403                         Language language = getLanguage(doc);
404
405                         if (language != null) {
406                             BracketCompletion bracketCompletion = language.getBracketCompletion();
407
408                             if (bracketCompletion != null) {
409                                 try {
410                                     int p0 = Math.min(caret.getDot(), caret.getMark());
411                                     int p1 = Math.max(caret.getDot(), caret.getMark());
412
413                                     if (p0 != p1) {
414                                         doc.remove(p0, p1 - p0);
415                                     }
416
417                                     int caretPosition = caret.getDot();
418
419                                     // XXX Change this to logic above with pre and after. If it's not
420
// handled keep going.
421
boolean handled =
422                                         bracketCompletion.beforeCharInserted(doc, caretPosition,
423                                             caret, insertedChar);
424
425                                     if (!handled) {
426                                         if ((str != null) && (str.length() > 0)) {
427                                             doc.insertString(p0, str, null);
428                                         }
429
430                                         bracketCompletion.afterCharInserted(doc, caret.getDot() - 1,
431                                             caret, insertedChar);
432                                     } else {
433                                         caret.setDot(caretPosition + 1);
434                                     }
435                                 } catch (BadLocationException JavaDoc e) {
436                                     e.printStackTrace();
437                                 }
438
439                                 return;
440                             }
441                         }
442                     }
443                 }
444
445                 super.replaceSelection(target, dotPos, caret, str, overwrite);
446             }
447         }
448
449         public class GsfInsertBreakAction extends InsertBreakAction {
450             static final long serialVersionUID = -1506173310438326380L;
451
452             @Override JavaDoc
453             protected Object JavaDoc beforeBreak(JTextComponent JavaDoc target, BaseDocument doc, Caret JavaDoc caret) {
454                 if (completionSettingEnabled()) {
455                     Language language = getLanguage(doc);
456
457                     if (language != null) {
458                         BracketCompletion bracketCompletion = language.getBracketCompletion();
459
460                         if (bracketCompletion != null) {
461                             try {
462                                 int newOffset = bracketCompletion.beforeBreak(doc, caret.getDot(), caret);
463
464                                 if (newOffset >= 0) {
465                                     return new Integer JavaDoc(newOffset);
466                                 }
467                             } catch (BadLocationException JavaDoc ble) {
468                                 Exceptions.printStackTrace(ble);
469                             }
470                         }
471                     }
472                 }
473
474                 // return Boolean.TRUE;
475
return null;
476             }
477
478             @Override JavaDoc
479             protected void afterBreak(JTextComponent JavaDoc target, BaseDocument doc, Caret JavaDoc caret,
480                 Object JavaDoc cookie) {
481                 if (completionSettingEnabled()) {
482                     if (cookie != null) {
483                         if (cookie instanceof Integer JavaDoc) {
484                             // integer
485
int nowDotPos = caret.getDot();
486                             caret.setDot(nowDotPos + 1);
487                         }
488                     }
489                 }
490             }
491         }
492
493         public class GsfDeleteCharAction extends ExtDeleteCharAction {
494             public GsfDeleteCharAction(String JavaDoc nm, boolean nextChar) {
495                 super(nm, nextChar);
496             }
497
498             @Override JavaDoc
499             protected void charBackspaced(BaseDocument doc, int dotPos, Caret JavaDoc caret, char ch)
500                 throws BadLocationException JavaDoc {
501                 if (completionSettingEnabled()) {
502                     Language language = getLanguage(doc);
503
504                     if (language != null) {
505                         BracketCompletion bracketCompletion = language.getBracketCompletion();
506
507                         if (bracketCompletion != null) {
508                             boolean success = bracketCompletion.charBackspaced(doc, dotPos, caret, ch);
509
510 // if (offset >= 0) {
511
// caret.setDot(offset);
512
// }
513
}
514                     }
515                 }
516             }
517         }
518
519         private class GenericGoToDeclarationAction extends GotoDeclarationAction {
520             @Override JavaDoc
521             public boolean gotoDeclaration(JTextComponent JavaDoc target) {
522                 GoToSupport.performGoTo((BaseDocument)target.getDocument(),
523                     target.getCaretPosition());
524
525                 return true;
526             }
527         }
528
529         private class GenericGenerateGoToPopupAction extends NbGenerateGoToPopupAction {
530             public void actionPerformed(ActionEvent JavaDoc evt, JTextComponent JavaDoc target) {
531             }
532
533             private void addAcceleretors(Action JavaDoc a, JMenuItem JavaDoc item, JTextComponent JavaDoc target) {
534                 // Try to get the accelerator
535
Keymap JavaDoc km = target.getKeymap();
536
537                 if (km != null) {
538                     KeyStroke JavaDoc[] keys = km.getKeyStrokesForAction(a);
539
540                     if ((keys != null) && (keys.length > 0)) {
541                         item.setAccelerator(keys[0]);
542                     } else if (a != null) {
543                         KeyStroke JavaDoc ks = (KeyStroke JavaDoc)a.getValue(Action.ACCELERATOR_KEY);
544
545                         if (ks != null) {
546                             item.setAccelerator(ks);
547                         }
548                     }
549                 }
550             }
551
552             private void addAction(JTextComponent JavaDoc target, JMenu JavaDoc menu, Action JavaDoc a) {
553                 if (a != null) {
554                     String JavaDoc actionName = (String JavaDoc)a.getValue(Action.NAME);
555                     JMenuItem JavaDoc item = null;
556
557                     if (a instanceof BaseAction) {
558                         item = ((BaseAction)a).getPopupMenuItem(target);
559                     }
560
561                     if (item == null) {
562                         // gets trimmed text that doesn' contain "go to"
563
String JavaDoc itemText = (String JavaDoc)a.getValue(ExtKit.TRIMMED_TEXT);
564
565                         if (itemText == null) {
566                             itemText = getItemText(target, actionName, a);
567                         }
568
569                         if (itemText != null) {
570                             item = new JMenuItem JavaDoc(itemText);
571                             Mnemonics.setLocalizedText(item, itemText);
572                             item.addActionListener(a);
573                             addAcceleretors(a, item, target);
574                             item.setEnabled(a.isEnabled());
575
576                             Object JavaDoc helpID = a.getValue("helpID"); // NOI18N
577

578                             if ((helpID != null) && (helpID instanceof String JavaDoc)) {
579                                 item.putClientProperty("HelpID", helpID); // NOI18N
580
}
581                         } else {
582                             if (ExtKit.gotoSourceAction.equals(actionName)) {
583                                 item = new JMenuItem JavaDoc(NbBundle.getBundle(GsfEditorKit.class)
584                                                              .getString("goto_source_open_source_not_formatted")); //NOI18N
585
addAcceleretors(a, item, target);
586                                 item.setEnabled(false);
587                             }
588                         }
589                     }
590
591                     if (item != null) {
592                         menu.add(item);
593                     }
594                 }
595             }
596
597             private void addAction(JTextComponent JavaDoc target, JMenu JavaDoc menu, String JavaDoc actionName) {
598                 BaseKit kit = Utilities.getKit(target);
599
600                 if (kit == null) {
601                     return;
602                 }
603
604                 Action JavaDoc a = kit.getActionByName(actionName);
605
606                 if (a != null) {
607                     addAction(target, menu, a);
608                 } else { // action-name is null, add the separator
609
menu.addSeparator();
610                 }
611             }
612
613             private String JavaDoc getItemText(JTextComponent JavaDoc target, String JavaDoc actionName, Action JavaDoc a) {
614                 String JavaDoc itemText;
615
616                 if (a instanceof BaseAction) {
617                     itemText = ((BaseAction)a).getPopupMenuText(target);
618                 } else {
619                     itemText = actionName;
620                 }
621
622                 return itemText;
623             }
624
625             @Override JavaDoc
626             public JMenuItem JavaDoc getPopupMenuItem(final JTextComponent JavaDoc target) {
627                 String JavaDoc menuText =
628                     NbBundle.getBundle(GsfEditorKit.class).getString("generate-goto-popup"); //NOI18N
629
JMenu JavaDoc jm = new JMenu JavaDoc(menuText);
630                 //addAction(target, jm, ExtKit.gotoSourceAction);
631
addAction(target, jm, ExtKit.gotoDeclarationAction);
632
633                 //addAction(target, jm, gotoSuperImplementationAction);
634
//addAction(target, jm, ExtKit.gotoAction);
635
return jm;
636             }
637         }
638     }
639 }
640
Popular Tags