1 19 20 package org.netbeans.modules.java.codegen; 21 22 import java.util.*; 23 import javax.swing.text.Position ; 24 25 import org.openide.src.*; 26 import org.openide.text.*; 27 28 import org.netbeans.modules.java.bridge.Binding; 29 30 35 class ContainerSupport implements TextBinding.Container, ContainerImpl { 36 38 TreeSet children; 39 40 ElementBinding parent; 41 42 SourceText source; 43 44 47 boolean separateMembers; 48 49 private static final Comparator CHILD_COMPARATOR = new PositionComparator(); 50 51 private static final boolean DEBUG = false; 52 53 public ContainerSupport(SourceText s, ElementBinding parent) { 54 this.source = s; 55 this.parent = parent; 56 children = createSet(null); 57 separateMembers = true; 59 } 60 61 private Element getElement() { 62 return parent.getElement(); 63 } 64 65 public boolean isEmpty() { 66 return children == null || children.isEmpty(); 67 } 68 69 73 public PositionRef getFirstPosition() { 74 ElementBinding first; 75 synchronized (this) { 76 if (children.isEmpty()) 77 return null; 78 79 first = (ElementBinding)children.first(); 80 } 81 return first.wholeBounds.getBegin(); 82 } 83 84 88 public PositionRef getLastPosition() { 89 ElementBinding last; 90 synchronized (this) { 91 if (children.isEmpty()) 92 return null; 93 94 last = (ElementBinding)children.last(); 95 } 96 return last.wholeBounds.getEnd(); 97 } 98 99 protected PositionBounds getContainerBounds() { 100 return parent.findContainerBounds(this); 101 } 102 103 protected TreeSet createSet(Collection c) { 104 TreeSet s = new TreeSet(CHILD_COMPARATOR); 105 if (c != null) 106 s.addAll(c); 107 return s; 108 } 109 110 public void updateChildren(Collection c) { 111 ElementBinding last = null; 112 ElementBinding first = null; 113 114 for (Iterator it = c.iterator(); it.hasNext(); ) { 115 ElementBinding b = ((ElementBinding)it.next()); 116 if (first == null) { 117 first = b; 118 } 119 b.containerRef = this; 120 last = b; 121 } 122 children = createSet(c); 123 } 124 125 129 public synchronized ElementBinding findNext(ElementBinding b) { 130 SortedSet s; 131 132 if (b == null) { 133 if (children.isEmpty()) 134 return null; 135 return (ElementBinding)children.first(); 136 } 137 synchronized (source.getTreeLock()) { 138 s = children.tailSet(b); 139 } 140 if (s.size() < 2) 141 return null; 142 Iterator it = s.iterator(); 143 it.next(); 144 return (ElementBinding)it.next(); 145 } 146 147 public synchronized ElementBinding findPrevious(ElementBinding b) { 148 SortedSet s; 149 150 if (b == null) { 151 if (children.isEmpty()) 152 return null; 153 return (ElementBinding)children.last(); 154 } 155 synchronized (source.getTreeLock()) { 156 s = children.headSet(b); 157 } 158 if (s.size() < 1) 159 return null; 160 return (ElementBinding)s.last(); 161 } 162 163 166 public ElementBinding findBindingAt(int pos) { 167 Integer posObj = new Integer (pos); 168 SortedSet s = children.tailSet(posObj); 169 if (s == null || s.isEmpty()) 170 return null; 171 return ((ElementBinding)s.iterator().next()).findBindingAt(pos); 172 } 173 174 public ElementBinding findParent() { 175 return parent; 176 } 177 178 181 public boolean canInsertAfter(Binding b) { 182 if (!source.isAtomicAsUser()) 183 return true; 184 185 ElementBinding previous = (ElementBinding)b; 186 ElementBinding next; 187 PositionRef first; 188 PositionRef last; 189 PositionBounds cb = getContainerBounds(); 190 191 if (!source.isGeneratorEnabled() || cb == null) 192 return true; 193 194 if (previous == null) { 195 first = source.createPos(cb.getBegin().getOffset(), 197 Position.Bias.Forward); 198 if (children.isEmpty()) 199 next = null; 200 else 201 next = (ElementBinding)children.first(); 202 } else { 203 if (!previous.canInsertAfter()) 205 return false; 206 first = source.createPos(previous.wholeBounds.getEnd().getOffset(), 207 Position.Bias.Forward); 208 SortedSet s = children.tailSet(previous); 209 Iterator it = s.iterator(); 210 it.next(); 211 if (it.hasNext()) { 212 next = (ElementBinding)it.next(); 213 } else { 214 next = null; 215 } 216 } 217 218 if (next != null) { 219 last = source.createPos(next.wholeBounds.getBegin().getOffset() - 1, 220 Position.Bias.Forward); 221 } else { 222 int endOffset = cb.getEnd().getOffset(); 223 224 if (endOffset != 0) 225 endOffset--; 226 last = source.createPos(endOffset,Position.Bias.Forward); 227 } 228 229 return source.canWriteInside(new PositionBounds(first, last)); 230 } 231 232 public void reorder(Map fromToMap) throws SourceException { 233 } 235 public void replace(Binding oldBinding, Binding newBinding) throws SourceException { 236 } 238 public void insert(Binding toInitialize, Binding previous) throws SourceException { 239 } 241 242 245 public void insertChild(ElementBinding n, ElementBinding previous, ElementBinding next, 246 PositionBounds bounds) throws SourceException { 247 boolean emptyBefore, emptyAfter; 248 249 if (separateMembers) { 250 emptyBefore = emptyAfter = true; 251 } else { 252 emptyBefore = previous == null; 253 emptyAfter = next == null; 254 } 255 if (DEBUG) { 256 System.err.println("Trying to insert " + n + " after " + previous + ", before " + next + " container bounds = " + bounds); 258 } 259 n.create(this, previous, next, bounds, emptyBefore, emptyAfter); 260 } 261 262 public void insertChild(ElementBinding n, ElementBinding previous, ElementBinding next) 263 throws SourceException { 264 PositionBounds cb = getContainerBounds(); 265 if (cb == null) { 266 PositionRef upperBound = parent.getEndPosition(); 267 cb = new PositionBounds(upperBound, upperBound); 268 } 269 insertChild(n, previous, next, cb); 270 } 271 272 private void doReorder(Map reorderMap) throws SourceException { 273 Collection refPositions = new ArrayList(reorderMap.size()); 274 275 for (Iterator it = reorderMap.keySet().iterator(); it.hasNext(); ) { 276 ElementBinding impl = (ElementBinding)it.next(); 277 refPositions.add(impl.prepareInsert(null, false)); 278 } 279 280 Iterator it2 = refPositions.iterator(); 281 for (Iterator it = reorderMap.entrySet().iterator(); it.hasNext(); ) { 282 Map.Entry en = (Map.Entry)it.next(); 283 ElementBinding b2 = (ElementBinding)en.getValue(); 284 285 PositionRef refPos = (PositionRef)it2.next(); 286 } 288 } 289 290 private void performRemove(MultiPropertyChangeEvent evt) 291 throws SourceException { 292 if (evt == null) 293 return; 294 Collection elems = evt.getAffectedItems(); 295 int[] removeIndices = evt.getIndices(); 296 boolean empty = ((Object [])evt.getNewValue()).length == 0; 297 int pos = 0; 298 for (Iterator it = elems.iterator(); it.hasNext(); pos++) { 299 Element e = (Element)it.next(); 300 ElementBinding victim = source.findBinding(e); 301 boolean collapse; 302 303 if (this.separateMembers) 304 collapse = true; 305 else 306 collapse = empty; 307 victim.remove(collapse, collapse); 308 } 309 } 310 311 private void performReorder(MultiPropertyChangeEvent evt, int[] offsets) 312 throws SourceException { 313 if (evt == null) 314 return; 315 316 Element[] oldEls = (Element[])evt.getOldValue(); 317 Element[] newEls = (Element[])evt.getNewValue(); 318 int[] indices = evt.getIndices(); 319 Collection refPositions = new ArrayList(oldEls.length); 320 Collection items = new ArrayList(oldEls.length); 321 322 ElementBinding[] toMove = new ElementBinding[newEls.length]; 323 int count = 0; 324 325 ElementBinding refBinding = null; 326 for (int i = 0; i < indices.length; i++) { 327 if (indices[i] == -1) 328 continue; 330 toMove[indices[i]] = source.findBinding(oldEls[i]); 331 335 count++; 336 } 337 338 for (int i = 0; i < newEls.length; i++) { 340 if (toMove[i] == null) 341 continue; 342 343 ElementBinding previous, next; 344 ElementBinding moving = toMove[i]; 345 if (i > 0) 346 previous = source.findBinding(newEls[i - 1]); 347 else 348 previous = null; 349 if (i < newEls.length - 1) 350 next = source.findBinding(newEls[i + 1]); 351 else 352 next = null; 353 354 moving.moveTo(previous, next); 355 } 356 } 357 358 private void performInsert(MultiPropertyChangeEvent evt) 359 throws SourceException { 360 if (evt == null) 361 return; 362 Collection inserted = evt.getAffectedItems(); 363 int[] indexes = evt.getIndices(); 364 Iterator it = inserted.iterator(); 365 Element[] newEls = (Element[])evt.getNewValue(); 366 int indexPos = 0; 367 int existingPos = -1; 368 Element[] allElems = (Element[])evt.getNewValue(); 369 PositionRef upperBound; 370 ElementBinding nextBinding; 371 372 for (int i = 0; i < inserted.size(); i++) { 373 Element n = (Element)it.next(); 374 ElementBinding b = source.findBinding(n); 375 ElementBinding previous; 376 int idx = indexes[indexPos++]; 377 378 if (existingPos < idx) { 379 int tempIndex = indexPos; 380 existingPos = idx + 1; 381 while (existingPos < allElems.length && 382 tempIndex < indexes.length && 383 existingPos == indexes[tempIndex]) { 384 existingPos++; 385 tempIndex++; 386 } 387 } 388 if (existingPos >= allElems.length) { 389 nextBinding = null; 390 } 391 else { 392 nextBinding = source.findBinding(allElems[existingPos]); 393 upperBound = nextBinding.wholeBounds.getBegin(); 394 } 395 if (idx == 0) 396 previous = null; 397 else { 398 Element ref = newEls[idx - 1]; 399 previous = source.findBinding(ref); 400 } 401 insertChild(b, previous, nextBinding); 402 } 403 } 404 405 public static final int OP_REORDER = 0; 406 public static final int OP_INSERT = 1; 407 public static final int OP_REPLACE = 2; 408 public static final int OP_REMOVE = 3; 409 410 public void changeMembers(final MultiPropertyChangeEvent evt) 411 throws SourceException { 412 if (!source.isGeneratorEnabled()) 413 return; 415 source.runAtomic(parent.getElement(), new ExceptionRunnable() { 416 public void run() throws Exception { 417 performChangeMembers(evt); 418 } 419 }); 420 } 421 422 427 private void performChangeMembers(MultiPropertyChangeEvent evt) 428 throws SourceException { 429 430 MultiPropertyChangeEvent removeEv, reorderEv, insertEv; 434 435 Collection evs; 436 int[] offsets; 437 438 if (evt.getEventType() == evt.TYPE_COMPOUND) { 439 evs = evt.getComponents(); 440 offsets = evt.getIndices(); 441 } else { 442 evs = Collections.singletonList(evt); 443 offsets = null; 444 } 445 removeEv = reorderEv = insertEv = null; 446 for (Iterator it = evs.iterator(); it.hasNext(); ) { 447 MultiPropertyChangeEvent tmp; 448 449 tmp = (MultiPropertyChangeEvent)it.next(); 450 switch (tmp.getEventType()) { 451 case MultiPropertyChangeEvent.TYPE_ADD: 452 insertEv = tmp; 453 break; 454 case MultiPropertyChangeEvent.TYPE_REMOVE: 455 removeEv = tmp; 456 break; 457 case MultiPropertyChangeEvent.TYPE_REORDER: 458 reorderEv = tmp; 459 break; 460 default: 461 throw new IllegalArgumentException ("Unknown operation " + tmp.getEventType()); 463 } 464 } 465 performRemove(removeEv); 467 performInsert(insertEv); 468 performReorder(reorderEv, offsets); 469 computeChildren((Element[])evt.getNewValue()); 470 } 471 472 private void computeChildren(Element[] els) { 473 ElementBinding[] bindings = new ElementBinding[els.length]; 474 475 for (int i = 0; i < els.length; i++) { 476 bindings[i] = source.findBinding(els[i]); 477 } 478 updateChildren(Arrays.asList(bindings)); 479 } 480 481 482 private class Writer implements ExceptionRunnable { 483 int operation; 484 Map reorderMap; 485 ElementBinding previous, current; 486 487 Writer(Map reorder) { 488 this.operation = OP_REORDER; 489 this.reorderMap = reorder; 490 } 491 492 Writer(ElementBinding prev, ElementBinding toinsert) { 493 this.previous = prev; 494 this.current = toinsert; 495 this.operation = OP_INSERT; 496 } 497 498 public void run() throws Exception { 499 if (!source.isGeneratorEnabled()) 500 return; 501 switch (operation) { 502 case OP_INSERT: 503 507 case OP_REORDER: 508 doReorder(reorderMap); 509 break; 510 default: 511 throw new UnsupportedOperationException ("Unknown operation :" + operation); } 513 } 514 } 515 } 516 | Popular Tags |