1 19 20 package org.openide.loaders; 21 22 23 import java.awt.datatransfer.*; 24 import java.beans.*; 25 import java.io.*; 26 import java.util.*; 27 import javax.swing.Action ; 28 import org.netbeans.modules.openide.loaders.UIException; 29 import org.openide.filesystems.*; 30 import org.openide.nodes.*; 31 import org.openide.util.*; 32 import org.openide.util.actions.SystemAction; 33 import org.openide.util.datatransfer.ExTransferable; 34 35 39 public class DataNode extends AbstractNode { 40 41 42 static final long serialVersionUID = -7882925922830244768L; 43 44 45 private DataObject obj; 46 47 48 private PropL propL; 49 50 51 private static boolean showFileExtensions = true; 52 53 58 public DataNode (DataObject obj, Children ch) { 59 this(obj, ch, null); 60 } 61 62 75 public DataNode (DataObject obj, Children ch, Lookup lookup) { 76 super (ch, lookup); 77 this.obj = obj; 78 79 propL = new PropL (); 80 if (lookup == null) { 81 setCookieSet(CookieSet.createGeneric(propL)); 82 } 83 84 obj.addPropertyChangeListener (org.openide.util.WeakListeners.propertyChange (propL, obj)); 85 86 super.setName (obj.getName ()); 87 updateDisplayName (); 88 } 89 90 private void updateDisplayName () { 91 FileObject prim = obj.getPrimaryFile (); 92 String newDisplayName; 93 94 if (prim.isRoot()) { 95 File f = FileUtil.toFile(prim); 100 if (f == null) { 101 FileObject archiveFile = FileUtil.getArchiveFile(prim); 103 if (archiveFile != null) { 104 f = FileUtil.toFile(archiveFile); 105 } 106 } 107 if (f != null) { 108 newDisplayName = f.getAbsolutePath(); 110 } else { 111 try { 112 newDisplayName = prim.getURL().toExternalForm(); 114 } catch (FileStateInvalidException e) { 115 newDisplayName = "???"; } 118 } 119 } else if (showFileExtensions || obj instanceof DataFolder || obj instanceof DefaultDataObject) { 120 newDisplayName = prim.getNameExt(); 121 } else { 122 newDisplayName = prim.getName (); 123 } 124 125 if (displayFormat != null) 126 setDisplayName (displayFormat.format (new Object [] { newDisplayName })); 127 else 128 setDisplayName (newDisplayName); 129 } 130 131 134 public DataObject getDataObject() { 135 return obj; 136 } 137 138 146 public void setName (String name, boolean rename) { 147 try { 148 if (rename) { 149 obj.rename (name); 150 } 151 152 super.setName (name); 153 updateDisplayName (); 154 } catch (IOException ex) { 155 String msg = null; 156 if ((ex.getLocalizedMessage() == null) || 157 (ex.getLocalizedMessage().equals(ex.getMessage()))) { 158 msg = NbBundle.getMessage (DataNode.class, "MSG_renameError", getName (), name); } else { 160 msg = ex.getLocalizedMessage(); 161 } 162 163 RuntimeException e = new IllegalArgumentException (); 164 UIException.annotateUser(e, null, msg, ex, null); 165 throw e; 166 } 167 } 168 169 173 public void setName (String name) { 174 setName (name, true); 175 } 176 177 178 184 public String getDisplayName () { 185 String s = super.getDisplayName (); 186 187 try { 188 s = obj.getPrimaryFile ().getFileSystem ().getStatus ().annotateName (s, new LazyFilesSet()); 189 } catch (FileStateInvalidException e) { 190 } 192 193 return s; 194 } 195 196 197 207 public String getHtmlDisplayName() { 208 try { 209 FileSystem.Status stat = 210 obj.getPrimaryFile().getFileSystem().getStatus(); 211 if (stat instanceof FileSystem.HtmlStatus) { 212 FileSystem.HtmlStatus hstat = (FileSystem.HtmlStatus) stat; 213 214 String result = hstat.annotateNameHtml ( 215 super.getDisplayName(), new LazyFilesSet()); 216 217 if (!super.getDisplayName().equals(result)) { 219 return result; 220 } 221 } 222 } catch (FileStateInvalidException e) { 223 } 225 return super.getHtmlDisplayName(); 226 } 227 228 235 public java.awt.Image getIcon (int type) { 236 java.awt.Image img = super.getIcon (type); 237 238 try { 239 img = obj.getPrimaryFile ().getFileSystem ().getStatus ().annotateIcon (img, type, new LazyFilesSet()); 240 } catch (FileStateInvalidException e) { 241 } 243 244 return img; 245 } 246 247 254 public java.awt.Image getOpenedIcon (int type) { 255 java.awt.Image img = super.getOpenedIcon(type); 256 257 try { 258 img = obj.getPrimaryFile ().getFileSystem ().getStatus ().annotateIcon (img, type, new LazyFilesSet()); 259 } catch (FileStateInvalidException e) { 260 } 262 263 return img; 264 } 265 266 public HelpCtx getHelpCtx () { 267 return obj.getHelpCtx (); 268 } 269 270 273 public boolean canRename () { 274 return obj.isRenameAllowed (); 275 } 276 277 280 public boolean canDestroy () { 281 return obj.isDeleteAllowed (); 282 } 283 284 286 public void destroy () throws IOException { 287 if (obj.isDeleteAllowed ()) { 288 obj.delete (); 289 } 290 super.destroy (); 291 } 292 293 296 public boolean canCopy () { 297 return obj.isCopyAllowed (); 298 } 299 300 303 public boolean canCut () { 304 return obj.isMoveAllowed (); 305 } 306 307 316 @Deprecated 317 protected SystemAction[] createActions () { 318 return null; 319 } 320 321 325 public Action [] getActions (boolean context) { 326 if (systemActions == null) { 327 systemActions = createActions (); 328 } 329 330 if (systemActions != null) { 331 return systemActions; 332 } 333 334 return obj.getLoader ().getSwingActions (); 335 } 336 337 341 @Deprecated 342 public SystemAction[] getActions () { 343 if (systemActions == null) { 344 systemActions = createActions (); 345 } 346 347 if (systemActions != null) { 348 return systemActions; 349 } 350 351 return obj.getLoader ().getActions (); 352 } 353 354 355 363 public Action getPreferredAction () { 364 if (obj.isTemplate ()) { 365 return null; 366 } else { 367 Action action = super.getPreferredAction (); 368 if (action != null) { 369 return action; 370 } 371 Action [] arr = getActions(false); 372 if (arr != null && arr.length > 0) { 373 return arr[0]; 374 } 375 return null; 376 } 377 } 378 379 392 @Override 393 public <T extends Node.Cookie> T getCookie(Class <T> cl) { 394 if (ownLookup()) { 395 return super.getCookie(cl); 396 } 397 T c = obj.getCookie(cl); 398 if (c != null) { 399 return c; 400 } else { 401 return super.getCookie (cl); 402 } 403 } 404 405 409 protected Sheet createSheet () { 410 Sheet s = Sheet.createDefault (); 411 Sheet.Set ss = s.get (Sheet.PROPERTIES); 412 413 Node.Property p; 414 415 p = createNameProperty (obj); 416 ss.put (p); 417 418 FileObject fo = getDataObject().getPrimaryFile(); 419 if (couldBeTemplate(fo) && fo.canWrite()) { 420 try { 421 p = new PropertySupport.Reflection<Boolean >(obj, Boolean.TYPE, "isTemplate", "setTemplate"); p.setName(DataObject.PROP_TEMPLATE); 423 p.setDisplayName(DataObject.getString("PROP_template")); 424 p.setShortDescription(DataObject.getString("HINT_template")); 425 ss.put(p); 426 } catch (Exception ex) { 427 throw new InternalError (); 428 } 429 } 430 431 if (fo.isData()) { 432 ss.put(new AllFilesProperty()); 433 ss.put(new SizeProperty()); 434 ss.put(new LastModifiedProperty()); 435 } 436 437 return s; 438 } 439 440 private static boolean couldBeTemplate(FileObject fo) { 441 FileSystem fs; 442 try { 443 fs = fo.getFileSystem(); 444 } catch (FileStateInvalidException e) { 445 return false; 446 } 447 return fs.isDefault() && fo.getPath().startsWith("Templates/"); } 449 450 455 private final class AllFilesProperty extends PropertySupport.ReadOnly<String []> { 456 457 public AllFilesProperty() { 458 super(DataObject.PROP_FILES, String [].class, 459 DataObject.getString("PROP_files"), DataObject.getString("HINT_files")); 460 } 461 462 public String [] getValue() { 463 Set<FileObject> files = obj.files(); 464 FileObject primary = obj.getPrimaryFile(); 465 String [] res = new String [files.size()]; 466 assert files.contains(primary); 467 468 int i=1; 469 for (Iterator<FileObject> it = files.iterator(); it.hasNext(); ) { 470 FileObject next = it.next(); 471 res[next == primary ? 0 : i++] = name(next); 472 } 473 474 Arrays.sort(res, 1, res.length); 475 return res; 476 } 477 478 private String name(FileObject fo) { 479 return FileUtil.getFileDisplayName(fo); 480 } 481 482 } 483 484 private final class SizeProperty extends PropertySupport.ReadOnly<Long > { 485 486 public SizeProperty() { 487 super("size", Long.TYPE, DataObject.getString("PROP_size"), DataObject.getString("HINT_size")); 488 } 489 490 public Long getValue() { 491 return new Long (getDataObject().getPrimaryFile().getSize()); 492 } 493 494 } 495 496 private final class LastModifiedProperty extends PropertySupport.ReadOnly<Date> { 497 498 public LastModifiedProperty() { 499 super("lastModified", Date.class, DataObject.getString("PROP_lastModified"), DataObject.getString("HINT_lastModified")); 500 } 501 502 public Date getValue() { 503 return getDataObject().getPrimaryFile().lastModified(); 504 } 505 506 } 507 508 514 public Transferable clipboardCopy () throws IOException { 515 ExTransferable t = ExTransferable.create (super.clipboardCopy ()); 516 t.put (LoaderTransfer.transferable ( 517 getDataObject (), 518 LoaderTransfer.CLIPBOARD_COPY) 519 ); 520 addExternalFileTransferable( t, getDataObject() ); 522 return t; 523 } 524 525 531 public Transferable clipboardCut () throws IOException { 532 ExTransferable t = ExTransferable.create (super.clipboardCut ()); 533 t.put (LoaderTransfer.transferable ( 534 getDataObject (), 535 LoaderTransfer.CLIPBOARD_CUT) 536 ); 537 addExternalFileTransferable( t, getDataObject() ); 539 return t; 540 } 541 542 private void addExternalFileTransferable( ExTransferable t, DataObject d ) { 543 FileObject fo = d.getPrimaryFile(); 544 File file = FileUtil.toFile( fo ); 545 if( null != file ) { 546 final ArrayList<File> list = new ArrayList<File>(1); 548 list.add( file ); 549 t.put( new ExTransferable.Single( DataFlavor.javaFileListFlavor ) { 550 public Object getData() { 551 return list; 552 } 553 }); 554 final String uriList = file.toURI().toString() + "\r\n"; 556 t.put( new ExTransferable.Single( createUriListFlavor() ) { 557 public Object getData() { 558 return uriList; 559 } 560 }); 561 } 562 } 563 564 private DataFlavor createUriListFlavor () { 565 try { 566 return new DataFlavor("text/uri-list;class=java.lang.String"); 567 } catch (ClassNotFoundException ex) { 568 throw new AssertionError (ex); 570 } 571 } 572 573 575 static Node.Property createNameProperty (final DataObject obj) { 576 Node.Property p = new org.openide.nodes.PropertySupport.ReadWrite<String >(org.openide.loaders.DataObject.PROP_NAME, 577 String .class, 578 org.openide.loaders.DataObject.getString("PROP_name"), 579 org.openide.loaders.DataObject.getString("HINT_name")) { 580 581 public String getValue() { 582 return obj.getName(); 583 } 584 585 public void setValue(String val) throws IllegalAccessException , 586 IllegalArgumentException , 587 java.lang.reflect.InvocationTargetException { 588 if (!canWrite()) 589 throw new java.lang.IllegalAccessException (); 590 if (!(val instanceof java.lang.String )) 591 throw new java.lang.IllegalArgumentException (); 592 try { 593 obj.rename((java.lang.String ) val); 594 } 595 catch (java.io.IOException ex) { 596 java.lang.String msg = null; 597 598 if ((ex.getLocalizedMessage() == null) || 599 (ex.getLocalizedMessage().equals(ex.getMessage()))) { 600 msg = org.openide.util.NbBundle.getMessage(org.openide.loaders.DataNode.class, 601 "MSG_renameError", 602 obj.getName(), 603 val); 604 } else { 605 msg = ex.getLocalizedMessage(); 606 } 607 UIException.annotateUser(ex, null, msg, null, null); 608 throw new java.lang.reflect.InvocationTargetException (ex); 609 } 610 } 611 612 public boolean canWrite() { 613 return obj.isRenameAllowed(); 614 } 615 617 public Object getValue(String key) { 618 if ("suppressCustomEditor".equals(key)) { 619 return Boolean.TRUE; 620 } else { 621 return super.getValue(key); 622 } 623 } 624 }; 625 626 return p; 627 } 628 629 631 private void updateFilesInCookieSet(Set<FileObject> obj) { 632 if (ownLookup()) { 633 return; 634 } 635 getCookieSet().assign(FileObject.class, obj.toArray(new FileObject[0])); 636 } 637 638 641 void fireChange(final PropertyChangeEvent ev) { 642 Mutex.EVENT.writeAccess(new Runnable () { 643 public void run() { 644 645 if (DataFolder.PROP_CHILDREN.equals(ev.getPropertyName())) { 646 return; 648 } 649 650 if (DataObject.PROP_PRIMARY_FILE.equals(ev.getPropertyName())) { 651 propL.updateStatusListener(); 652 setName(obj.getName(), false); 653 updateFilesInCookieSet(obj.files()); 654 return; 655 } 656 657 if (DataObject.PROP_FILES.equals(ev.getPropertyName())) { 658 updateFilesInCookieSet(obj.files()); 659 } 660 661 if (DataObject.PROP_NAME.equals(ev.getPropertyName())) { 662 DataNode.super.setName(obj.getName()); 663 updateDisplayName(); 664 } 665 if (DataObject.PROP_COOKIE.equals(ev.getPropertyName())) { 666 fireCookieChange(); 667 } 669 670 if (DataObject.PROP_VALID.equals(ev.getPropertyName())) { 673 Object newVal = ev.getNewValue(); 674 if ((newVal instanceof Boolean ) && (!((Boolean ) newVal).booleanValue())) { 675 fireNodeDestroyed(); 676 } 677 return; 678 } 679 680 681 List transmitProperties = Arrays.asList(new String [] { 682 DataObject.PROP_NAME, DataObject.PROP_FILES, DataObject.PROP_TEMPLATE}); 683 if (transmitProperties.contains(ev.getPropertyName())) { 684 firePropertyChange(ev.getPropertyName(), ev.getOldValue(), ev.getNewValue()); 685 } 686 } 687 }); 688 } 689 690 693 public Node.Handle getHandle () { 694 return new ObjectHandle(obj, obj.isValid() ? (this != obj.getNodeDelegate()) : true); 695 } 696 697 699 final void fireChangeAccess (boolean icon, boolean name) { 700 if (name) { 701 fireDisplayNameChange (null, null); 702 } 703 if (icon) { 704 fireIconChange (); 705 } 706 } 707 708 712 public static boolean getShowFileExtensions () { 713 return showFileExtensions; 714 } 715 716 719 public static void setShowFileExtensions (boolean s) { 720 boolean refresh = ( showFileExtensions != s ); 721 showFileExtensions = s; 722 723 if ( refresh ) { 724 RequestProcessor.getDefault().post(new Runnable () { 726 public void run () { 727 Iterator it = DataObjectPool.getPOOL().getActiveDataObjects(); 728 while ( it.hasNext() ) { 729 DataObject obj = ((DataObjectPool.Item)it.next()).getDataObjectOrNull(); 730 if ( obj != null && obj.getNodeDelegate() instanceof DataNode ) { 731 ((DataNode)obj.getNodeDelegate()).updateDisplayName(); 732 } 733 } 734 } 735 }, 300, Thread.MIN_PRIORITY); 736 } 737 738 } 739 740 private static Class defaultLookup; 741 743 private boolean ownLookup() { 744 if (defaultLookup == null) { 745 try { 746 defaultLookup = Class.forName("org.openide.nodes.NodeLookup", false, Node.class.getClassLoader()); 747 } catch (ClassNotFoundException ex) { 748 Exceptions.printStackTrace(ex); 749 return false; 750 } 751 } 752 return !defaultLookup.isInstance(getLookup()); 753 } 754 755 758 private static RequestProcessor.Task refreshNamesIconsTask = null; 759 760 private static Set<DataNode> refreshNameNodes = null; 761 private static Set<DataNode> refreshIconNodes = null; 762 763 private static boolean refreshNamesIconsRunning = false; 764 private static final Object refreshNameIconLock = "DataNode.refreshNameIconLock"; 766 769 private class PropL extends Object 770 implements PropertyChangeListener, FileStatusListener, CookieSet.Before { 771 772 private FileStatusListener weakL; 773 774 private FileSystem previous; 775 776 public PropL () { 777 updateStatusListener (); 778 } 779 780 public void propertyChange (PropertyChangeEvent ev) { 781 fireChange (ev); 782 } 783 784 786 private void updateStatusListener () { 787 if (previous != null) { 788 previous.removeFileStatusListener (weakL); 789 } 790 try { 791 previous = obj.getPrimaryFile ().getFileSystem (); 792 793 if (weakL == null) { 794 weakL = org.openide.filesystems.FileUtil.weakFileStatusListener (this, null); 795 } 796 797 previous.addFileStatusListener (weakL); 798 } catch (FileStateInvalidException ex) { 799 previous = null; 800 } 801 } 802 803 806 public void annotationChanged (FileStatusEvent ev) { 807 boolean thisChanged = false; 809 Iterator it = obj.files().iterator(); 810 while (it.hasNext()) { 811 FileObject fo = (FileObject)it.next(); 812 if (ev.hasChanged(fo)) { 813 thisChanged = true; 814 break; 815 } 816 } 817 if (thisChanged) { 818 synchronized (refreshNameIconLock) { 820 boolean post = false; 821 if (ev.isNameChange()) { 822 if (refreshNameNodes == null) { 823 refreshNameNodes = new HashSet<DataNode>(); 824 } 825 post |= refreshNameNodes.add(DataNode.this); 826 } 827 if (ev.isIconChange()) { 828 if (refreshIconNodes == null) { 829 refreshIconNodes = new HashSet<DataNode>(); 830 } 831 post |= refreshIconNodes.add(DataNode.this); 832 } 833 if (post && !refreshNamesIconsRunning) { 834 refreshNamesIconsRunning = true; 835 if (refreshNamesIconsTask == null) { 836 refreshNamesIconsTask = RequestProcessor.getDefault().post(new NamesUpdater()); 837 } else { 838 refreshNamesIconsTask.schedule(0); 841 } 842 } 843 } 844 } 845 } 846 847 public void beforeLookup(Class <?> clazz) { 848 if (clazz.isAssignableFrom(FileObject.class)) { 849 updateFilesInCookieSet(obj.files()); 850 } 851 } 852 } 853 854 private static class NamesUpdater implements Runnable { 855 857 public void run() { 858 DataNode[] _refreshNameNodes, _refreshIconNodes; 859 synchronized (refreshNameIconLock) { 860 if (refreshNameNodes != null) { 861 _refreshNameNodes = refreshNameNodes.toArray(new DataNode[refreshNameNodes.size()]); 862 refreshNameNodes.clear(); 863 } else { 864 _refreshNameNodes = new DataNode[0]; 865 } 866 if (refreshIconNodes != null) { 867 _refreshIconNodes = refreshIconNodes.toArray(new DataNode[refreshIconNodes.size()]); 868 refreshIconNodes.clear(); 869 } else { 870 _refreshIconNodes = new DataNode[0]; 871 } 872 refreshNamesIconsRunning = false; 873 } 874 for (int i = 0; i < _refreshNameNodes.length; i++) { 875 _refreshNameNodes[i].fireChangeAccess(false, true); 876 } 877 for (int i = 0; i < _refreshIconNodes.length; i++) { 878 _refreshIconNodes[i].fireChangeAccess(true, false); 879 } 880 } 881 882 } 883 884 885 private static class ObjectHandle implements Node.Handle { 886 private FileObject obj; 887 private boolean clone; 888 889 static final long serialVersionUID =6616060729084681518L; 890 891 892 public ObjectHandle (DataObject obj, boolean clone) { 893 this.obj = obj.getPrimaryFile (); 894 this.clone = clone; 895 } 896 897 public Node getNode () throws IOException { 898 if (obj == null) { 899 throw new IOException("File could not be restored"); } 915 Node n = DataObject.find (obj).getNodeDelegate (); 916 return clone ? n.cloneNode () : n; 917 } 918 } 919 920 923 private class LazyFilesSet implements Set<FileObject> { 924 925 private Set<FileObject> obj_files; 926 927 synchronized private void lazyInitialization () { 928 obj_files = obj.files(); 929 } 930 931 public boolean add(FileObject o) { 932 lazyInitialization(); 933 return obj_files.add(o); 934 } 935 936 public boolean addAll(Collection<? extends FileObject> c) { 937 lazyInitialization(); 938 return obj_files.addAll(c); 939 } 940 941 public void clear() { 942 lazyInitialization(); 943 obj_files.clear(); 944 } 945 946 public boolean contains(Object o) { 947 lazyInitialization(); 948 return obj_files.contains(o); 949 } 950 951 public boolean containsAll(Collection c) { 952 lazyInitialization(); 953 return obj_files.containsAll(c); 954 } 955 956 public boolean isEmpty() { 957 lazyInitialization(); 958 return obj_files.isEmpty(); 959 } 960 961 public Iterator<FileObject> iterator() { 962 return new FilesIterator (); 963 } 964 965 public boolean remove(Object o) { 966 lazyInitialization(); 967 return obj_files.remove(o); 968 } 969 970 public boolean removeAll(Collection c) { 971 lazyInitialization(); 972 return obj_files.removeAll(c); 973 } 974 975 public boolean retainAll(Collection c) { 976 lazyInitialization(); 977 return obj_files.retainAll(c); 978 } 979 980 public int size() { 981 lazyInitialization(); 982 return obj_files.size(); 983 } 984 985 public Object [] toArray() { 986 lazyInitialization(); 987 return obj_files.toArray(); 988 } 989 990 public <FileObject> FileObject[] toArray(FileObject[] a) { 991 lazyInitialization(); 992 return obj_files.toArray(a); 993 } 994 995 public boolean equals(Object obj) { 996 lazyInitialization(); 997 return obj_files.equals(obj); 998 } 999 1000 public String toString() { 1001 lazyInitialization(); 1002 return obj_files.toString(); 1003 } 1004 1005 public int hashCode() { 1006 lazyInitialization(); 1007 return obj_files.hashCode(); 1008 } 1009 1010 1013 private final class FilesIterator implements Iterator<FileObject> { 1014 1016 private boolean first = true; 1017 1018 1021 private Iterator<FileObject> itDelegate = null; 1022 1023 FilesIterator() {} 1024 1025 public boolean hasNext() { 1026 return first ? true : getIteratorDelegate().hasNext(); 1027 } 1028 1029 public FileObject next() { 1030 if (first) { 1031 first = false; 1032 return obj.getPrimaryFile (); 1033 } 1034 else { 1035 return getIteratorDelegate().next(); 1036 } 1037 } 1038 1039 public void remove() { 1040 getIteratorDelegate().remove(); 1041 } 1042 1043 1045 private Iterator<FileObject> getIteratorDelegate() { 1046 if (itDelegate == null) { 1047 lazyInitialization (); 1048 itDelegate = obj_files.iterator (); 1050 itDelegate.next(); 1052 } 1053 return itDelegate; 1054 } 1055 } 1056 } 1057 1058 1059 1060} 1061 | Popular Tags |