1 19 20 package org.netbeans.modules.editor; 21 22 import java.awt.BorderLayout ; 23 import java.awt.Component ; 24 import java.awt.Dimension ; 25 import java.awt.event.ActionEvent ; 26 import java.awt.event.FocusAdapter ; 27 import java.awt.event.FocusEvent ; 28 import java.awt.event.FocusListener ; 29 import java.beans.PropertyChangeEvent ; 30 import java.beans.PropertyChangeListener ; 31 import java.util.Collection ; 32 import java.util.HashMap ; 33 import java.util.Iterator ; 34 import java.util.Map ; 35 import javax.swing.Action ; 36 import javax.swing.BorderFactory ; 37 import javax.swing.event.ChangeListener ; 38 import javax.swing.text.AttributeSet ; 39 import javax.swing.text.Document ; 40 import javax.swing.text.JTextComponent ; 41 import org.netbeans.api.editor.mimelookup.MimeLookup; 42 import org.netbeans.api.editor.settings.FontColorSettings; 43 import org.netbeans.editor.BaseKit; 44 import org.netbeans.editor.Coloring; 45 import org.netbeans.editor.EditorUI; 46 import org.netbeans.editor.Settings; 47 import org.netbeans.editor.Utilities; 48 import org.netbeans.editor.ext.ExtEditorUI; 49 import org.netbeans.editor.ext.ExtKit; 50 import org.netbeans.modules.editor.options.AllOptionsFolder; 51 import org.openide.filesystems.FileObject; 52 import org.openide.loaders.DataObject; 53 import org.openide.util.LookupEvent; 54 import org.openide.util.LookupListener; 55 import org.openide.util.RequestProcessor; 56 import org.openide.util.WeakListeners; 57 import org.openide.util.actions.ActionPerformer; 58 import org.openide.util.actions.SystemAction; 59 import org.openide.util.actions.CallbackSystemAction; 60 import org.openide.windows.TopComponent; 61 import javax.swing.JComponent ; 62 import javax.swing.JPanel ; 63 import javax.swing.JScrollPane ; 64 import javax.swing.JToolBar ; 65 import javax.swing.border.Border ; 66 import org.netbeans.api.editor.mimelookup.MimePath; 67 import org.netbeans.modules.editor.impl.CustomizableSideBar; 68 import org.netbeans.modules.editor.impl.CustomizableSideBar.SideBarPosition; 69 import org.openide.text.CloneableEditorSupport; 70 import org.openide.util.ContextAwareAction; 71 import org.openide.util.Lookup; 72 73 79 80 public class NbEditorUI extends ExtEditorUI { 81 82 private FocusListener focusL; 83 84 private boolean attached = false; 85 private ChangeListener listener; 86 private FontColorSettings fontColorSettings; 87 private LookupListener weakLookupListener; 88 private Lookup.Result result; 89 private LookupListener lookupListener; 90 91 private static final Map mime2Coloring = new HashMap (5); 92 93 97 protected SystemActionUpdater createSystemActionUpdater( 98 String editorActionName, boolean updatePerformer, boolean syncEnabling) { 99 return new SystemActionUpdater(editorActionName, updatePerformer, syncEnabling); 100 } 101 102 public NbEditorUI() { 103 focusL = new FocusAdapter () { 104 public void focusGained(FocusEvent evt) { 105 Document doc = getDocument(); 107 if (doc != null) { 108 DataObject dob = NbEditorUtilities.getDataObject(doc); 109 if (dob != null) { 110 final FileObject fo = dob.getPrimaryFile(); 111 if (fo != null) { 112 RequestProcessor.getDefault().post(new Runnable () { 114 public void run() { 115 fo.refresh(); 116 } 117 }); 118 } 119 } 120 } 121 } 122 }; 123 124 } 125 126 127 private static Lookup getContextLookup(java.awt.Component component){ 128 Lookup lookup = null; 129 for (java.awt.Component c = component; c != null; c = c.getParent()) { 130 if (c instanceof Lookup.Provider) { 131 lookup = ((Lookup.Provider)c).getLookup (); 132 if (lookup != null) { 133 break; 134 } 135 } 136 } 137 return lookup; 138 } 139 140 protected void attachSystemActionPerformer(String editorActionName){ 141 new NbEditorUI.SystemActionPerformer(editorActionName); 142 } 143 144 private String getDocumentContentType(){ 145 JTextComponent c = getComponent(); 146 if (c == null){ 147 return null; 148 } 149 Document doc = c.getDocument(); 150 String mimeType = (String ) doc.getProperty("mimeType"); if (mimeType == null){ 152 return null; 153 } 154 return mimeType; 155 } 156 157 private FontColorSettings getFontColorSettings(){ 158 synchronized (Settings.class){ 159 if (fontColorSettings == null){ 160 final String mimeType = getDocumentContentType(); 161 if (mimeType == null){ 162 return null; 163 } 164 Lookup lookup = MimeLookup.getLookup(MimePath.parse(mimeType)); 165 result = lookup.lookup(new Lookup.Template(FontColorSettings.class)); 166 Collection inst = result.allInstances(); 167 lookupListener = new MyLookupListener(mimeType); 168 weakLookupListener = (LookupListener) WeakListeners.create( 169 LookupListener.class, lookupListener, result); 170 171 result.addLookupListener(weakLookupListener); 172 if (inst.size() > 0){ 173 fontColorSettings = (FontColorSettings)inst.iterator().next(); 174 } 175 } 176 } 177 return fontColorSettings; 178 } 179 180 181 protected Map createColoringMap(){ 182 FontColorSettings fcs = getFontColorSettings(); 183 String mimeType = getDocumentContentType(); 184 if (fcs == null || mimeType == null){ 185 return super.createColoringMap(); 186 } 187 synchronized (Settings.class){ 188 Map cm = (Map )mime2Coloring.get(mimeType); 189 if (cm != null){ 190 return cm; 191 } 192 cm = new HashMap (); 193 cm.putAll(super.createColoringMap()); 194 195 for(Iterator it = cm.keySet().iterator(); it.hasNext(); ) { 196 197 Object nameObj = it.next(); 198 if (!(nameObj instanceof String )) { 199 continue; 200 } 201 202 String name = (String ) nameObj; 203 204 AttributeSet as = fcs.getTokenFontColors(name); 205 if (as == null){ 206 as = fcs.getFontColors(name); 207 if (as == null){ 208 continue; 209 } 210 } 211 212 cm.put(name, Coloring.fromAttributeSet(as)); 213 } 214 215 mime2Coloring.put(mimeType, cm); 216 return cm; 217 } 218 } 219 220 protected void installUI(JTextComponent c) { 221 super.installUI(c); 222 223 if (!attached){ 224 attachSystemActionPerformer(ExtKit.findAction); 225 attachSystemActionPerformer(ExtKit.replaceAction); 226 attachSystemActionPerformer(ExtKit.gotoAction); 227 attachSystemActionPerformer(ExtKit.showPopupMenuAction); 228 229 233 attached = true; 234 } 235 236 c.addFocusListener(focusL); 237 } 238 239 240 protected void uninstallUI(JTextComponent c) { 241 super.uninstallUI(c); 242 243 c.removeFocusListener(focusL); 244 } 245 246 protected JComponent createExtComponent() { 247 248 final JTextComponent component = getComponent(); 249 251 final JComponent ec = new JPanel (new BorderLayout ()); 253 ec.putClientProperty(JTextComponent .class, component); 254 255 final JScrollPane scroller = new JScrollPane (component); 257 258 scroller.getViewport().setMinimumSize(new Dimension (4,4)); 259 260 Border empty = BorderFactory.createEmptyBorder(); 262 scroller.setBorder(empty); 266 scroller.setViewportBorder(empty); 267 268 String mimeType = NbEditorUtilities.getMimeType(component); 269 270 Map sideBars = CustomizableSideBar.createSideBars(component); 271 if (listener == null){ 272 listener = new ChangeListener (){ 273 public void stateChanged(javax.swing.event.ChangeEvent e) { 274 if (Utilities.getEditorUI(component) == null) { 275 return; } 277 Map newMap = CustomizableSideBar.createSideBars(component); 278 processSideBars(newMap, scroller, ec); 279 ec.revalidate(); 280 ec.repaint(); 281 282 } 283 }; 284 CustomizableSideBar.addChangeListener(mimeType, listener); 285 } 286 287 processSideBars(sideBars, scroller, ec); 288 289 initGlyphCorner(scroller); 290 291 ec.add(scroller); 292 return ec; 293 } 294 295 296 public boolean isLineNumberEnabled() { 297 return AllOptionsFolder.getDefault().getLineNumberVisible(); 298 } 299 300 public void setLineNumberEnabled(boolean lineNumberEnabled) { 301 AllOptionsFolder.getDefault().setLineNumberVisible(lineNumberEnabled); 302 } 303 304 private void processSideBars(Map sideBars, JScrollPane scroller, JComponent ec){ 305 ec.removeAll(); 306 scroller.setRowHeader(null); 307 scroller.setColumnHeaderView(null); 308 for (Iterator entries = sideBars.entrySet().iterator(); entries.hasNext(); ) { 309 Map.Entry entry = (Map.Entry ) entries.next(); 310 SideBarPosition position = (SideBarPosition) entry.getKey(); 311 JComponent sideBar = (JComponent ) entry.getValue(); 312 313 if (position.isScrollable()) { 314 if (position.getPosition() == SideBarPosition.WEST) { 315 scroller.setRowHeaderView(sideBar); 316 } else { 317 if (position.getPosition() == SideBarPosition.NORTH) { 318 scroller.setColumnHeaderView(sideBar); 319 } else { 320 throw new IllegalArgumentException ("Unsupported side bar position, scrollable = true, position=" + position.getBorderLayoutPosition()); } 322 } 323 } else { 324 ec.add(sideBar, position.getBorderLayoutPosition()); 325 } 326 } 327 ec.add(scroller); 328 } 329 330 protected JToolBar createToolBarComponent() { 331 return new NbEditorToolBar(getComponent()); 332 } 333 334 private class SystemActionPerformer implements PropertyChangeListener { 335 336 private String editorActionName; 337 338 private Action editorAction; 339 340 private Action systemAction; 341 342 343 SystemActionPerformer(String editorActionName) { 344 this.editorActionName = editorActionName; 345 346 synchronized (NbEditorUI.this.getComponentLock()) { 347 JTextComponent component = getComponent(); 349 if (component != null) { 350 propertyChange(new PropertyChangeEvent (NbEditorUI.this, 351 EditorUI.COMPONENT_PROPERTY, null, component)); 352 } 353 354 NbEditorUI.this.addPropertyChangeListener(this); 355 } 356 } 357 358 private void attachSystemActionPerformer(JTextComponent c){ 359 if (c == null) return; 360 361 Action editorAction = getEditorAction(c); 362 if (editorAction == null) return; 363 364 Action globalSystemAction = getSystemAction(c); 365 if (globalSystemAction == null) return; 366 367 if (globalSystemAction instanceof CallbackSystemAction){ 368 Object key = ((CallbackSystemAction)globalSystemAction).getActionMapKey(); 369 c.getActionMap ().put (key, editorAction); 370 } 371 } 372 373 private void detachSystemActionPerformer(JTextComponent c){ 374 if (c == null) return; 375 376 Action editorAction = getEditorAction(c); 377 if (editorAction == null) return; 378 379 Action globalSystemAction = getSystemAction(c); 380 if (globalSystemAction == null) return; 381 382 if (globalSystemAction instanceof CallbackSystemAction){ 383 Object key = ((CallbackSystemAction)globalSystemAction).getActionMapKey(); 384 Object ea = c.getActionMap ().get (key); 385 if (editorAction.equals(ea)){ 386 c.getActionMap ().remove(key); 387 } 388 } 389 390 } 391 392 393 public synchronized void propertyChange(PropertyChangeEvent evt) { 394 String propName = evt.getPropertyName(); 395 396 if (EditorUI.COMPONENT_PROPERTY.equals(propName)) { 397 JTextComponent component = (JTextComponent )evt.getNewValue(); 398 399 if (component != null) { component.addPropertyChangeListener(this); 401 attachSystemActionPerformer(component); 402 } else { component = (JTextComponent )evt.getOldValue(); 404 component.removePropertyChangeListener(this); 405 detachSystemActionPerformer(component); 406 } 407 } 408 } 409 410 private synchronized Action getEditorAction(JTextComponent component) { 411 if (editorAction == null) { 412 BaseKit kit = Utilities.getKit(component); 413 if (kit != null) { 414 editorAction = kit.getActionByName(editorActionName); 415 } 416 } 417 return editorAction; 418 } 419 420 private Action getSystemAction(JTextComponent c) { 421 if (systemAction == null) { 422 Action ea = getEditorAction(c); 423 if (ea != null) { 424 String saClassName = (String )ea.getValue(NbEditorKit.SYSTEM_ACTION_CLASS_NAME_PROPERTY); 425 if (saClassName != null) { 426 Class saClass; 427 try { 428 saClass = Class.forName(saClassName); 429 } catch (Throwable t) { 430 saClass = null; 431 } 432 433 if (saClass != null) { 434 systemAction = SystemAction.get(saClass); 435 if (systemAction instanceof ContextAwareAction){ 436 Lookup lookup = getContextLookup(c); 437 if (lookup!=null){ 438 systemAction = ((ContextAwareAction)systemAction).createContextAwareInstance(lookup); 439 } 440 } 441 442 } 443 } 444 } 445 } 446 return systemAction; 447 } 448 449 } 450 451 452 456 public final class SystemActionUpdater 457 implements PropertyChangeListener , ActionPerformer { 458 459 private String editorActionName; 460 461 private boolean updatePerformer; 462 463 private boolean syncEnabling; 464 465 private Action editorAction; 466 467 private Action systemAction; 468 469 private PropertyChangeListener enabledPropertySyncL; 470 471 private boolean listeningOnTCRegistry; 472 473 474 SystemActionUpdater(String editorActionName, boolean updatePerformer, 475 boolean syncEnabling) { 476 this.editorActionName = editorActionName; 477 this.updatePerformer = updatePerformer; 478 this.syncEnabling = syncEnabling; 479 480 synchronized (NbEditorUI.this.getComponentLock()) { 481 JTextComponent component = getComponent(); 483 if (component != null) { 484 propertyChange(new PropertyChangeEvent (NbEditorUI.this, 485 EditorUI.COMPONENT_PROPERTY, null, component)); 486 } 487 488 NbEditorUI.this.addPropertyChangeListener(this); 489 } 490 } 491 492 public void editorActivated() { 493 Action ea = getEditorAction(); 494 Action sa = getSystemAction(); 495 if (ea != null && sa != null) { 496 if (updatePerformer) { 497 if (ea.isEnabled() && sa instanceof CallbackSystemAction) { 498 ((CallbackSystemAction)sa).setActionPerformer(this); 499 } 500 } 501 502 if (syncEnabling) { 503 if (enabledPropertySyncL == null) { 504 enabledPropertySyncL = new EnabledPropertySyncListener(sa); 505 } 506 ea.addPropertyChangeListener(enabledPropertySyncL); 507 } 508 } 509 } 510 511 public void editorDeactivated() { 512 Action ea = getEditorAction(); 513 Action sa = getSystemAction(); 514 if (ea != null && sa != null) { 515 522 523 if (syncEnabling && enabledPropertySyncL != null) { 524 ea.removePropertyChangeListener(enabledPropertySyncL); 525 } 526 } 527 } 528 529 private void reset() { 530 if (enabledPropertySyncL != null) { 531 editorAction.removePropertyChangeListener(enabledPropertySyncL); 532 } 533 534 543 544 editorAction = null; 545 systemAction = null; 546 enabledPropertySyncL = null; 547 } 548 549 550 public void performAction(SystemAction action) { 551 JTextComponent component = getComponent(); 552 Action ea = getEditorAction(); 553 if (component != null && ea != null) { 554 ea.actionPerformed(new ActionEvent (component, 0, "")); } 556 } 557 558 private void startTCRegistryListening() { 559 if (!listeningOnTCRegistry) { 560 listeningOnTCRegistry = true; 561 TopComponent.getRegistry().addPropertyChangeListener(this); 562 } 563 } 564 565 private void stopTCRegistryListening() { 566 if (listeningOnTCRegistry) { 567 listeningOnTCRegistry = false; 568 TopComponent.getRegistry().removePropertyChangeListener(this); 569 } 570 } 571 572 public synchronized void propertyChange(PropertyChangeEvent evt) { 573 String propName = evt.getPropertyName(); 574 575 if (TopComponent.Registry.PROP_ACTIVATED.equals (propName)) { 576 TopComponent activated = (TopComponent)evt.getNewValue(); 577 578 if(activated instanceof CloneableEditorSupport.Pane) 579 editorActivated(); 580 else 581 editorDeactivated(); 582 } else if (EditorUI.COMPONENT_PROPERTY.equals(propName)) { 583 JTextComponent component = (JTextComponent )evt.getNewValue(); 584 585 if (component != null) { component.addPropertyChangeListener(this); 587 if (component.isDisplayable()) { 588 startTCRegistryListening(); 589 } 590 591 } else { component = (JTextComponent )evt.getOldValue(); 593 component.removePropertyChangeListener(this); 594 stopTCRegistryListening(); 595 } 596 597 reset(); 598 599 } else if ("editorKit".equals(propName)) { reset(); 601 602 } else if ("ancestor".equals(propName)) { if (((Component )evt.getSource()).isDisplayable()) { startTCRegistryListening(); 605 } else { stopTCRegistryListening(); 607 } 608 } 609 } 610 611 private synchronized Action getEditorAction() { 612 if (editorAction == null) { 613 BaseKit kit = Utilities.getKit(getComponent()); 614 if (kit != null) { 615 editorAction = kit.getActionByName(editorActionName); 616 } 617 } 618 return editorAction; 619 } 620 621 private Action getSystemAction() { 622 if (systemAction == null) { 623 Action ea = getEditorAction(); 624 if (ea != null) { 625 String saClassName = (String )ea.getValue(NbEditorKit.SYSTEM_ACTION_CLASS_NAME_PROPERTY); 626 if (saClassName != null) { 627 Class saClass; 628 try { 629 saClass = Class.forName(saClassName); 630 } catch (Throwable t) { 631 saClass = null; 632 } 633 634 if (saClass != null) { 635 systemAction = SystemAction.get(saClass); 636 } 637 } 638 } 639 } 640 return systemAction; 641 } 642 643 protected void finalize() throws Throwable { 644 reset(); 645 } 646 647 } 648 649 653 static class EnabledPropertySyncListener implements PropertyChangeListener { 654 655 Action action; 656 657 EnabledPropertySyncListener(Action actionToBeSynced) { 658 this.action = actionToBeSynced; 659 } 660 661 public void propertyChange(PropertyChangeEvent evt) { 662 if ("enabled".equals(evt.getPropertyName())) { action.setEnabled(((Boolean )evt.getNewValue()).booleanValue()); 664 } 665 } 666 667 } 668 669 public Map getColoringMap() { 670 return createColoringMap(); 671 } 672 673 private class MyLookupListener implements LookupListener { 674 675 private String mimeType; 676 677 public MyLookupListener(String mimeType) { 678 super(); 679 this.mimeType = mimeType; 680 } 681 682 public void resultChanged(LookupEvent ev) { 683 synchronized (Settings.class){ 684 mime2Coloring.remove(mimeType); 685 Lookup.Result result = ((Lookup.Result)ev.getSource()); 686 Collection newInstances = result.allInstances(); 688 if (newInstances.size() > 0){ 689 fontColorSettings = (FontColorSettings)newInstances.iterator().next(); 690 } 691 } 692 settingsChangeImpl(null); 693 } 694 } 695 696 } 697 | Popular Tags |