1 19 20 package org.netbeans.modules.form.layoutdesign; 21 22 import java.util.*; 23 24 25 31 32 public class LayoutUtils implements LayoutConstants { 33 34 private LayoutUtils() { 35 } 36 37 public static LayoutInterval getAdjacentEmptySpace(LayoutComponent comp, int dimension, int direction) { 38 LayoutInterval interval = comp.getLayoutInterval(dimension); 39 LayoutInterval parent; 40 while ((parent = interval.getParent()) != null) { 41 if (parent.isSequential()) { 42 int index = parent.indexOf(interval); 43 if (direction == LEADING) { 44 if (index == 0) { 45 interval = parent; 46 } else { 47 LayoutInterval candidate = parent.getSubInterval(index-1); 48 return candidate.isEmptySpace() ? candidate : null; 49 } 50 } else { 51 if (index == parent.getSubIntervalCount()-1) { 52 interval = parent; 53 } else { 54 LayoutInterval candidate = parent.getSubInterval(index+1); 55 return candidate.isEmptySpace() ? candidate : null; 56 } 57 } 58 } else { 59 if (LayoutInterval.isPlacedAtBorder(interval, dimension, direction)) { 61 interval = parent; 62 } else { 63 return null; 64 } 65 } 66 } 67 return null; 68 } 69 70 73 static LayoutInterval getOutermostComponent(LayoutInterval interval, int dimension, int alignment) { 74 if (interval.isComponent()) { 75 return interval; 76 } 77 78 assert alignment == LEADING || alignment == TRAILING; 79 80 if (interval.isSequential()) { 81 int d = alignment == LEADING ? 1 : -1; 82 int i = alignment == LEADING ? 0 : interval.getSubIntervalCount()-1; 83 while (i >= 0 && i < interval.getSubIntervalCount()) { 84 LayoutInterval li = interval.getSubInterval(i); 85 if (li.isEmptySpace()) { 86 i += d; 87 } 88 else { 92 return getOutermostComponent(li, dimension, alignment); 93 } 94 } 95 } 97 else if (interval.isParallel()) { 98 LayoutInterval best = null; 99 int pos = Integer.MAX_VALUE; 100 for (int i=0, n=interval.getSubIntervalCount(); i < n; i++) { 101 LayoutInterval li = getOutermostComponent(interval.getSubInterval(i), dimension, alignment); 102 if (li != null) { 103 if (LayoutInterval.isAlignedAtBorder(li, interval, alignment)) { 104 return li; 105 } 106 int p = li.getCurrentSpace().positions[dimension][alignment] 107 * (alignment == LEADING ? 1 : -1); 108 if (p < pos) { 109 best = li; 110 pos = p; 111 } 112 } 113 } 114 return best; 115 } 116 return null; 120 } 121 122 128 static int getSizeOfDefaultGap(LayoutInterval interval, VisualMapper visualMapper) { 129 assert interval.isEmptySpace(); 130 LayoutInterval parent = interval.getParent(); 131 if (parent.isParallel()) 132 return interval.getPreferredSize(); 133 134 LayoutInterval candidate = interval; 136 LayoutInterval srcInt = null; 137 LayoutInterval targetInt = null; 138 while ((parent != null) && ((srcInt == null) || (targetInt == null))) { 139 int index = parent.indexOf(candidate); 140 if ((srcInt == null) && (index > 0)) { 141 srcInt = parent.getSubInterval(index-1); 142 } 143 if ((targetInt == null) && (index < parent.getSubIntervalCount()-1)) { 144 targetInt = parent.getSubInterval(index+1); 145 } 146 if ((srcInt == null) || (targetInt == null)) { 147 do { 148 candidate = parent; 149 parent = parent.getParent(); 150 } while ((parent != null) && parent.isParallel()); 151 } 152 } 153 154 List sources = edgeSubComponents(srcInt, TRAILING); 156 List targets = edgeSubComponents(targetInt, LEADING); 157 158 return getSizeOfDefaultGap(sources, targets, visualMapper, null, Collections.EMPTY_MAP); 160 } 161 162 static int getSizeOfDefaultGap(List sources, List targets, VisualMapper visualMapper, 163 String contId, Map boundsMap) { 164 if (((sources != null) && (sources.isEmpty())) 165 || ((targets != null) && (targets.isEmpty()))) { 166 return 0; } 168 sources = (sources == null) ? Collections.EMPTY_LIST : sources; 169 targets = (targets == null) ? Collections.EMPTY_LIST : targets; 170 int size = 0; 171 boolean containerGap = false; 172 int containerGapAlignment = -1; 173 LayoutInterval temp = null; 174 if (sources.isEmpty()) { 175 if (targets.isEmpty()) { 176 return 0; 177 } else { 178 containerGap = true; 180 containerGapAlignment = LEADING; 181 temp = (LayoutInterval)targets.get(0); 182 } 183 } else { 184 temp = (LayoutInterval)sources.get(0); 185 if (targets.isEmpty()) { 186 containerGap = true; 188 containerGapAlignment = TRAILING; 189 } 190 } 191 int dimension = (temp == temp.getComponent().getLayoutInterval(HORIZONTAL)) ? HORIZONTAL : VERTICAL; 192 int max = Short.MIN_VALUE; 194 int min = Short.MAX_VALUE; 195 boolean positionsNotUpdated = false; 196 Iterator iter = sources.iterator(); 197 while (iter.hasNext()) { 198 LayoutInterval source = (LayoutInterval)iter.next(); 199 LayoutRegion region = sizeOfEmptySpaceHelper(source, boundsMap); 200 int trailing = region.positions[dimension][TRAILING]; 201 if (trailing == LayoutRegion.UNKNOWN) { 202 positionsNotUpdated = true; break; 203 } else { 204 max = Math.max(max, trailing); 205 } 206 } 207 iter = targets.iterator(); 208 while (iter.hasNext()) { 209 LayoutInterval target = (LayoutInterval)iter.next(); 210 LayoutRegion region = sizeOfEmptySpaceHelper(target, boundsMap); 211 int leading = region.positions[dimension][LEADING]; 212 if (leading == LayoutRegion.UNKNOWN) { 213 positionsNotUpdated = true; break; 214 } else { 215 min = Math.min(min, leading); 216 } 217 } 218 if (containerGap) { 219 iter = sources.isEmpty() ? targets.iterator() : sources.iterator(); 220 while (iter.hasNext()) { 221 LayoutInterval interval = (LayoutInterval)iter.next(); 222 LayoutComponent component = interval.getComponent(); 223 LayoutRegion region = sizeOfEmptySpaceHelper(interval, boundsMap); 224 String parentId = (contId == null) ? component.getParent().getId() : contId; 225 int padding = visualMapper.getPreferredPaddingInParent(parentId, component.getId(), dimension, containerGapAlignment); 226 int position = region.positions[dimension][containerGapAlignment]; 227 int delta = (containerGapAlignment == LEADING) ? (position - min) : (max - position); 228 if (!positionsNotUpdated) padding -= delta; 229 size = Math.max(size, padding); 230 } 231 } else { 232 Iterator srcIter = sources.iterator(); 233 while (srcIter.hasNext()) { 234 LayoutInterval srcCandidate = (LayoutInterval)srcIter.next(); 235 String srcId = srcCandidate.getComponent().getId(); 236 LayoutRegion srcRegion = sizeOfEmptySpaceHelper(srcCandidate, boundsMap); 237 int srcDelta = max - srcRegion.positions[dimension][TRAILING]; 238 Iterator targetIter = targets.iterator(); 239 while (targetIter.hasNext()) { 240 LayoutInterval targetCandidate = (LayoutInterval)targetIter.next(); 241 String targetId = targetCandidate.getComponent().getId(); 242 LayoutRegion targetRegion = sizeOfEmptySpaceHelper(targetCandidate, boundsMap); 243 int targetDelta = targetRegion.positions[dimension][LEADING] - min; 244 int padding = visualMapper.getPreferredPadding(srcId, 245 targetId, dimension, LEADING, VisualMapper.PADDING_RELATED); 246 if (!positionsNotUpdated) padding -= srcDelta + targetDelta; 247 size = Math.max(size, padding); 248 } 249 } 250 } 251 return size; 252 } 253 254 private static LayoutRegion sizeOfEmptySpaceHelper(LayoutInterval interval, Map boundsMap) { 255 LayoutComponent component = interval.getComponent(); 256 String compId = component.getId(); 257 if (boundsMap.containsKey(compId)) { 258 return (LayoutRegion)boundsMap.get(compId); 259 } else { 260 return interval.getCurrentSpace(); 261 } 262 } 263 264 static int getVisualPosition(LayoutInterval interval, int dimension, int alignment) { 265 if (interval.isEmptySpace()) { 266 assert alignment == LEADING || alignment == TRAILING; 267 LayoutInterval neighbor = LayoutInterval.getDirectNeighbor(interval, alignment, false); 268 if (neighbor != null) { 269 interval = neighbor; 270 alignment ^= 1; 271 } 272 else interval = LayoutInterval.getFirstParent(interval, PARALLEL); 273 } 274 return interval.getCurrentSpace().positions[dimension][alignment]; 275 } 276 277 288 static List edgeSubComponents(LayoutInterval root, int edge) { 289 List components = null; 290 List candidates = new LinkedList(); 291 if (root != null) { 292 components = new LinkedList(); 293 candidates.add(root); 294 } 295 while (!candidates.isEmpty()) { 296 LayoutInterval candidate = (LayoutInterval)candidates.get(0); 297 candidates.remove(candidate); 298 if (candidate.isGroup()) { 299 if (candidate.isSequential()) { 300 int index = (edge == LEADING) ? 0 : candidate.getSubIntervalCount()-1; 301 candidates.add(candidate.getSubInterval(index)); 302 } else { 303 Iterator subs = candidate.getSubIntervals(); 304 while (subs.hasNext()) { 305 candidates.add(subs.next()); 306 } 307 } 308 } else if (candidate.isComponent()) { 309 components.add(candidate); 310 } 311 } 312 return components; 313 } 314 315 321 static boolean contentOverlap(LayoutRegion space, LayoutInterval interval, int dimension) { 322 return contentOverlap(space, interval, -1, -1, dimension); 323 } 324 325 static boolean contentOverlap(LayoutRegion space, LayoutInterval interval, int fromIndex, int toIndex, int dimension) { 326 LayoutRegion examinedSpace = interval.getCurrentSpace(); 327 if (!interval.isGroup()) { 328 return LayoutRegion.overlap(space, examinedSpace, dimension, 0); 329 } 330 boolean overlap = !examinedSpace.isSet(dimension) 331 || LayoutRegion.overlap(space, examinedSpace, dimension, 0); 332 if (overlap) { 333 if (fromIndex < 0) 334 fromIndex = 0; 335 if (toIndex < 0) 336 toIndex = interval.getSubIntervalCount()-1; 337 assert fromIndex <= toIndex; 338 339 overlap = false; 340 for (int i=fromIndex; i <= toIndex; i++) { 341 LayoutInterval li = interval.getSubInterval(i); 342 if (!li.isEmptySpace() && contentOverlap(space, li, dimension)) { 343 overlap = true; 344 break; 345 } 346 } 347 } 348 return overlap; 349 } 350 351 355 static boolean contentOverlap(LayoutInterval interval1, LayoutInterval interval2, int dimension) { 356 return contentOverlap(interval1, interval2, -1, -1, dimension); 357 } 358 359 363 static boolean contentOverlap(LayoutInterval interval1, LayoutInterval interval2, 364 int fromIndex, int toIndex, int dimension) 365 { 366 if (!interval2.isGroup()) { 367 if (!interval1.isGroup()) { 368 return LayoutRegion.overlap(interval1.getCurrentSpace(), 369 interval2.getCurrentSpace(), dimension, 0); 370 } 371 LayoutInterval temp = interval1; 372 interval1 = interval2; 373 interval2 = temp; 374 } 375 376 List int2list = null; 378 List addList = null; 379 Iterator it1 = getComponentIterator(interval1); 380 while (it1.hasNext()) { 381 LayoutRegion space1 = ((LayoutInterval)it1.next()).getCurrentSpace(); 382 Iterator it2 = int2list != null ? 383 int2list.iterator() : 384 getComponentIterator(interval2, fromIndex, toIndex); 385 if (int2list == null && it1.hasNext()) { 386 int2list = new LinkedList(); 387 addList = int2list; 388 } 389 while (it2.hasNext()) { 390 LayoutInterval li2 = (LayoutInterval) it2.next(); 391 if (LayoutRegion.overlap(space1, li2.getCurrentSpace(), dimension, 0)) 392 return true; 393 if (addList != null) 394 addList.add(li2); 395 } 396 addList = null; 397 } 398 return false; 399 } 400 401 407 static boolean isOverlapPreventedInOtherDimension(LayoutInterval compInterval, 408 LayoutInterval interval, 409 int dimension) 410 { 411 int otherDim = dimension^1; 412 compInterval = (LayoutInterval) getComponentIterator(compInterval).next(); 413 LayoutComponent component = compInterval.getComponent(); 414 LayoutInterval otherCompInterval = component.getLayoutInterval(otherDim); 415 Iterator it = getComponentIterator(interval); 416 assert it.hasNext(); 417 do { 418 LayoutComponent comp = ((LayoutInterval)it.next()).getComponent(); 419 LayoutInterval otherInterval = comp.getLayoutInterval(otherDim); 420 LayoutInterval parent = LayoutInterval.getCommonParent(otherCompInterval, otherInterval); 421 if (parent == null || parent.isParallel()) 422 return false; 423 } 424 while (it.hasNext()); 425 return true; 426 } 427 428 static Iterator getComponentIterator(LayoutInterval interval) { 429 return new ComponentIterator(interval, 0, interval.getSubIntervalCount()-1); 430 } 431 432 static Iterator getComponentIterator(LayoutInterval interval, int startIndex, int endIndex) { 433 return new ComponentIterator(interval, startIndex, endIndex); 434 } 435 436 private static class ComponentIterator implements Iterator { 437 private LayoutInterval root; 438 private int startIndex, endIndex; 439 private boolean initialized; 440 private int index; 441 private LayoutInterval next; 442 443 ComponentIterator(LayoutInterval interval, int startIndex, int endIndex) { 444 root = interval; 445 this.startIndex = startIndex; 446 this.endIndex = endIndex; 447 findNext(); 448 initialized = true; 449 } 450 451 private void findNext() { 452 LayoutInterval parent; 453 int idx; 454 if (next == null) { 455 if (initialized) 456 return; 457 if (!root.isGroup()) { 458 if (root.isComponent()) { 459 next = root; 460 } 461 return; 462 } 463 parent = root; idx = startIndex; 465 } 466 else if (next != root) { parent = next.getParent(); 468 idx = index + 1; 469 } 470 else { next = null; 472 return; 473 } 474 475 next = null; 476 do { 477 while (idx < parent.getSubIntervalCount()) { 478 if (parent == root && idx > endIndex) 479 return; LayoutInterval sub = parent.getSubInterval(idx); 481 if (sub.isComponent()) { next = sub; 483 index = idx; 484 return; 485 } 486 if (sub.isGroup()) { parent = sub; 488 idx = 0; 489 } 490 else idx++; 491 } 492 if (parent != root) { idx = parent.getParent().indexOf(parent) + 1; 494 parent = parent.getParent(); 495 } 496 else break; } 498 while (true); 499 } 500 501 public boolean hasNext() { 502 return next != null; 503 } 504 505 public Object next() { 506 if (next == null) 507 throw new NoSuchElementException(); 508 509 Object ret = next; 510 findNext(); 511 return ret; 512 } 513 514 public void remove() { 515 throw new UnsupportedOperationException (); 516 } 517 } 518 } 519 | Popular Tags |