1 19 20 package org.netbeans.core.multiview; 21 22 import java.awt.BorderLayout ; 23 import java.awt.event.ActionEvent ; 24 import java.io.IOException ; 25 import java.io.ObjectInput ; 26 import java.io.ObjectOutput ; 27 import java.io.Serializable ; 28 import java.lang.reflect.InvocationHandler ; 29 import java.lang.reflect.InvocationTargetException ; 30 import java.lang.reflect.Method ; 31 import java.lang.reflect.Proxy ; 32 import java.util.*; 33 import java.util.logging.Level ; 34 import java.util.logging.Logger ; 35 import javax.swing.*; 36 import javax.swing.event.ChangeEvent ; 37 import javax.swing.event.ChangeListener ; 38 import javax.swing.undo.CannotRedoException ; 39 import javax.swing.undo.CannotUndoException ; 40 import org.netbeans.core.api.multiview.MultiViewPerspective; 41 import org.netbeans.core.multiview.MultiViewModel.ActionRequestObserverFactory; 42 import org.netbeans.core.multiview.MultiViewModel.ElementSelectionListener; 43 import org.netbeans.core.spi.multiview.CloseOperationHandler; 44 import org.netbeans.core.spi.multiview.CloseOperationState; 45 import org.netbeans.core.spi.multiview.MultiViewDescription; 46 import org.netbeans.core.spi.multiview.MultiViewElement; 47 import org.openide.awt.UndoRedo; 48 import org.openide.text.CloneableEditorSupport.Pane; 49 import org.openide.util.HelpCtx; 50 import org.openide.util.Lookup; 51 import org.openide.util.SharedClassObject; 52 import org.openide.windows.TopComponent; 53 54 61 62 63 public final class MultiViewPeer { 64 65 static final String MULTIVIEW_ID = "MultiView-"; 67 MultiViewModel model; 68 TabsComponent tabs; 69 SelectionListener selListener; 70 CloseOperationHandler closeHandler; 71 transient MultiViewTopComponentLookup lookup; 72 TopComponent peer; 73 private ActionRequestObserverFactory factory; 74 private MultiViewActionMap delegatingMap; 75 private boolean activated = false; 76 private Object editorSettingsListener; 77 private DelegateUndoRedo delegateUndoRedo; 78 79 public MultiViewPeer(TopComponent pr, ActionRequestObserverFactory fact) { 80 selListener = new SelectionListener(); 81 peer = pr; 82 factory = fact; 83 editorSettingsListener = createEditorListener(); 84 delegateUndoRedo = new DelegateUndoRedo(); 85 } 86 87 88 89 90 public void setMultiViewDescriptions(MultiViewDescription[] descriptions, MultiViewDescription defaultDesc) { 91 if (model != null) { 92 model.removeElementSelectionListener(selListener); 93 } 94 model = new MultiViewModel(descriptions, defaultDesc, factory); 95 model.addElementSelectionListener(selListener); 96 tabs.setModel(model); 97 } 98 99 public void setCloseOperationHandler(CloseOperationHandler handler) { 100 closeHandler = handler; 101 } 102 103 void setDeserializedMultiViewDescriptions(MultiViewDescription[] descriptions, 104 MultiViewDescription defaultDesc, Map existingElements) { 105 if (model != null) { 106 model.removeElementSelectionListener(selListener); 107 } 108 model = new MultiViewModel(descriptions, defaultDesc, factory, existingElements); 109 model.addElementSelectionListener(selListener); 110 tabs.setModel(model); 111 } 112 113 116 MultiViewModel getModel() { 117 return model; 118 } 119 120 121 void initComponents() { 122 initActionMap(); 123 peer.setLayout(new BorderLayout ()); 124 tabs = new TabsComponent(isToolbarVisible()); 125 peer.add(tabs); 126 ActionMap map = peer.getActionMap(); 127 Action act = new AccessTogglesAction(); 128 map.put("NextViewAction", new GetRightEditorAction()); map.put("PreviousViewAction", new GetLeftEditorAction()); map.put("accesstoggles", act); InputMap input = peer.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 132 KeyStroke stroke = KeyStroke.getKeyStroke("control F10"); input.put(stroke, "accesstoggles"); input = peer.getInputMap(JComponent.WHEN_FOCUSED); 137 input.put(stroke, "accesstoggles"); 139 peer.putClientProperty("MultiViewBorderHack.topOffset", new Integer (tabs.getPreferredSize().height - 1)); 140 } 141 142 private void initActionMap() { 145 delegatingMap = new MultiViewActionMap(peer, new ActionMap ()); 146 if(peer instanceof TopComponent.Cloneable) { 147 delegatingMap.put("cloneWindow", new javax.swing.AbstractAction () { public void actionPerformed(ActionEvent evt) { 149 TopComponent cloned = ((TopComponent.Cloneable) 150 peer).cloneComponent(); 151 cloned.open(); 152 cloned.requestActive(); 153 } 154 }); 155 } 156 delegatingMap.put("closeWindow", new javax.swing.AbstractAction () { public void actionPerformed(ActionEvent evt) { 158 peer.close(); 159 } 160 }); 161 peer.setActionMap(delegatingMap); 162 } 163 164 void peerComponentClosed() { 165 Iterator it = model.getCreatedElements().iterator(); 166 while (it.hasNext()) { 167 MultiViewElement el = (MultiViewElement)it.next(); 168 model.markAsHidden(el); 169 el.componentClosed(); 170 } 171 172 } 173 174 void peerComponentShowing() { 175 MultiViewElement el = model.getActiveElement(); 176 el.componentShowing(); 177 delegatingMap.setDelegateMap(el.getVisualRepresentation().getActionMap()); 178 ((MultiViewTopComponentLookup)peer.getLookup()).setElementLookup(el.getLookup()); 179 JComponent jc = el.getToolbarRepresentation(); 180 jc.setOpaque(false); 181 tabs.setInnerToolBar(jc); 182 tabs.setToolbarBarVisible(isToolbarVisible()); 183 if (editorSettingsListener != null) { 184 addEditorListener(editorSettingsListener); 185 } 186 } 187 188 void peerComponentHidden() { 189 model.getActiveElement().componentHidden(); 190 if (editorSettingsListener != null) { 191 removeEditorListener(editorSettingsListener); 192 } 193 } 194 195 void peerComponentDeactivated() { 196 activated = false; 197 model.getActiveElement().componentDeactivated(); 198 } 199 200 boolean isActivated() { 201 return activated; 202 } 203 204 void peerComponentActivated() { 205 activated = true; 206 model.getActiveElement().componentActivated(); 207 } 208 209 void peerComponentOpened() { 210 showCurrentElement(true); 211 tabs.setToolbarBarVisible(isToolbarVisible()); 212 } 213 214 boolean requestFocusInWindow() { 215 return model.getActiveElement().getVisualRepresentation().requestFocusInWindow(); 216 } 217 218 void requestFocus() { 219 model.getActiveElement().getVisualRepresentation().requestFocus(); 220 } 221 222 225 void hideElement(MultiViewDescription desc) { 226 if (desc != null) { 227 MultiViewElement el = model.getElementForDescription(desc); 228 el.componentHidden(); 229 } 230 } 231 232 233 void showCurrentElement() { 234 showCurrentElement(false); 235 } 236 237 240 241 private void showCurrentElement(boolean calledFromComponentOpened) { 242 MultiViewElement el = model.getActiveElement(); 243 MultiViewDescription desc = model.getActiveDescription(); 244 245 tabs.switchToCard(el, desc.getDisplayName()); 250 peer.setIcon(desc.getIcon()); 251 if (peer.isOpened() || calledFromComponentOpened) { 254 if (!model.wasShownBefore(el)) { 255 el.componentOpened(); 256 model.markAsShown(el); 257 } 258 } 259 if (!calledFromComponentOpened) { 260 if (peer.isVisible()) { 264 el.componentShowing(); 265 } 266 delegatingMap.setDelegateMap(el.getVisualRepresentation().getActionMap()); 270 ((MultiViewTopComponentLookup)peer.getLookup()).setElementLookup(el.getLookup()); 271 272 if (peer.isVisible()) { 273 tabs.setInnerToolBar(el.getToolbarRepresentation()); 274 tabs.setToolbarBarVisible(isToolbarVisible()); 275 } 276 277 } 278 } 279 280 281 282 286 Action[] peerGetActions(Action[] superActions) { 287 Action[] acts = model.getActiveElement().getActions(); 289 for (int i = 0; i < acts.length; i++) { 290 Action act = acts[i]; 291 for (int j = 0 ; j < superActions.length; j++) { 292 Action superact = superActions[j]; 293 if (superact != null && act != null && superact.getClass().equals(act.getClass())) { 294 acts[i] = superActions[j]; 297 break; 298 } 299 } 300 } 301 return acts; 302 } 303 304 MultiViewHandlerDelegate getMultiViewHandlerDelegate() { 305 return new MVTCHandler(); 307 } 308 309 312 int getPersistenceType() { 313 314 MultiViewDescription[] descs = model.getDescriptions(); 319 int type = TopComponent.PERSISTENCE_NEVER; 320 for (int i = 0; i < descs.length; i++) { 321 if (!(descs[i] instanceof Serializable )) { 322 Logger.getLogger(MultiViewTopComponent.class.getName()).warning( 323 "The MultiviewDescription instance " + descs[i].getClass() + " is not serializable. Cannot persist TopComponent."); 324 type = TopComponent.PERSISTENCE_NEVER; 325 break; 326 } 327 if (descs[i].getPersistenceType() == TopComponent.PERSISTENCE_ALWAYS) { 328 type = descs[i].getPersistenceType(); 329 } 331 if (descs[i].getPersistenceType() == TopComponent.PERSISTENCE_ONLY_OPENED && 332 type != TopComponent.PERSISTENCE_ALWAYS) { 333 type = descs[i].getPersistenceType(); 334 } 336 337 } 338 return type; 339 } 340 341 String preferredID() { 342 StringBuffer retValue = new StringBuffer (MULTIVIEW_ID); 343 MultiViewDescription[] descs = model.getDescriptions(); 344 for (int i = 0; i < descs.length; i++) { 345 retValue.append(descs[i].preferredID()); 346 retValue.append("|"); } 348 return retValue.toString(); 349 } 350 351 352 353 357 void peerWriteExternal (ObjectOutput out) throws IOException { 358 if (closeHandler != null) { 359 if (closeHandler instanceof Serializable ) { 360 out.writeObject(closeHandler); 361 } else { 362 Logger.getAnonymousLogger().info( 364 "The CloseOperationHandler isn not serializable. MultiView component id=" + preferredID()); 365 } 366 } 367 MultiViewDescription[] descs = model.getDescriptions(); 368 MultiViewDescription curr = model.getActiveDescription(); 369 int currIndex = 0; 370 for (int i = 0; i < descs.length; i++) { 371 out.writeObject(descs[i]); 372 if (descs[i].getPersistenceType() != TopComponent.PERSISTENCE_NEVER) { 373 MultiViewElement elem = model.getElementForDescription(descs[i], false); 375 if (elem != null && elem instanceof Serializable ) { 376 out.writeObject(elem); 377 } 378 } 379 if (descs[i] == curr) { 380 currIndex = i; 381 } 382 } 383 out.writeObject(new Integer (currIndex)); 384 385 } 386 387 391 void peerReadExternal (ObjectInput in) throws IOException , ClassNotFoundException { 392 ArrayList descList = new ArrayList(); 393 HashMap map = new HashMap(); 394 int current = 0; 395 CloseOperationHandler close = null; 396 while (true) { 397 Object obj = in.readObject(); 398 if (obj instanceof MultiViewDescription) { 399 descList.add(obj); 400 } 401 else if (obj instanceof MultiViewElement) { 402 map.put(descList.get(descList.size() - 1), obj); 403 } 404 else if (obj instanceof Integer ) { 405 Integer integ = (Integer )obj; 406 current = integ.intValue(); 407 break; 408 } 409 if (obj instanceof CloseOperationHandler) { 410 close = (CloseOperationHandler)obj; 411 } 412 } 413 if (close == null) { 414 close = SpiAccessor.DEFAULT.createDefaultCloseHandler(); 416 } 417 setCloseOperationHandler(close); 418 MultiViewDescription[] descs = new MultiViewDescription[descList.size()]; 420 descs = (MultiViewDescription[])descList.toArray(descs); 421 MultiViewDescription currDesc = descs[current]; 422 setDeserializedMultiViewDescriptions(descs, currDesc, map); 423 } 424 425 426 private Action[] getDefaultTCActions() { 427 if (peer instanceof MultiViewTopComponent) { 429 return ((MultiViewTopComponent)peer).getDefaultTCActions(); 430 } 431 return new Action[0]; 432 } 433 434 435 436 JEditorPane getEditorPane() { 437 if (model != null) { 438 MultiViewElement el = model.getActiveElement(); 439 if (el != null && el.getVisualRepresentation() instanceof Pane) { 440 Pane pane = (Pane)el.getVisualRepresentation(); 441 return pane.getEditorPane(); 442 } 443 } 444 return null; 445 } 446 447 HelpCtx getHelpCtx() { 448 return model.getActiveDescription().getHelpCtx(); 449 } 450 451 458 UndoRedo peerGetUndoRedo() { 459 return delegateUndoRedo; 460 } 461 462 private UndoRedo privateGetUndoRedo() { 463 return model.getActiveElement().getUndoRedo() != null ? model.getActiveElement().getUndoRedo() : UndoRedo.NONE; 464 } 465 466 470 boolean canClose() { 471 Collection col = model.getCreatedElements(); 472 Iterator it = col.iterator(); 473 Collection badOnes = new ArrayList(); 474 while (it.hasNext()) { 475 MultiViewElement el = (MultiViewElement)it.next(); 476 CloseOperationState state = el.canCloseElement(); 477 if (!state.canClose()) { 478 badOnes.add(state); 479 } 480 } 481 if (badOnes.size() > 0) { 482 CloseOperationState[] states = new CloseOperationState[badOnes.size()]; 483 states = (CloseOperationState[])badOnes.toArray(states); 484 return closeHandler.resolveCloseOperation(states); 485 } 486 return true; 487 } 488 489 public void updateName() { 491 if (model != null) { 493 MultiViewElement el = model.getActiveElement(); 494 if (el.getVisualRepresentation() instanceof Pane) { 495 Pane pane = (Pane)el.getVisualRepresentation(); 496 pane.updateName(); 497 peer.setDisplayName(pane.getComponent().getDisplayName()); 498 } 499 } 500 } 502 503 public Lookup getLookup() { 504 if (lookup == null) { 505 lookup = new MultiViewTopComponentLookup(delegatingMap); 506 } 507 return lookup; 508 } 509 510 511 void addEditorListener(Object listener) { 516 try { 517 final ClassLoader loader = (ClassLoader )Lookup.getDefault().lookup(ClassLoader .class); 518 Class settingsClass = Class.forName( 519 "org.netbeans.editor.Settings", false, loader); Class listenerClass = Class.forName( 521 "org.netbeans.editor.SettingsChangeListener", false, loader); Method addSettingsListener = settingsClass.getMethod( 523 "addSettingsChangeListener",new Class [ ] { listenerClass }); addSettingsListener.invoke(settingsClass, new Object [] { listener }); 525 } catch (Throwable t) { 526 t.printStackTrace(); 527 } 528 } 529 530 void removeEditorListener(Object listener) { 531 try { 532 final ClassLoader loader = (ClassLoader )Lookup.getDefault().lookup(ClassLoader .class); 533 Class settingsClass = Class.forName( 534 "org.netbeans.editor.Settings", false, loader); Class listenerClass = Class.forName( 536 "org.netbeans.editor.SettingsChangeListener", false, loader); Method addSettingsListener = settingsClass.getMethod( 538 "removeSettingsChangeListener",new Class [ ] { listenerClass }); addSettingsListener.invoke(settingsClass, new Object [] { listener }); 540 } catch (Throwable t) { 541 t.printStackTrace(); 542 } 543 } 544 545 Object createEditorListener() { 546 try { 547 final ClassLoader loader = (ClassLoader )Lookup.getDefault().lookup(ClassLoader .class); 548 Class listenerClass; 549 try { 550 listenerClass = Class.forName("org.netbeans.editor.SettingsChangeListener", false, loader); } catch (ClassNotFoundException ex) { 552 Logger.getLogger(MultiViewPeer.class.getName()).log(Level.CONFIG, "Disabling interaction with editor/lib", ex); return null; 554 } 555 InvocationHandler ih = new InvocationHandler () { 556 public Object invoke(Object proxy, Method method, Object [] args) { 557 SwingUtilities.invokeLater(new Runnable () { 558 public void run() { 559 tabs.setToolbarBarVisible(isToolbarVisible()); 560 } 561 }); 562 return null; 563 } 564 }; 565 return Proxy.newProxyInstance(loader, 566 new Class [] { listenerClass }, ih); 567 } catch (Throwable t) { 568 Logger.getLogger(MultiViewPeer.class.getName()).log(Level.WARNING, null, t); 569 } 570 return null; 571 } 572 573 boolean isToolbarVisible() { 574 JEditorPane pane = getEditorPane(); 577 if (pane != null) { 578 Object obj = pane.getActionMap().get("toggle-toolbar"); 579 if (obj == null) { 580 return true; 581 } 582 } else { 583 return true; 584 } 585 SharedClassObject option = null; 586 ClassLoader loader = (ClassLoader ) Lookup.getDefault().lookup(ClassLoader .class); 587 if (loader == null) { 588 loader = MultiViewPeer.class.getClassLoader().getSystemClassLoader(); 589 } 590 try { 591 Class editorBaseOption = Class.forName("org.netbeans.modules.editor.options.BaseOptions", true, 592 loader); 593 option = SharedClassObject.findObject(editorBaseOption); 594 } catch (ClassNotFoundException ex) { 595 ex.printStackTrace(); 596 } 597 if (option != null) { 598 try { 599 Method is = option.getClass().getMethod("isToolbarVisible", new Class [0]); 600 Object ret; 601 ret = is.invoke(option, new Object [0]); 602 if (ret instanceof Boolean ) { 603 return ((Boolean )ret).booleanValue(); 604 } 605 } catch (IllegalArgumentException ex) { 606 ex.printStackTrace(); 607 } catch (SecurityException ex) { 608 ex.printStackTrace(); 609 } catch (InvocationTargetException ex) { 610 ex.printStackTrace(); 611 } catch (NoSuchMethodException ex) { 612 ex.printStackTrace(); 613 } catch (IllegalAccessException ex) { 614 ex.printStackTrace(); 615 } 616 } 617 return true; 618 } 619 620 621 public String toString() { 622 return "[model=" + model + "]"; } 624 627 private class SelectionListener implements ElementSelectionListener { 628 629 public void selectionChanged(MultiViewDescription oldOne, MultiViewDescription newOne) { 630 hideElement(oldOne); 631 showCurrentElement(); 632 delegateUndoRedo.updateListeners(model.getElementForDescription(oldOne), 633 model.getElementForDescription(newOne)); 634 } 635 636 public void selectionActivatedByButton() { 637 MultiViewElement elem = model.getActiveElement(); 638 elem.getVisualRepresentation().requestFocus(); 639 elem.componentActivated(); 640 } 641 642 } 643 644 private class MVTCHandler implements MultiViewHandlerDelegate { 645 private MultiViewPerspective[] perspectives = null; 646 647 public MultiViewPerspective[] getDescriptions() { 648 return model.getPerspectives(); 649 } 650 651 public MultiViewPerspective getSelectedDescription() { 652 return model.getSelectedPerspective(); 653 } 654 655 public void requestActive(MultiViewPerspective pers) { 656 MultiViewDescription desc = Accessor.DEFAULT.extractDescription(pers); 657 if (model.getActiveDescription() != desc) { 658 model.getActiveElement().componentDeactivated(); 659 tabs.changeActiveManually(desc); 660 model.getActiveElement().componentActivated(); 661 } 662 } 663 664 public void requestVisible(MultiViewPerspective pers) { 665 MultiViewDescription desc = Accessor.DEFAULT.extractDescription(pers); 666 tabs.changeVisibleManually(desc); 667 } 668 669 674 675 } 676 677 678 private class AccessTogglesAction extends AbstractAction { 679 680 AccessTogglesAction() { 681 putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("control F10")); } 684 685 public void actionPerformed(ActionEvent e) { 686 tabs.requestFocusForSelectedButton(); 687 688 } 689 } 690 691 private class DelegateUndoRedo implements UndoRedo { 692 693 private List listeners = new ArrayList(); 694 695 public boolean canUndo() { 696 return privateGetUndoRedo().canUndo(); 697 } 698 699 public boolean canRedo() { 700 return privateGetUndoRedo().canRedo(); 701 } 702 703 public void undo() throws CannotUndoException { 704 privateGetUndoRedo().undo(); 705 } 706 707 public void redo() throws CannotRedoException { 708 privateGetUndoRedo().redo(); 709 } 710 711 public void addChangeListener(ChangeListener l) { 712 listeners.add(l); 713 privateGetUndoRedo().addChangeListener(l); 714 } 715 716 public void removeChangeListener(ChangeListener l) { 717 listeners.remove(l); 718 privateGetUndoRedo().removeChangeListener(l); 719 } 720 721 public String getUndoPresentationName() { 722 return privateGetUndoRedo().getUndoPresentationName(); 723 } 724 725 public String getRedoPresentationName() { 726 return privateGetUndoRedo().getRedoPresentationName(); 727 } 728 729 private void fireElementChange() { 730 Iterator it = new ArrayList(listeners).iterator(); 731 while (it.hasNext()) { 732 ChangeListener elem = (ChangeListener ) it.next(); 733 ChangeEvent event = new ChangeEvent (this); 734 elem.stateChanged(event); 735 } 736 737 } 738 739 void updateListeners(MultiViewElement old, MultiViewElement fresh) { 740 Iterator it = listeners.iterator(); 741 while (it.hasNext()) { 742 ChangeListener elem = (ChangeListener ) it.next(); 743 if (old.getUndoRedo() != null) { 744 old.getUndoRedo().removeChangeListener(elem); 745 } 746 if (fresh.getUndoRedo() != null) { 747 fresh.getUndoRedo().addChangeListener(elem); 748 } 749 } 750 fireElementChange(); 751 } 752 753 } 754 755 } | Popular Tags |