1 19 20 package org.netbeans.modules.apisupport.project.layers; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.io.ByteArrayInputStream ; 25 import java.io.ByteArrayOutputStream ; 26 import java.io.FileNotFoundException ; 27 import java.io.FilterOutputStream ; 28 import java.io.IOException ; 29 import java.io.InputStream ; 30 import java.io.NotSerializableException ; 31 import java.io.ObjectOutputStream ; 32 import java.io.OutputStream ; 33 import java.io.UnsupportedEncodingException ; 34 import java.net.MalformedURLException ; 35 import java.net.URI ; 36 import java.net.URL ; 37 import java.net.URLConnection ; 38 import java.util.ArrayList ; 39 import java.util.Arrays ; 40 import java.util.Collection ; 41 import java.util.Collections ; 42 import java.util.Comparator ; 43 import java.util.Date ; 44 import java.util.Enumeration ; 45 import java.util.HashSet ; 46 import java.util.Iterator ; 47 import java.util.LinkedHashMap ; 48 import java.util.LinkedHashSet ; 49 import java.util.Map ; 50 import java.util.Set ; 51 import java.util.SortedSet ; 52 import java.util.StringTokenizer ; 53 import java.util.TreeSet ; 54 import org.netbeans.api.java.classpath.ClassPath; 55 import org.netbeans.modules.apisupport.project.Util; 56 import org.netbeans.modules.xml.tax.cookies.TreeEditorCookie; 57 import org.netbeans.tax.InvalidArgumentException; 58 import org.netbeans.tax.ReadOnlyException; 59 import org.netbeans.tax.TreeAttribute; 60 import org.netbeans.tax.TreeCDATASection; 61 import org.netbeans.tax.TreeChild; 62 import org.netbeans.tax.TreeDocumentRoot; 63 import org.netbeans.tax.TreeElement; 64 import org.netbeans.tax.TreeException; 65 import org.netbeans.tax.TreeObjectList; 66 import org.netbeans.tax.TreeParentNode; 67 import org.netbeans.tax.TreeText; 68 import org.openide.ErrorManager; 69 import org.openide.filesystems.AbstractFileSystem; 70 import org.openide.filesystems.FileAttributeEvent; 71 import org.openide.filesystems.FileChangeListener; 72 import org.openide.filesystems.FileEvent; 73 import org.openide.filesystems.FileLock; 74 import org.openide.filesystems.FileObject; 75 import org.openide.filesystems.FileRenameEvent; 76 import org.openide.filesystems.FileUtil; 77 import org.openide.filesystems.URLMapper; 78 import org.openide.util.Enumerations; 79 import org.openide.util.NbCollections; 80 import org.openide.util.TopologicalSortException; 81 import org.openide.util.Utilities; 82 import org.openide.util.WeakListeners; 83 84 96 final class WritableXMLFileSystem extends AbstractFileSystem 97 implements AbstractFileSystem.Attr, 98 AbstractFileSystem.Change, 99 AbstractFileSystem.Info, 100 AbstractFileSystem.List, 101 FileChangeListener, 103 PropertyChangeListener { 104 105 private final TreeEditorCookie cookie; 106 private TreeDocumentRoot doc; private URL location; 108 private String suffix; private final FileChangeListener fileChangeListener; 110 private ClassPath classpath; 112 public WritableXMLFileSystem(URL location, TreeEditorCookie cookie, ClassPath classpath) { 113 this.attr = this; 114 this.change = this; 115 this.info = this; 116 this.list = this; 117 this.cookie = cookie; 119 try { 120 doc = cookie.openDocumentRoot(); 121 } catch (TreeException e) { 122 Util.err.notify(ErrorManager.INFORMATIONAL, e); 123 } catch (IOException e) { 124 Util.err.notify(ErrorManager.INFORMATIONAL, e); 125 } 126 fileChangeListener = FileUtil.weakFileChangeListener(this, null); 127 cookie.addPropertyChangeListener(WeakListeners.propertyChange(this, cookie)); 128 setLocation(location); 129 setClasspath(classpath); 130 } 131 132 private void writeObject(ObjectOutputStream out) throws IOException { 133 throw new NotSerializableException ("WritableXMLFileSystem is not persistent"); } 135 136 private void setLocation(URL location) { 137 String u = location.toExternalForm(); 138 if (u.endsWith("/")) { throw new IllegalArgumentException (u); 140 } 141 this.location = location; 142 } 143 144 private void setClasspath(ClassPath classpath) { 145 this.classpath = classpath; 146 } 147 148 public String getDisplayName() { 149 FileObject fo = URLMapper.findFileObject(location); 150 if (fo != null) { 151 return FileUtil.getFileDisplayName(fo); 152 } else { 153 return location.toExternalForm(); 154 } 155 } 156 157 public boolean isReadOnly() { 158 return false; 159 } 160 161 private TreeElement getRootElement() { 162 if (doc == null) { 163 return null; 164 } 165 Iterator it; 166 it = doc.getChildNodes().iterator(); 167 while (it.hasNext()) { 168 Object next = it.next(); 169 if (next instanceof TreeElement) { 170 return (TreeElement) next; 171 } 172 } 173 return null; 174 } 175 176 179 private TreeElement findElement(String name) { 180 return findElementIn(getRootElement(), name); 181 } 182 183 private static TreeElement findElementIn(TreeElement el, String name) { 184 if (el == null) return null; 185 if (name.equals("")) { return el; 187 } else { 188 int idx = name.indexOf((char) '/'); 189 String nextName, remainder; 190 if (idx == -1) { 191 nextName = name; 192 remainder = ""; } else { 194 nextName = name.substring(0, idx); 195 remainder = name.substring(idx + 1); 196 } 197 TreeElement subel = null; 198 Iterator it = el.getChildNodes(TreeElement.class).iterator(); 199 while (it.hasNext()) { 200 TreeElement e = (TreeElement) it.next(); 201 if (e.getLocalName().equals("file") || e.getLocalName().equals("folder")) { TreeAttribute attr = e.getAttribute("name"); if (attr != null && attr.getValue().equals(nextName)) { 205 subel = e; 206 break; 207 } 208 } 209 } 210 return findElementIn(subel, remainder); 211 } 212 } 213 214 public boolean folder(String name) { 215 TreeElement el = findElement(name); 216 if (el == null) { 217 return false; 219 } 220 boolean res = el.getLocalName().equals("folder"); return res; 223 } 224 225 228 public String [] children(String f) { 229 TreeElement el = findElement(f); 230 if (el == null) { 231 return new String [] {}; 233 } 234 Iterator it = el.getChildNodes(TreeElement.class).iterator(); 235 ArrayList kids = new ArrayList (); Set allNames = new HashSet (); while (it.hasNext()) { 238 TreeElement sub = (TreeElement) it.next(); 239 if (sub.getLocalName().equals("file") || sub.getLocalName().equals("folder")) { TreeAttribute attr = sub.getAttribute("name"); if (attr == null) { 243 continue; 244 } 245 String name = attr.getValue(); if (allNames.add(name)) { 247 kids.add(name); 248 261 } 262 } 263 } 264 return (String []) kids.toArray(new String [kids.size()]); 266 } 267 268 269 private byte[] getContentsOf(final String name) throws FileNotFoundException { 270 TreeElement el = findElement(name); 271 if (el == null) throw new FileNotFoundException (name); 272 TreeAttribute attr = el.getAttribute("url"); if (attr != null) { 274 try { 275 URL [] u = LayerUtils.currentify(new URL (location, attr.getValue()), suffix, classpath); 276 URLConnection conn = u[0].openConnection(); 277 conn.connect(); 278 InputStream is = conn.getInputStream(); 279 byte[] buf = new byte[conn.getContentLength()]; 280 if (is.read(buf) != buf.length) throw new IOException ("wrong content length"); FileObject fo = URLMapper.findFileObject(u[0]); 283 if (fo != null) { 284 fo.removeFileChangeListener(fileChangeListener); 285 fo.addFileChangeListener(fileChangeListener); 286 } 287 return buf; 288 } catch (IOException ioe) { 289 throw new FileNotFoundException (ioe.getMessage()); 290 } 291 } else { 292 StringBuffer buf = new StringBuffer (); 293 Iterator it = el.getChildNodes().iterator(); 294 while (it.hasNext()) { 295 Object o = it.next(); 296 if (o instanceof TreeCDATASection) { 297 buf.append(((TreeCDATASection) o).getData()); 298 } else if (o instanceof TreeText) { 299 buf.append(((TreeText) o).getData().trim()); 300 } 301 } 302 try { 303 return buf.toString().getBytes("UTF-8"); } catch (UnsupportedEncodingException uee) { 306 throw new FileNotFoundException (uee.getMessage()); 307 } 308 } 309 } 310 311 314 public InputStream inputStream(String name) throws FileNotFoundException { 315 return new ByteArrayInputStream (getContentsOf(name)); 316 } 317 318 public OutputStream outputStream(final String name) throws IOException { 319 final TreeElement el = findElement(name); 320 if (el == null) { 321 throw new FileNotFoundException (name); 322 } 323 TreeAttribute attr = el.getAttribute("url"); if (attr != null) { 325 String u = attr.getValue(); 326 if (URI.create(u).isAbsolute()) { 327 throw new IOException (name); 329 } 330 FileObject external = URLMapper.findFileObject(new URL (location, u)); 332 if (external == null) { 333 throw new FileNotFoundException (name); 334 } 335 final FileLock lock = external.lock(); 336 return new FilterOutputStream (external.getOutputStream(lock)) { 337 public void close() throws IOException { 338 super.close(); 339 lock.releaseLock(); 340 } 341 }; 342 } 343 return new ByteArrayOutputStream () { 345 public void close() throws IOException { 346 super.close(); 347 byte[] contents = toByteArray(); 348 365 FileObject parent = findLayerParent(); 366 String externalName = LayerUtils.findGeneratedName(parent, name); 367 assert externalName.indexOf('/') == -1 : externalName; 368 FileObject externalFile = parent.createData(externalName); 369 FileLock lock = externalFile.lock(); 370 try { 371 OutputStream os = externalFile.getOutputStream(lock); 372 try { 373 os.write(contents); 374 } finally { 375 os.close(); 376 } 377 } finally { 378 lock.releaseLock(); 379 } 380 externalFile.addFileChangeListener(fileChangeListener); 381 try { 382 el.addAttribute("url", externalName); } catch (ReadOnlyException e) { 384 throw (IOException ) new IOException (e.toString()).initCause(e); 385 } catch (InvalidArgumentException e) { 386 assert false : e; 387 } 388 } 389 }; 390 } 391 private FileObject findLayerParent() throws IOException { 392 String loc = location.toExternalForm(); 393 int slash = loc.lastIndexOf('/'); 394 assert slash != -1 : loc; 395 FileObject parent = URLMapper.findFileObject(new URL (loc.substring(0, slash + 1))); 396 if (parent == null) { 397 throw new IOException (loc); 398 } 399 return parent; 400 } 401 402 private void createFileOrFolder(String name, boolean folder) throws IOException { 403 String parentName, baseName; 404 int idx = name.lastIndexOf('/'); 405 if (idx == -1) { 406 parentName = ""; baseName = name; 408 } else { 409 parentName = name.substring(0, idx); 410 baseName = name.substring(idx + 1); 411 } 412 TreeElement el = findElement(parentName); 413 if (el == null) { 414 throw new FileNotFoundException (parentName); 415 } 416 try { 417 TreeElement nue = new TreeElement(folder ? "folder" : "file", true); nue.addAttribute("name", baseName); appendWithIndent(el, nue); 420 } catch (InvalidArgumentException e) { 421 assert false : e; 422 } catch (ReadOnlyException e) { 423 throw (IOException ) new IOException (e.toString()).initCause(e); 424 } 425 } 426 427 public void createFolder(String name) throws IOException { 428 createFileOrFolder(name, true); 429 } 430 431 public void createData(String name) throws IOException { 432 createFileOrFolder(name, false); 433 } 434 435 public void delete(String name) throws IOException { 436 TreeElement el = findElement(name); 437 if (el == null) { 438 throw new FileNotFoundException (name); 439 } 440 TreeAttribute externalName = el.getAttribute("url"); if (externalName != null && !URI.create(externalName.getValue()).isAbsolute()) { 442 FileObject externalFile = URLMapper.findFileObject(new URL (location, externalName.getValue())); 444 if (externalFile != null) { 445 externalFile.removeFileChangeListener(fileChangeListener); 446 externalFile.delete(); 447 } 448 } 449 try { 450 deleteWithIndent((TreeChild) el); 451 } catch (ReadOnlyException e) { 452 throw (IOException ) new IOException (e.toString()).initCause(e); 453 } 454 } 455 456 public void rename(String oldName, String newName) throws IOException { 457 TreeElement el = findElement(oldName); 458 if (el == null) { 459 throw new FileNotFoundException (oldName); 460 } 461 int idx = newName.lastIndexOf('/') + 1; 462 if (idx != oldName.lastIndexOf('/') + 1 || !oldName.substring(0, idx).equals(newName.substring(0, idx))) { 463 throw new IOException ("Cannot rename to a different dir: " + oldName + " -> " + newName); } 465 String newBaseName = newName.substring(idx); 466 assert newBaseName.indexOf('/') == -1; 467 assert newBaseName.length() > 0; 468 try { 469 el.getAttribute("name").setValue(newBaseName); } catch (ReadOnlyException e) { 471 throw (IOException ) new IOException (e.toString()).initCause(e); 472 } catch (InvalidArgumentException e) { 473 assert false : e; 474 } 475 } 476 477 547 548 public Enumeration attributes(String name) { 549 TreeElement el = findElement(name); 550 if (el == null) { 551 return Enumerations.empty(); 552 } 553 java.util.List <String > l = new ArrayList (10); 554 Iterator it = el.getChildNodes(TreeElement.class).iterator(); 555 while (it.hasNext()) { 556 TreeElement sub = (TreeElement) it.next(); 557 if (sub.getLocalName().equals("attr")) { TreeAttribute attr = sub.getAttribute("name"); if (attr == null) { 560 continue; 562 } 563 l.add(attr.getValue()); 564 } 565 } 566 return Collections.enumeration(l); 567 } 568 569 public Object readAttribute(String name, String attrName) { 570 if (attrName.equals("WritableXMLFileSystem.cp")) { return classpath; 573 } 574 if (attrName.equals("WritableXMLFileSystem.location")) { return location; 577 } 578 if (attrName.equals("DataFolder.Index.reorderable")) { return Boolean.TRUE; 580 } 581 TreeElement el = findElement(name); 582 if (el == null) { 583 return null; 584 } 585 boolean literal = false; 586 if (attrName.startsWith("literal:")) { attrName = attrName.substring("literal:".length()); literal = true; 589 } 590 Iterator it = el.getChildNodes(TreeElement.class).iterator(); 591 while (it.hasNext()) { 592 TreeElement sub = (TreeElement) it.next(); 593 if (!sub.getLocalName().equals("attr")) { continue; 595 } 596 TreeAttribute attr = sub.getAttribute("name"); if (attr == null) { 598 continue; 600 } 601 if (!attrName.equals(attr.getValue())) { 602 continue; 603 } 604 try { 605 if ((attr = sub.getAttribute("stringvalue")) != null) { String inStr = attr.getValue(); 608 StringBuffer outStr = new StringBuffer (inStr.length()); 609 for (int j = 0; j < inStr.length(); j++) { 610 char ch = inStr.charAt(j); 611 if (ch == '\\' && inStr.charAt(j + 1) == 'u' && j + 5 < inStr.length()) { 612 String hex = inStr.substring(j + 2, j + 6); 613 try { 614 outStr.append((char) Integer.parseInt(hex, 16)); 615 j += 5; 616 } catch (NumberFormatException e) { 617 outStr.append(ch); 619 } 620 } else { 621 outStr.append(ch); 622 } 623 } 624 return outStr.toString(); 625 } else if ((attr = sub.getAttribute("boolvalue")) != null) { return Boolean.valueOf(attr.getValue()); 627 } else if ((attr = sub.getAttribute("urlvalue")) != null) { return new URL (attr.getValue()); 629 } else if ((attr = sub.getAttribute("newvalue")) != null) { String clazz = attr.getValue(); 631 if (literal) { 632 return "new:" + clazz; } } else if ((attr = sub.getAttribute("methodvalue")) != null) { String clazz = attr.getValue(); 636 if (literal) { 637 return "method:" + clazz; } } 640 } catch (Exception e) { 641 return null; 644 } 645 } 647 return null; 648 779 } 780 781 private final Set orderAbsorbers = new HashSet (); public void writeAttribute(String name, String attrName, Object v) throws IOException { 783 if (v != null && v.getClass().getName().equals("org.openide.filesystems.MultiFileObject$VoidValue")) { v = null; 787 } 788 if (v == null && attrName.indexOf('/') != -1) { 789 String mebbeOrder = name + '/' + attrName; if (orderAbsorbers.remove(mebbeOrder)) { 791 return; } 794 v = Boolean.FALSE; 796 } 797 if (name.indexOf('/') == -1) { 798 Iterator it = orderAbsorbers.iterator(); 800 while (it.hasNext()) { 801 String n = (String ) it.next(); 802 if (n.startsWith(name + '/')) { 803 it.remove(); 804 } 805 } 806 } 807 if (attrName.equals("OpenIDE-Folder-Order") && (v instanceof String )) { java.util.List <String > order = Collections.list(NbCollections.checkedEnumerationByFilter(new StringTokenizer ((String ) v, "/"), String .class, true)); if (!order.isEmpty()) { 812 Set <String > myOwn = new HashSet (Arrays.asList(children(name))); 816 Iterator it = order.iterator(); 817 String prev = (String ) it.next(); 818 while (it.hasNext()) { 819 String next = (String ) it.next(); 820 if (myOwn.contains(prev) || myOwn.contains(next)) { 821 writeAttribute(name, prev + '/' + next, Boolean.TRUE); } 823 prev = next; 824 } 825 } 826 for (int i = 0; i < order.size() - 1; i++) { 829 for (int j = i + 1; j < order.size(); j++) { 830 orderAbsorbers.add(name + '/' + (String ) order.get(i) + '/' + (String ) order.get(j)); 831 } 832 } 833 return; 835 } 836 TreeElement el = findElement(name); 837 if (el == null) { 838 throw new FileNotFoundException (name); 839 } 840 TreeChild existingAttr = null; 842 Iterator it = el.getChildNodes(TreeElement.class).iterator(); 843 while (it.hasNext()) { 844 TreeElement sub = (TreeElement) it.next(); 845 if (sub.getLocalName().equals("attr")) { TreeAttribute attr = sub.getAttribute("name"); if (attr == null) { 848 continue; 850 } 851 if (attr.getValue().equals(attrName)) { 852 existingAttr = sub; 853 break; 854 } 855 } 856 } 857 TreeElement attr; 858 try { 859 attr = new TreeElement("attr", true); attr.addAttribute("name", attrName); if (v instanceof String ) { 862 String inStr = (String ) v; 863 String newValueMagic = "newvalue:"; String methodValueMagic = "methodvalue:"; if (inStr.startsWith(newValueMagic)) { 866 attr.addAttribute("newvalue", inStr.substring(newValueMagic.length())); } else if (inStr.startsWith(methodValueMagic)) { 869 attr.addAttribute("methodvalue", inStr.substring(methodValueMagic.length())); } else { 872 StringBuffer outStr = new StringBuffer (); 875 for (int i = 0; i < inStr.length(); i++) { 876 char c = inStr.charAt(i); 877 if (Character.isISOControl(c) || c == '&' || c == '<' || c == '>' || c == '"' || c == '\'') { 878 outStr.append(encodeChar(c)); 879 } else { 880 outStr.append(c); 881 } 882 } 883 attr.addAttribute("stringvalue", outStr.toString()); } 885 } else if (v instanceof URL ) { 886 attr.addAttribute("urlvalue", ((URL ) v).toExternalForm()); } else if (v instanceof Boolean ) { 888 attr.addAttribute("boolvalue", v.toString()); } else if (v instanceof Character ) { 890 attr.addAttribute("charvalue", v.toString()); } else if (v instanceof Integer ) { 892 attr.addAttribute("intvalue", v.toString()); } else if (v != null) { 894 throw new UnsupportedOperationException ("XXX: " + v); } 896 if (v != null && existingAttr == null) { 897 appendWithIndent(el, attr); 898 } else if (v != null) { 899 ((TreeParentNode) el).replaceChild(existingAttr, attr); 900 } else if (existingAttr != null) { 901 deleteWithIndent(existingAttr); 902 } 903 } catch (InvalidArgumentException e) { 904 throw new AssertionError (e); 905 } catch (ReadOnlyException e) { 906 throw (IOException ) new IOException (e.toString()).initCause(e); 907 } 908 997 } 998 999 1000 private static String encodeChar(char ch) { 1001 String encChar = Integer.toString((int) ch, 16); 1002 return "\\u" + "0000".substring(0, "0000".length() - encChar.length()).concat(encChar); } 1004 1005 public void renameAttributes(String oldName, String newName) { 1006 } 1008 1009 public void deleteAttributes(String name) { 1010 } 1012 1013 public boolean readOnly(String name) { 1014 return false; 1015 } 1016 1017 public String mimeType(String name) { 1018 return null; } 1020 1021 public long size(String name) { 1022 try { 1023 return getContentsOf(name).length; 1024 } catch (FileNotFoundException fnfe) { 1025 return 0; 1026 } 1027 } 1028 1029 public void markUnimportant(String name) { 1030 } 1032 1033 public Date lastModified(String name) { 1034 final TreeElement el = findElement(name); 1035 if (el == null) { 1036 return new Date (0L); 1037 } 1038 TreeAttribute attr = el.getAttribute("url"); if (attr == null) { 1040 return new Date (0L); 1041 } 1042 String u = attr.getValue(); 1043 if (URI.create(u).isAbsolute()) { 1044 return new Date (0L); 1045 } 1046 FileObject external; 1047 try { 1048 external = URLMapper.findFileObject(new URL (location, u)); 1049 } catch (MalformedURLException e) { 1050 assert false : e; 1051 return new Date (0L); 1052 } 1053 if (external == null) { 1054 return new Date (0L); 1055 } 1056 return external.lastModified(); 1057 } 1058 1059 1061 public void lock(String name) throws IOException { 1062 } 1066 1067 public void unlock(String name) { 1068 } 1070 1071 private static final int INDENT_STEP = 4; 1073 1077 private static void appendWithIndent(TreeElement parent, TreeChild child) throws ReadOnlyException { 1078 TreeParentNode doc = parent; 1079 int depth = -2; while (doc != null) { 1081 doc = ((TreeChild) doc).getParentNode(); 1082 depth++; 1083 } 1084 TreeChild position = insertBefore(parent, child); 1085 try { 1086 if (position != null) { 1087 parent.insertBefore(child, position); 1088 parent.insertBefore(new TreeText("\n" + spaces((depth + 1) * INDENT_STEP)), position); } else { 1090 if ( parent.hasChildNodes()) { 1091 parent.appendChild(new TreeText(spaces(INDENT_STEP))); 1092 } else { 1093 parent.appendChild(new TreeText("\n" + spaces((depth + 1) * INDENT_STEP))); } 1095 parent.appendChild(child); 1096 parent.appendChild(new TreeText("\n" + spaces(depth * INDENT_STEP))); } 1098 parent.normalize(); 1099 TreeElement childe = (TreeElement) child; 1100 if (childe.getQName().equals("attr") && childe.getAttribute("name").getValue().indexOf('/') != -1) { resort(parent); 1103 } 1104 } catch (InvalidArgumentException e) { 1105 assert false : e; 1106 } 1107 } 1108 1116 private static TreeChild insertBefore(TreeElement parent, TreeChild child) throws ReadOnlyException { 1117 if (!(child instanceof TreeElement)) { 1118 return null; } 1120 TreeElement childe = (TreeElement) child; 1121 if (childe.getQName().equals("file") || childe.getQName().equals("folder")) { String name = childe.getAttribute("name").getValue(); Iterator it = parent.getChildNodes(TreeElement.class).iterator(); 1124 while (it.hasNext()) { 1125 TreeElement kid = (TreeElement) it.next(); 1126 if (kid.getQName().equals("file") || kid.getQName().equals("folder")) { TreeAttribute attr = kid.getAttribute("name"); if (attr != null) { String kidname = attr.getValue(); 1130 if (kidname.compareTo(name) > 0) { 1131 return kid; 1132 } 1133 } 1134 } 1135 } 1136 return null; 1137 } else if (childe.getQName().equals("attr")) { String name = childe.getAttribute("name").getValue(); int slash = name.indexOf('/'); 1140 if (slash == -1) { 1141 Iterator it = parent.getChildNodes(TreeElement.class).iterator(); 1143 while (it.hasNext()) { 1144 TreeElement kid = (TreeElement) it.next(); 1145 if (kid.getQName().equals("file") || kid.getQName().equals("folder")) { return kid; 1147 } else if (kid.getQName().equals("attr")) { TreeAttribute attr = kid.getAttribute("name"); if (attr != null) { 1150 String kidname = attr.getValue(); 1151 if (kidname.compareTo(name) > 0) { 1152 return kid; 1153 } 1154 } 1155 } else { 1156 throw new AssertionError ("Weird child: " + kid.getQName()); 1157 } 1158 } 1159 return null; 1160 } else { 1161 return null; 1163 1193 } 1194 } else { 1195 throw new AssertionError ("Weird child: " + childe.getQName()); 1196 } 1197 } 1198 1207 private static void resort(TreeElement parent) throws ReadOnlyException { 1208 class Item { 1209 public TreeElement child; 1210 boolean isAttr() { 1211 return child.getQName().equals("attr"); } 1213 String getName() { 1214 TreeAttribute attr = child.getAttribute("name"); return attr != null ? attr.getValue() : ""; 1216 } 1217 boolean isOrderingAttr() { 1218 return isAttr() && getName().indexOf('/') != -1; 1219 } 1220 String getFormer() { 1221 String n = getName(); 1222 return n.substring(0, n.indexOf('/')); 1223 } 1224 String getLatter() { 1225 String n = getName(); 1226 return n.substring(n.indexOf('/') + 1); 1227 } 1228 } 1229 Set <Item> items = new LinkedHashSet (); 1230 SortedSet <Integer > indices = new TreeSet (); 1231 for (int i = 0; i < parent.getChildrenNumber(); i++) { 1232 TreeChild child = (TreeChild) parent.getChildNodes().get(i); 1233 if (child instanceof TreeElement) { 1234 Item item = new Item(); 1235 item.child = (TreeElement) child; 1236 items.add(item); 1237 indices.add(new Integer (i)); 1238 } 1239 } 1240 Map <Item,Collection <Item>> edges = new LinkedHashMap (); 1241 Map <String ,Item> filesAndFolders = new LinkedHashMap (); 1242 Map <String ,Item> attrs = new LinkedHashMap (); 1243 Set <String > orderedFilesAndFolders = new LinkedHashSet (); 1244 Iterator it = items.iterator(); 1245 while (it.hasNext()) { 1246 Item item = (Item) it.next(); 1247 String name = item.getName(); 1248 if (item.isAttr()) { 1249 attrs.put(name, item); 1250 if (item.isOrderingAttr()) { 1251 orderedFilesAndFolders.add(item.getFormer()); 1252 orderedFilesAndFolders.add(item.getLatter()); 1253 } 1254 } else { 1255 filesAndFolders.put(name, item); 1256 } 1257 } 1258 class NameComparator implements Comparator { 1259 public int compare(Object o1, Object o2) { 1260 Item i1 = (Item) o1; 1261 Item i2 = (Item) o2; 1262 return i1.getName().compareTo(i2.getName()); 1263 } 1264 } 1265 Set <Item> sortedAttrs = new TreeSet (new NameComparator()); 1266 Set <Item> sortedFilesAndFolders = new TreeSet (new NameComparator()); 1267 Set <Item> orderableItems = new LinkedHashSet (); 1268 it = items.iterator(); 1269 while (it.hasNext()) { 1270 Item item = (Item) it.next(); 1271 String name = item.getName(); 1272 if (item.isAttr()) { 1273 if (item.isOrderingAttr()) { 1274 Item former = (Item) filesAndFolders.get(item.getFormer()); 1275 if (former != null) { 1276 Set <Item> formerConstraints = (Set ) edges.get(former); 1277 if (formerConstraints == null) { 1278 formerConstraints = new LinkedHashSet (); 1279 edges.put(former, formerConstraints); 1280 } 1281 formerConstraints.add(item); 1282 } 1283 Item latter = (Item) filesAndFolders.get(item.getLatter()); 1284 if (latter != null) { 1285 Set <Item> constraints = new LinkedHashSet (); 1286 constraints.add(latter); 1287 edges.put(item, constraints); 1288 } 1289 orderableItems.add(item); 1290 } else { 1291 sortedAttrs.add(item); 1292 } 1293 } else { 1294 if (orderedFilesAndFolders.contains(name)) { 1295 orderableItems.add(item); 1296 } else { 1297 sortedFilesAndFolders.add(item); 1298 } 1299 } 1300 } 1301 java.util.List <Item> orderedItems; 1302 try { 1303 orderedItems = Utilities.topologicalSort(orderableItems, edges); 1304 } catch (TopologicalSortException e) { 1305 return; 1307 } 1308 it = items.iterator(); 1309 while (it.hasNext()) { 1310 Item item = (Item) it.next(); 1311 parent.removeChild(item.child); 1312 } 1313 java.util.List <Item> allOrderedItems = new ArrayList (sortedAttrs); 1314 allOrderedItems.addAll(orderedItems); 1315 allOrderedItems.addAll(sortedFilesAndFolders); 1316 assert new HashSet (allOrderedItems).equals(items); 1317 it = allOrderedItems.iterator(); 1318 Iterator indexIt = indices.iterator(); 1319 while (it.hasNext()) { 1320 Item item = (Item) it.next(); 1321 int index = ((Integer ) indexIt.next()).intValue(); 1322 parent.insertChildAt(item.child, index); 1323 } 1324 } 1325 private static String spaces(int size) { 1326 char[] chars = new char[size]; 1327 for (int i = 0; i < size; i++) { 1328 chars[i] = ' '; 1329 } 1330 return new String (chars); 1331 } 1332 1335 private static void deleteWithIndent(TreeChild child) throws ReadOnlyException { 1336 TreeChild next = child.getNextSibling(); 1337 if (next instanceof TreeText && ((TreeText) next).getData().matches("(\r|\n|\r\n)[ \t]+")) { next.removeFromContext(); 1340 } else { 1341 TreeChild previous = child.getPreviousSibling(); 1342 if (previous instanceof TreeText && ((TreeText) previous).getData().matches("(\r|\n|\r\n)[ \t]+")) { previous.removeFromContext(); 1344 } else { 1345 } 1347 } 1348 TreeElement parent = (TreeElement) child.getParentNode(); 1349 TreeObjectList list = parent.getChildNodes(); 1350 boolean kill = true; 1351 Iterator it = list.iterator(); 1352 while (it.hasNext()) { 1353 Object o = it.next(); 1354 if (o == child) { 1355 continue; 1356 } 1357 if (!(o instanceof TreeText)) { 1358 kill = false; 1359 break; 1360 } 1361 if (((TreeText) o).getData().trim().length() > 0) { 1362 kill = false; 1363 break; 1364 } 1365 } 1366 if (kill) { 1367 try { 1368 if (((TreeChild) parent).getParentNode() instanceof TreeDocumentRoot) { 1370 it = list.iterator(); 1371 while (it.hasNext()) { 1372 ((TreeChild) it.next()).removeFromContext(); 1373 } 1374 parent.appendChild(new TreeText("\n")); } else { 1376 TreeElement parent2 = new TreeElement(parent.getQName(), true); 1379 TreeAttribute attr = parent.getAttribute("name"); if (attr != null) { 1381 parent2.addAttribute("name", attr.getValue()); } 1383 TreeParentNode grandparent = ((TreeChild) parent).getParentNode(); 1384 grandparent.replaceChild(parent, parent2); 1386 parent = parent2; } 1388 } catch (InvalidArgumentException e) { 1389 assert false : e; 1390 } 1391 } 1392 child.removeFromContext(); 1393 parent.normalize(); 1394 } 1395 1396 public void fileDeleted(FileEvent fe) { 1402 someFileChange(); 1403 } 1404 public void fileFolderCreated(FileEvent fe) { 1405 } 1407 public void fileDataCreated(FileEvent fe) { 1408 } 1410 public void fileAttributeChanged(FileAttributeEvent fe) { 1411 } 1413 public void fileRenamed(FileRenameEvent fe) { 1414 someFileChange(); 1415 } 1416 public void fileChanged(FileEvent fe) { 1417 someFileChange(); 1418 } 1419 private void someFileChange() { 1420 refreshResource("", true); 1422 } 1423 1424 public void propertyChange(PropertyChangeEvent evt) { 1425 if (!evt.getPropertyName().equals(TreeEditorCookie.PROP_DOCUMENT_ROOT)) { 1426 return; 1427 } 1428 if (cookie.getStatus() == TreeEditorCookie.STATUS_OK || cookie.getStatus() == TreeEditorCookie.STATUS_NOT) { 1429 try { 1431 doc = cookie.openDocumentRoot(); 1432 1436 Enumeration <? extends FileObject> e = existingFileObjects(getRoot()); 1437 while (e.hasMoreElements()) { 1438 FileObject fo = (FileObject) e.nextElement(); 1439 refreshResource(fo.getPath(), true); 1441 } 1442 } catch (TreeException e) { 1445 Util.err.notify(ErrorManager.INFORMATIONAL, e); 1446 } catch (IOException e) { 1447 Util.err.notify(ErrorManager.INFORMATIONAL, e); 1448 } 1449 } 1450 } 1451 1452} 1453 | Popular Tags |