1 19 20 package org.netbeans.core; 21 22 import java.awt.BorderLayout ; 23 import java.beans.PropertyChangeEvent ; 24 import java.beans.PropertyChangeListener ; 25 import java.io.IOException ; 26 import java.io.ObjectInput ; 27 import java.io.ObjectOutput ; 28 import java.io.ObjectStreamException ; 29 import java.io.Serializable ; 30 import java.text.MessageFormat ; 31 import java.util.ArrayList ; 32 import java.util.Arrays ; 33 import java.util.HashMap ; 34 import java.util.Iterator ; 35 import java.util.List ; 36 import java.util.Map ; 37 import java.util.logging.Level ; 38 import java.util.logging.Logger ; 39 import javax.swing.SwingUtilities ; 40 import org.openide.explorer.ExplorerManager; 41 import org.openide.explorer.propertysheet.PropertySheet; 42 import org.openide.nodes.Node; 43 import org.openide.nodes.NodeAdapter; 44 import org.openide.nodes.NodeEvent; 45 import org.openide.nodes.NodeListener; 46 import org.openide.nodes.NodeOp; 47 import org.openide.util.Exceptions; 48 import org.openide.util.HelpCtx; 49 import org.openide.util.NbBundle; 50 import org.openide.util.Mutex; 51 import org.openide.util.Utilities; 52 import org.openide.util.io.NbMarshalledObject; 53 import org.openide.util.io.SafeException; 54 import org.openide.windows.Mode; 55 import org.openide.windows.TopComponent; 56 import org.openide.windows.Workspace; 57 import org.openide.windows.WindowManager; 58 59 62 public final class NbSheet extends TopComponent { 63 64 68 private static final String PROP_LONGER_DISPLAY_NAME = "longerDisplayName"; 70 71 static final long serialVersionUID = 7807519514644165460L; 72 73 74 private static NbSheet sharedSheet; 75 76 transient private final Listener listener; 77 78 transient private final SheetNodesListener snListener; 79 80 boolean global; 81 82 private PropertySheet propertySheet; 83 84 private Node[] nodes = new Node[0]; 85 86 88 public NbSheet () { 89 this (false); 90 } 91 92 94 public NbSheet (boolean global) { 95 this.global = global; 96 this.propertySheet = new PropertySheet (); 97 98 putClientProperty("NamingType", "BothOnlyCompName"); 106 setLayout (new BorderLayout ()); 107 add(propertySheet, BorderLayout.CENTER); 108 109 setIcon (Utilities.loadImage("org/netbeans/core/resources/frames/properties.gif", true)); 111 updateTitle(); 113 putClientProperty("SlidingName", NbBundle.getMessage(NbSheet.class, "CTL_PropertiesWindow")); 116 listener = new Listener (); 118 119 snListener = new SheetNodesListener(); 120 121 getAccessibleContext ().setAccessibleName ( 123 NbBundle.getBundle(NbSheet.class).getString ("ACSN_PropertiesSheet")); 124 getAccessibleContext ().setAccessibleDescription ( 125 NbBundle.getBundle(NbSheet.class).getString ("ACSD_PropertiesSheet")); 126 setActivatedNodes(null); 127 } 128 129 134 public static NbSheet findDefault () { 135 if (sharedSheet == null) { 136 TopComponent tc = WindowManager.getDefault().findTopComponent("properties"); if (tc != null) { 138 if (tc instanceof NbSheet) { 139 sharedSheet = (NbSheet) tc; 140 } else { 141 IllegalStateException exc = new IllegalStateException 143 ("Incorrect settings file. Unexpected class returned." + " Expected:" + NbSheet.class.getName() + " Returned:" + tc.getClass().getName()); Logger.getLogger(NbSheet.class.getName()).log(Level.WARNING, null, exc); 147 NbSheet.getDefault(); 149 } 150 } else { 151 NbSheet.getDefault(); 154 } 155 } 156 return sharedSheet; 157 } 158 159 protected String preferredID () { 160 return "properties"; } 162 163 166 public static NbSheet getDefault () { 167 if (sharedSheet == null) { 168 sharedSheet = new NbSheet(true); 169 } 170 return sharedSheet; 171 } 172 173 175 public int getPersistenceType() { 176 return TopComponent.PERSISTENCE_ALWAYS; 177 } 178 179 public HelpCtx getHelpCtx () { 180 return (global ? org.openide.explorer.ExplorerUtils.getHelpCtx (nodes, new HelpCtx (NbSheet.class)) : null); 182 } 183 184 186 @SuppressWarnings ("deprecation") 187 public void requestFocus () { 188 super.requestFocus(); 189 propertySheet.requestFocus(); 190 } 191 192 194 @SuppressWarnings ("deprecation") 195 public boolean requestFocusInWindow () { 196 super.requestFocusInWindow(); 197 return propertySheet.requestFocusInWindow(); 198 } 199 200 201 @SuppressWarnings ("deprecation") 202 public void open (Workspace workspace) { 203 if (global) { 204 Workspace realWorkspace = (workspace == null) 205 ? WindowManager.getDefault().getCurrentWorkspace() 206 : workspace; 207 Mode tcMode = realWorkspace.findMode(this); 208 if (tcMode == null) { 209 Mode mode = realWorkspace.findMode("properties"); if (mode == null) { 212 mode = realWorkspace.createMode( 213 "properties", NbBundle.getBundle(NbSheet.class).getString("CTL_PropertiesWindow"), 215 null 216 ); 217 } 218 mode.dockInto(this); 219 } 220 } 221 super.open(workspace); 223 224 if(global) { 225 SwingUtilities.invokeLater(listener); 227 } 228 } 229 230 231 private static MessageFormat globalPropertiesFormat = null; 232 private static MessageFormat localPropertiesFormat = null; 233 234 237 protected void updateTitle () { 238 Mode ourMode = WindowManager.getDefault().findMode(this); 240 String nodeTitle = null; 241 242 List <Node> copyNodes = new ArrayList <Node>(Arrays.asList(nodes)); 244 245 Node node = null; 246 247 if (!copyNodes.isEmpty()) { 248 node = copyNodes.get(0); 249 } 250 251 if(node == null) { 252 nodeTitle = ""; } else { 254 nodeTitle = node.getDisplayName(); 255 Object alternativeDisplayName = node.getValue(PROP_LONGER_DISPLAY_NAME); 256 if (alternativeDisplayName instanceof String ) { 257 nodeTitle = (String )alternativeDisplayName; 258 } 259 } 260 Object [] titleParams = new Object [] { 261 Integer.valueOf(copyNodes.size()), 262 nodeTitle 263 }; 264 if ((ourMode != null) && 266 ("properties".equals(ourMode.getName()))) { if (globalPropertiesFormat == null) { 268 globalPropertiesFormat = new MessageFormat (NbBundle.getMessage(NbSheet.class, "CTL_FMT_GlobalProperties")); 269 } 270 setName(globalPropertiesFormat.format(titleParams)); 271 } else { 272 if (localPropertiesFormat == null) { 273 localPropertiesFormat = new MessageFormat (NbBundle.getMessage(NbSheet.class, "CTL_FMT_LocalProperties")); 274 } 275 setName(localPropertiesFormat.format(titleParams)); 276 } 277 setToolTipText(getName()); 278 } 279 280 282 public void setNodes (Node[] nodes) { 283 setNodesWithoutReattaching(nodes); 284 snListener.detach(); 286 snListener.attach(nodes); 287 } 288 289 final Node[] getNodes() { 290 return nodes; 291 } 292 293 294 private void setNodesWithoutReattaching (Node[] nodes) { 295 this.nodes = nodes; 296 propertySheet.setNodes(nodes); 297 SwingUtilities.invokeLater(new Runnable () { 298 public void run() { 299 updateTitle(); 300 } 301 }); 302 } 303 308 309 310 public void writeExternal (ObjectOutput out) 311 throws IOException { 312 super.writeExternal(out); 313 314 if (global) { 315 out.writeObject (null); 317 } else { 318 Node.Handle[] arr = NodeOp.toHandles (nodes); 319 out.writeObject(arr); 320 } 321 322 out.writeBoolean(global); 323 } 324 325 326 public void readExternal (ObjectInput in) 327 throws IOException , ClassNotFoundException { 328 try { 329 super.readExternal(in); 330 } catch (SafeException se) { 331 } 334 Object obj = in.readObject (); 335 336 if (obj instanceof NbMarshalledObject || obj instanceof ExplorerManager) { 337 global = ((Boolean )in.readObject()).booleanValue(); 339 } else { 340 Node[] nodes; 341 342 if (obj == null) { 343 nodes = TopComponent.getRegistry().getActivatedNodes(); 346 } else { 347 Node.Handle[] arr = (Node.Handle[])obj; 349 350 try { 351 nodes = NodeOp.fromHandles (arr); 352 } catch (IOException ex) { 353 Exceptions.attachLocalizedMessage(ex, 354 NbBundle.getBundle(NbSheet.class).getString("EXC_CannotLoadNodes")); 355 Logger.getLogger(NbSheet.class.getName()).log(Level.WARNING, null, ex); 356 nodes = new Node[0]; 357 } 358 } 359 360 global = in.readBoolean (); 361 362 setNodes (nodes); 363 } 364 365 383 } 386 387 388 public Object readResolve () 389 throws ObjectStreamException { 390 if (global) { 391 return getDefault(); 392 } else { 393 if ((nodes == null) || (nodes.length <= 0)) { 394 return null; 395 } 396 } 397 return this; 398 } 399 400 protected Object writeReplace() throws ObjectStreamException { 401 if (global) { 402 return new Replacer(); 403 } else { 404 return super.writeReplace(); 405 } 406 } 407 408 private static final class Replacer implements Serializable { 409 static final long serialVersionUID=-7897067133215740572L; 410 Replacer() {} 411 private Object readResolve() throws ObjectStreamException { 412 return NbSheet.getDefault(); 413 } 414 } 415 416 418 private void updateGlobalListening(boolean listen) { 419 if (global) { 420 if (listen) { 421 TopComponent.getRegistry().addPropertyChangeListener( 422 listener); 423 } else { 424 TopComponent.getRegistry().removePropertyChangeListener (listener); 425 } 426 } 427 } 428 429 protected void componentOpened() { 430 updateGlobalListening (true); 431 } 432 433 protected void componentClosed() { 434 updateGlobalListening (false); 435 } 436 437 protected void componentDeactivated() { 438 super.componentDeactivated(); 439 if (Utilities.isMac()) { 440 propertySheet.firePropertyChange("MACOSX", true, false); 441 } 442 } 443 444 447 private class Listener extends Object implements Runnable , PropertyChangeListener { 448 Listener() {} 449 public void propertyChange (PropertyChangeEvent ev) { 450 if (TopComponent.Registry.PROP_ACTIVATED_NODES.equals( ev.getPropertyName() )) { 451 activate(); 452 } 453 461 } 462 463 public void run() { 464 activate(); 465 } 466 467 public void activate () { 468 Node[] arr = TopComponent.getRegistry ().getActivatedNodes(); 469 setNodes (arr); 470 } 471 472 } 473 476 private class SheetNodesListener extends NodeAdapter implements Runnable { 477 478 479 private HashMap <Node,NodeListener> listenerMap; 480 481 482 private HashMap <Node,PropertyChangeListener > pListenerMap; 483 484 SheetNodesListener() {} 485 486 489 public void nodeDestroyed(NodeEvent ev) { 490 Node destroyedNode = ev.getNode(); 491 NodeListener listener = listenerMap.get(destroyedNode); 492 PropertyChangeListener pListener = pListenerMap.get(destroyedNode); 493 destroyedNode.removeNodeListener(listener); 495 destroyedNode.removePropertyChangeListener(pListener); 496 listenerMap.remove(destroyedNode); 497 pListenerMap.remove(destroyedNode); 498 if (listenerMap.isEmpty() && !global) { 500 Mutex.EVENT.readAccess(new Runnable () { 502 public void run() { 503 close(); 504 } 505 }); 506 } else { 508 setNodesWithoutReattaching( 509 (listenerMap.keySet().toArray(new Node[listenerMap.size()])) 510 ); 511 } 512 } 513 514 public void attach (Node[] nodes) { 515 listenerMap = new HashMap <Node,NodeListener>(nodes.length * 2); 516 pListenerMap = new HashMap <Node,PropertyChangeListener >(nodes.length * 2); 517 NodeListener curListener = null; 518 PropertyChangeListener pListener = null; 519 for (int i = 0; i < nodes.length; i++) { 522 curListener = org.openide.nodes.NodeOp.weakNodeListener (this, nodes[i]); 523 pListener = org.openide.util.WeakListeners.propertyChange(this, nodes[i]); 524 listenerMap.put(nodes[i], curListener); 525 pListenerMap.put(nodes[i], pListener); 526 nodes[i].addNodeListener(curListener); 527 nodes[i].addPropertyChangeListener(pListener); 528 }; 529 } 530 531 public void detach () { 532 if (listenerMap == null) { 533 return; 534 } 535 for (Iterator iter = listenerMap.entrySet().iterator(); iter.hasNext(); ) { 537 Map.Entry curEntry = (Map.Entry )iter.next(); 538 ((Node)curEntry.getKey()).removeNodeListener((NodeListener)curEntry.getValue()); 539 } 540 for (Iterator iter = pListenerMap.entrySet().iterator(); iter.hasNext(); ) { 541 Map.Entry curEntry = (Map.Entry )iter.next(); 542 ((Node)curEntry.getKey()).removePropertyChangeListener((PropertyChangeListener )curEntry.getValue()); 543 } 544 listenerMap = null; 546 pListenerMap = null; 547 } 548 549 public void propertyChange(PropertyChangeEvent pce) { 550 if (Node.PROP_DISPLAY_NAME.equals(pce.getPropertyName())) { 551 SwingUtilities.invokeLater(this); 552 } 553 } 554 555 public void run() { 556 updateTitle(); 557 } 558 559 } 561 } 562 | Popular Tags |