1 19 package org.netbeans.modules.gsf; 20 21 import java.awt.Cursor ; 22 import java.awt.event.ActionEvent ; 23 import java.io.IOException ; 24 import java.util.ArrayList ; 25 import java.util.List ; 26 import javax.swing.Action ; 27 import javax.swing.JEditorPane ; 28 import javax.swing.JEditorPane ; 29 import javax.swing.JMenu ; 30 import javax.swing.JMenuItem ; 31 import javax.swing.KeyStroke ; 32 import javax.swing.text.BadLocationException ; 33 import javax.swing.text.Caret ; 34 import javax.swing.text.Document ; 35 import javax.swing.text.Document ; 36 import javax.swing.text.JTextComponent ; 37 import javax.swing.text.JTextComponent ; 38 import javax.swing.text.Keymap ; 39 import javax.swing.text.Position ; 40 import javax.swing.text.TextAction ; 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 109 public class GsfEditorKitFactory { 110 private final static boolean PRETTY_PRINT_AVAILABLE = Boolean.getBoolean("ruby.prettyprint"); 111 112 public static final String selectNextElementAction = "select-element-next"; public static final String selectPreviousElementAction = "select-element-previous"; 115 Language language; 116 String mimeType; 117 118 public GsfEditorKitFactory(Language language) { 119 assert language != null; 120 this.language = language; 121 this.mimeType = language.getMimeType(); 122 } 123 124 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 mimeType = (String )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 doc) { 148 DataObject od = (DataObject)doc.getProperty(Document.StreamDescriptionProperty); 149 150 return (od != null) ? od.getPrimaryFile() : null; 151 } 152 153 156 private static boolean completionSettingEnabled() { 157 return true; 159 } 160 161 public class GsfEditorKit extends NbEditorKit { 162 String 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 getContentType() { 170 return language.getMimeType(); 171 } 172 173 public Document createDefaultDocument() { 178 Document doc = new GsfDocument(this.getClass(), language); 179 180 doc.putProperty("mimeType", mimeType); 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 { 190 BracketCompletion bracketCompletion = language.getBracketCompletion(); 192 if (bracketCompletion != null) { 193 OffsetRange range = bracketCompletion.findMatching(getDocument(), offset); 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 213 234 CodeTemplateManager.get(doc); 237 } 238 239 @Override 240 public Completion createCompletion(ExtEditorUI extEditorUI) { 241 return null; 243 } 244 245 246 @Override 247 public Formatter createFormatter() { 248 throw new RuntimeException ("Not yet implemented"); 249 250 } 252 253 @Override 254 public void install(JEditorPane c) { 255 super.install(c); 256 } 257 258 @Override 259 public void deinstall(JEditorPane c) { 260 super.deinstall(c); 261 } 262 263 @Override 264 public Object clone() { 265 return new GsfEditorKit(); 266 } 267 268 @Override 269 protected Action [] createActions() { 270 GsfLanguage gsfLanguage = language.getGsfLanguage(); 271 272 ArrayList <Action > actions = new ArrayList (10); 273 274 actions.add(new GsfDefaultKeyTypedAction()); 275 actions.add(new GsfInsertBreakAction()); 276 actions.add(new GsfDeleteCharAction(deletePrevCharAction, false)); 277 278 String 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 [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 307 public boolean isEnabled() { 308 return PRETTY_PRINT_AVAILABLE; 309 } 310 311 public void actionPerformed(ActionEvent evt, JTextComponent 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 Cursor origCursor = target.getCursor(); 327 target.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 328 329 try { 330 Source js = Source.forFileObject(fo); 331 final String [] result = new String [1]; 332 333 js.runUserActionTask(new CancellableTask<CompilationController>() { 334 public void cancel() { 335 } 336 337 public void run(CompilationController controller) 338 throws Exception { 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 ioe) { 350 Exceptions.printStackTrace(ioe); 351 } finally { 352 target.setCursor(origCursor); 353 } 354 } 355 } 356 357 @Override 358 protected Class getShortDescriptionBundleClass() { 359 return PrettyPrintAction.class; 360 } 361 } 362 363 public class GsfDefaultKeyTypedAction extends ExtDefaultKeyTypedAction { 364 @Override 365 protected void insertString(BaseDocument doc, int dotPos, Caret caret, String str, 366 boolean overwrite) throws BadLocationException { 367 if (completionSettingEnabled()) { 368 Language language = getLanguage(doc); 369 370 if (language != null) { 371 BracketCompletion bracketCompletion = language.getBracketCompletion(); 372 373 if (bracketCompletion != null) { 374 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 394 protected void replaceSelection(JTextComponent target, int dotPos, Caret caret, 395 String str, boolean overwrite) throws BadLocationException { 396 char insertedChar = str.charAt(0); 397 Document 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 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 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 453 protected Object beforeBreak(JTextComponent target, BaseDocument doc, Caret 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 (newOffset); 466 } 467 } catch (BadLocationException ble) { 468 Exceptions.printStackTrace(ble); 469 } 470 } 471 } 472 } 473 474 return null; 476 } 477 478 @Override 479 protected void afterBreak(JTextComponent target, BaseDocument doc, Caret caret, 480 Object cookie) { 481 if (completionSettingEnabled()) { 482 if (cookie != null) { 483 if (cookie instanceof Integer ) { 484 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 nm, boolean nextChar) { 495 super(nm, nextChar); 496 } 497 498 @Override 499 protected void charBackspaced(BaseDocument doc, int dotPos, Caret caret, char ch) 500 throws BadLocationException { 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 } 514 } 515 } 516 } 517 } 518 519 private class GenericGoToDeclarationAction extends GotoDeclarationAction { 520 @Override 521 public boolean gotoDeclaration(JTextComponent 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 evt, JTextComponent target) { 531 } 532 533 private void addAcceleretors(Action a, JMenuItem item, JTextComponent target) { 534 Keymap km = target.getKeymap(); 536 537 if (km != null) { 538 KeyStroke [] keys = km.getKeyStrokesForAction(a); 539 540 if ((keys != null) && (keys.length > 0)) { 541 item.setAccelerator(keys[0]); 542 } else if (a != null) { 543 KeyStroke ks = (KeyStroke )a.getValue(Action.ACCELERATOR_KEY); 544 545 if (ks != null) { 546 item.setAccelerator(ks); 547 } 548 } 549 } 550 } 551 552 private void addAction(JTextComponent target, JMenu menu, Action a) { 553 if (a != null) { 554 String actionName = (String )a.getValue(Action.NAME); 555 JMenuItem item = null; 556 557 if (a instanceof BaseAction) { 558 item = ((BaseAction)a).getPopupMenuItem(target); 559 } 560 561 if (item == null) { 562 String itemText = (String )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 (itemText); 571 Mnemonics.setLocalizedText(item, itemText); 572 item.addActionListener(a); 573 addAcceleretors(a, item, target); 574 item.setEnabled(a.isEnabled()); 575 576 Object helpID = a.getValue("helpID"); 578 if ((helpID != null) && (helpID instanceof String )) { 579 item.putClientProperty("HelpID", helpID); } 581 } else { 582 if (ExtKit.gotoSourceAction.equals(actionName)) { 583 item = new JMenuItem (NbBundle.getBundle(GsfEditorKit.class) 584 .getString("goto_source_open_source_not_formatted")); 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 target, JMenu menu, String actionName) { 598 BaseKit kit = Utilities.getKit(target); 599 600 if (kit == null) { 601 return; 602 } 603 604 Action a = kit.getActionByName(actionName); 605 606 if (a != null) { 607 addAction(target, menu, a); 608 } else { menu.addSeparator(); 610 } 611 } 612 613 private String getItemText(JTextComponent target, String actionName, Action a) { 614 String 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 626 public JMenuItem getPopupMenuItem(final JTextComponent target) { 627 String menuText = 628 NbBundle.getBundle(GsfEditorKit.class).getString("generate-goto-popup"); JMenu jm = new JMenu (menuText); 630 addAction(target, jm, ExtKit.gotoDeclarationAction); 632 633 return jm; 636 } 637 } 638 } 639 } 640 | Popular Tags |