1 6 7 package org.netbeans.modules.piagetproject.gridsplit; 8 9 import java.awt.Component ; 10 import java.awt.Dimension ; 11 import java.awt.Point ; 12 import java.awt.Rectangle ; 13 import java.util.Iterator ; 14 import java.util.List ; 15 import java.util.ArrayList ; 16 17 21 public class GridSplitCell { 22 23 public static final int NORTH = 1; 24 public static final int SOUTH = 2; 25 public static final int WEST = 4; 26 public static final int EAST = 8; 27 28 public static final int NO_SPLITTER = 0; 29 public static final int HORIZONTAL_SPLITTER = NORTH + SOUTH; 30 public static final int VERTICAL_SPLITTER = WEST + EAST; 31 32 33 private GridSplitCell parent; 35 private List children = new ArrayList (); 37 private int splitterOrientation = NO_SPLITTER; 39 private Component component; 41 private double resizeWeight = 0.0; 43 private double normalizedResizeWeight = 0.0; 45 private boolean collapsed = false; 47 private boolean isHidden = false; 49 private Dimension dimension = new Dimension (0,0); 51 private Point location = new Point (0,0); 53 54 GridSplitCell( Component c, double resizeWeight ) { 55 this( c, resizeWeight, new Dimension (0,0) ); 56 } 57 58 GridSplitCell( Component c, double resizeWeight, Dimension initialDimension ) { 59 this.component = c; 60 this.resizeWeight = resizeWeight; 61 this.dimension.width = initialDimension.width; 62 this.dimension.height = initialDimension.height; 63 } 64 65 68 GridSplitCell( GridSplitCell src ) { 69 copy( src, this ); 70 this.parent = src.parent; 71 } 72 73 public GridSplitCell getParent() { 74 return parent; 75 } 76 77 void setParent( GridSplitCell newParent ) { 78 this.parent = newParent; 79 } 80 81 84 public int count() { 85 return children.size(); 86 } 87 88 91 public int countVisibleCells() { 92 return getVisibleCells().size(); 94 } 95 96 99 public GridSplitCell cellAt( int index ) { 100 return (GridSplitCell) children.get( index ); 101 } 102 103 106 public boolean isRootCell() { 107 return null == getParent(); 108 } 109 110 118 public GridSplitCell addToSide( Component compToAdd, int side, double initialSize, double resizeWeight ) { 119 GridSplitCell newChild = new GridSplitCell( compToAdd, resizeWeight ); 120 GridSplitCell owner; 121 GridSplitCell neighbor; 122 if( isRootCell() ) { 123 owner = this; 126 if( isSplitterSide( side ) ) { 127 if( side == NORTH || side == WEST ) { 130 neighbor = cellAt( 0 ); 131 } else { 132 neighbor = cellAt( count()-1 ); 133 } 134 } else { 135 owner = this; 137 neighbor = split(); 138 } 139 } else { 140 owner = getParent(); 141 if( owner.isSplitterSide( side ) ) { 142 neighbor = this; 144 } else { 145 owner = this; 147 neighbor = split(); 148 } 149 } 150 owner.addToSide( neighbor, newChild, side, initialSize ); 151 return newChild; 152 } 153 154 157 private GridSplitCell split() { 158 GridSplitCell child = new GridSplitCell( this ); 159 160 children.clear(); 161 children.add( child ); 162 child.setParent( this ); 163 component = null; 164 165 return child; 166 } 167 168 171 private void addToSide( GridSplitCell neighbor, GridSplitCell newChild, int side, double initialSize ) { 172 Dimension parentSize = getDimension( 0 ); 173 splitterOrientation = (side == NORTH || side == SOUTH) ? VERTICAL_SPLITTER : HORIZONTAL_SPLITTER; 174 int insertIndex = children.indexOf( neighbor ); 175 assert insertIndex >= 0; 176 if( side == SOUTH || side == EAST ) 177 insertIndex++; 178 if( insertIndex > children.size() ) 179 children.add( newChild ); 180 else 181 children.add( insertIndex, newChild ); 182 if( isHorizontalSplitter() ) { 183 newChild.dimension = new Dimension ( (int)(parentSize.width*initialSize), parentSize.height ); 184 } else { 185 newChild.dimension = new Dimension ( parentSize.width, (int)(parentSize.height*initialSize) ); 186 } 187 newChild.setParent( this ); 188 } 189 190 193 boolean isSplitterSide( int side ) { 194 return (isHorizontalSplitter() && (side == WEST || side == EAST)) 195 || (isVerticalSplitter() && (side == SOUTH || side == NORTH)); 196 } 197 198 202 public void remove( GridSplitCell child ) { 203 assert children.contains( child ); 204 205 children.remove( child ); 206 if( children.size() == 1 ) { 207 GridSplitCell orphan = cellAt( 0 ); 208 209 if( null != getParent() ) { 210 getParent().replace( this, orphan ); 212 } else { 213 copy( orphan, this ); 215 } 216 } 217 } 218 219 222 private void replace( GridSplitCell origCell, GridSplitCell newCell ) { 223 assert children.contains( origCell ); 224 int index = children.indexOf( origCell ); 225 if( newCell.isSplit() && newCell.splitterOrientation == splitterOrientation ) { 226 children.addAll( index, newCell.children ); 227 for( Iterator i=newCell.children.iterator(); i.hasNext(); ) { 228 GridSplitCell c = (GridSplitCell)i.next(); 229 c.setParent( this ); 230 } 231 children.remove( origCell ); 232 } else { 233 children.set( index, newCell ); 234 newCell.setParent( this ); 235 } 236 } 237 238 241 public boolean isSplit() { 242 return null == component || children.size() == 1; 243 } 244 245 public int getSplitOrientation() { 246 return splitterOrientation; 247 } 248 249 public boolean isHorizontalSplitter() { 250 return splitterOrientation == HORIZONTAL_SPLITTER; 251 } 252 253 public boolean isVerticalSplitter() { 254 return splitterOrientation == VERTICAL_SPLITTER; 255 } 256 257 public Component getComponent() { 258 return component; 259 } 260 261 266 public Dimension getMinimumSize( int dividerSize ) { 267 if( isCollapsed() || isHidden() ) { 268 return new Dimension ( 0, 0 ); 269 } else { 270 if( isSplit() ) { 271 return calculateMinimumSize( dividerSize ); 272 } else { 273 return component.getMinimumSize(); 274 } 275 } 276 } 277 278 281 private Dimension calculateMinimumSize( int dividerSize ) { 282 Dimension minSize = new Dimension ( 0, 0 ); 283 ArrayList visibleCells = getVisibleCells(); 284 for( Iterator i=visibleCells.iterator(); i.hasNext(); ) { 285 GridSplitCell child = (GridSplitCell)i.next(); 286 287 Dimension childMinSize = child.getMinimumSize( dividerSize ); 288 289 if( isHorizontalSplitter() ) { 290 minSize.width += childMinSize.width; 291 if( childMinSize.height > minSize.height ) 292 minSize.height = childMinSize.height; 293 } else { 294 minSize.height += childMinSize.height; 295 if( childMinSize.width > minSize.width ) 296 minSize.width = childMinSize.width; 297 } 298 } 299 if( isHorizontalSplitter() ) { 300 minSize.width += (visibleCells.size()-1)*dividerSize; 301 } else { 302 minSize.height += (visibleCells.size()-1)*dividerSize; 303 } 304 305 return minSize; 306 } 307 308 311 ArrayList getVisibleCells() { 312 ArrayList res = new ArrayList ( children.size() ); 313 for( Iterator i=children.iterator(); i.hasNext(); ) { 314 GridSplitCell child = (GridSplitCell)i.next(); 315 if( child.isHidden() ) 316 continue; 317 res.add( child ); 318 } 319 return res; 320 } 321 322 325 ArrayList getResizeableCells() { 326 ArrayList res = new ArrayList ( children.size() ); 327 for( Iterator i=children.iterator(); i.hasNext(); ) { 328 GridSplitCell child = (GridSplitCell)i.next(); 329 if( child.isHidden() || child.isCollapsed() ) 330 continue; 331 res.add( child ); 332 } 333 return res; 334 } 335 336 339 ArrayList getResizeHungryCells() { 340 ArrayList res = new ArrayList ( children.size() ); 341 for( Iterator i=children.iterator(); i.hasNext(); ) { 342 GridSplitCell child = (GridSplitCell)i.next(); 343 if( child.isHidden() || child.isCollapsed() || child.resizeWeight == 0.0 ) 344 continue; 345 res.add( child ); 346 } 347 return res; 348 } 349 350 353 void resize( int width, int height, int dividerSize ) { 354 if( isSplit() ) { 355 356 int currentSize = getSize( this, dividerSize ); 358 int newNetSize = (isHorizontalSplitter() ? width : height); 359 int delta = newNetSize - currentSize; 360 362 if( delta > 0 ) { 363 365 grow( delta, dividerSize ); 366 367 } else if( delta < 0 ) { 368 369 delta = shrink( delta, dividerSize ); 370 371 if( delta > 0 ) { 372 newNetSize -= delta; 375 if( isHorizontalSplitter() ) 376 width -= delta; 377 else 378 height -= delta; 379 } 380 } 381 382 int totalSize = 0; 384 ArrayList visibleCells = getVisibleCells(); 385 for( int i=0; i<visibleCells.size(); i++ ) { 386 GridSplitCell child = (GridSplitCell)visibleCells.get( i ); 387 int childWidth = isHorizontalSplitter() ? child.getSize( this, dividerSize ) : width; 388 int childHeight = isHorizontalSplitter() ? height : child.getSize( this, dividerSize ); 389 390 if( isHorizontalSplitter() ) { 391 totalSize += childWidth; 392 if( i == visibleCells.size()-1 && totalSize < newNetSize ) { 393 System.out.println( "Extra width: " + (newNetSize - totalSize)); 396 childWidth += newNetSize - totalSize; 397 } else { 399 totalSize += dividerSize; 400 } 401 } else { 402 totalSize += childHeight; 403 if( i == visibleCells.size()-1 && totalSize < newNetSize ) { 404 System.out.println( "Extra height: " + (newNetSize - totalSize)); 407 childHeight += newNetSize - totalSize; 408 } else { 410 totalSize += dividerSize; 411 } 412 } 413 child.resize( childWidth, childHeight, dividerSize ); 414 } 415 if( !(isCollapsed() || isHidden()) ) { 416 if( isHorizontalSplitter() ) 417 setDimension( new Dimension ( newNetSize, height ) ); 418 else 419 setDimension( new Dimension ( width, newNetSize ) ); 420 } 421 } else { 422 setDimension( new Dimension ( width, height ) ); 423 } 424 } 425 426 429 private void grow( int delta, int dividerSize ) { 430 ArrayList hungryCells = getResizeHungryCells(); 432 433 if( !hungryCells.isEmpty() ) { 435 normalizeResizeWeights( hungryCells ); 437 distributeDelta( delta, hungryCells, dividerSize ); 438 } else { 439 ArrayList resizeableCells = getResizeableCells(); 441 normalizeResizeWeights( resizeableCells ); 442 distributeDelta( delta, resizeableCells, dividerSize ); 443 } 444 } 445 446 452 private int shrink( int negativeDelta, int dividerSize ) { 453 int delta = -negativeDelta; 454 455 ArrayList hungryCells = getResizeHungryCells(); 457 458 int resizeArea = calculateShrinkableArea( hungryCells, dividerSize ); 460 if( resizeArea >= delta ) { 461 resizeArea = delta; 462 delta = 0; 463 } else { 464 delta -= resizeArea; 465 } 466 if( resizeArea > 0 ) { 467 distributeDelta( -resizeArea, hungryCells, dividerSize ); 469 } 470 471 if( delta > 0 ) { 472 ArrayList resizeableCells = getResizeableCells(); 475 476 resizeArea = calculateShrinkableArea( resizeableCells, dividerSize ); 477 if( resizeArea >= delta ) { 478 resizeArea = delta; 479 delta = 0; 480 } else { 481 delta -= resizeArea; 482 } 483 if( resizeArea > 0 ) { 484 distributeDelta( -resizeArea, resizeableCells, dividerSize ); 485 } 486 } 487 return delta; 488 } 489 490 496 private int calculateShrinkableArea( ArrayList cells, int dividerSize ) { 497 int res = 0; 498 ArrayList nonShrinkable = new ArrayList ( cells.size() ); 499 for( int i=0; i<cells.size(); i++ ) { 500 GridSplitCell c = (GridSplitCell)cells.get( i ); 501 if( c.isCollapsed() || c.isHidden() ) 502 continue; 503 int currentSize = c.getSize( c.getParent(), dividerSize ); 504 int minSize = c.getMinSize( c.getParent(), dividerSize ); 505 if( currentSize - minSize > 0 ) { 506 res += currentSize - minSize; 507 } else { 508 nonShrinkable.add( c ); 509 } 510 } 511 512 cells.removeAll( nonShrinkable ); 513 for( int i=0; i<cells.size(); i++ ) { 514 GridSplitCell c = (GridSplitCell)cells.get( i ); 515 int currentSize = c.getSize( c.getParent(), dividerSize ); 516 int minSize = c.getMinSize( c.getParent(), dividerSize ); 517 c.normalizedResizeWeight = 1.0*(currentSize-minSize)/res; 518 } 519 return res; 520 } 521 522 525 private void distributeDelta( int delta, ArrayList cells, int dividerSize ) { 526 int totalDistributed = 0; 527 for( int i=0; i<cells.size(); i++ ) { 528 GridSplitCell child = (GridSplitCell)cells.get( i ); 529 int childDelta = (int)(child.normalizedResizeWeight*delta); 530 totalDistributed += childDelta; 531 if( i == cells.size()-1 ) childDelta += delta - totalDistributed; 533 child.setSize( this, child.getSize( this, dividerSize ) + childDelta ); 534 } 535 } 536 537 540 private void normalizeResizeWeights( List cells ) { 541 if( cells.isEmpty() ) 542 return; 543 544 double totalWeight = 0.0; 545 for( Iterator i=cells.iterator(); i.hasNext(); ) { 546 GridSplitCell c = (GridSplitCell)i.next(); 547 totalWeight += c.resizeWeight; 548 } 549 550 double deltaWeight = (1.0 - totalWeight) / cells.size(); 551 552 for( Iterator i=cells.iterator(); i.hasNext(); ) { 553 GridSplitCell c = (GridSplitCell)i.next(); 554 c.normalizedResizeWeight = c.resizeWeight + deltaWeight; 555 } 556 } 557 558 561 public void setCollapsed( boolean collapsed ) { 562 if( this.collapsed == collapsed ) { 563 return; 564 } 565 this.collapsed = collapsed; 566 if( isSplit() ) { 567 for( Iterator i=children.iterator(); i.hasNext(); ) { 568 GridSplitCell cell = (GridSplitCell)i.next(); 569 cell.setCollapsed( collapsed ); 570 } 571 } else { 572 component.setVisible( !collapsed ); 573 } 574 } 575 576 public boolean isCollapsed() { 577 return collapsed; 578 } 579 580 public void setHidden( boolean hidden ) { 581 this.isHidden = hidden; 582 } 583 584 public boolean isHidden() { 585 return isHidden; 586 } 587 588 private int getSize( GridSplitCell splitCell, int dividerSize ) { 589 if( splitCell.isHorizontalSplitter() ) 590 return getDimension( dividerSize ).width; 591 return getDimension( dividerSize ).height; 592 } 593 594 private int getMinSize( GridSplitCell splitCell, int dividerSize ) { 595 if( splitCell.isHorizontalSplitter() ) 596 return getMinimumSize( dividerSize ).width; 597 return getMinimumSize( dividerSize ).height; 598 } 599 600 private void setSize( GridSplitCell splitCell, int newSize ) { 601 if( isCollapsed() || isHidden() ) 602 return; 603 604 if( splitCell.isHorizontalSplitter() ) 605 dimension.width = newSize; 606 else 607 dimension.height = newSize; 608 } 609 610 private void setDimension( Dimension newDimension ) { 611 if( isCollapsed() || isHidden() ) 612 return; 613 614 this.dimension = newDimension; 615 } 616 617 public Dimension getDimension( int dividerSize ) { 618 if( isHidden() || isCollapsed() ) 619 return new Dimension ( 0, 0 ); 620 621 if( isSplit() ) { 622 Dimension res = new Dimension ( 0, 0 ); 623 ArrayList visibleCells = getVisibleCells(); 624 for( int i=0; i<visibleCells.size(); i++ ) { 625 GridSplitCell child = (GridSplitCell)visibleCells.get( i ); 626 Dimension childDim = child.getDimension( dividerSize ); 627 if( isHorizontalSplitter() ) { 628 res.height = this.dimension.height; 629 res.width += childDim.width; 630 } else { 631 res.height += childDim.height; 632 res.width = this.dimension.width; 633 } 634 } 635 if( isHorizontalSplitter() ) { 636 res.width += (visibleCells.size()-1)*dividerSize; 637 } else { 638 res.height += (visibleCells.size()-1)*dividerSize; 639 } 640 return res; 641 } 642 return new Dimension ( dimension ); 643 } 644 645 private static void copy( GridSplitCell source, GridSplitCell target ) { 646 target.component = source.component; 647 target.children = new ArrayList ( source.children ); 648 for( Iterator i=target.children.iterator(); i.hasNext(); ) { 649 GridSplitCell cell = (GridSplitCell)i.next(); 650 cell.setParent( target ); 651 } 652 target.resizeWeight = source.resizeWeight; 654 target.splitterOrientation = source.splitterOrientation; 655 target.collapsed = source.collapsed; 656 target.dimension = new Dimension ( source.dimension ); 657 target.isHidden = source.isHidden; 658 target.location = new Point ( source.location ); 659 } 660 661 665 void setLocation( int x, int y, int dividerSize ) { 666 location.x = x; 667 location.y = y; 668 if( isSplit() ) { 669 ArrayList visibleCells = getVisibleCells(); 670 int childX = x; 671 int childY = y; 672 for( int i=0; i<visibleCells.size(); i++ ) { 673 GridSplitCell child = (GridSplitCell)visibleCells.get( i ); 674 Dimension d = child.getDimension( dividerSize ); 675 child.setLocation( childX, childY, dividerSize ); 676 677 if( isHorizontalSplitter() ) 678 childX += d.width + dividerSize; 679 else 680 childY += d.height + dividerSize; 681 } 682 } else { 683 component.setLocation( location ); 684 component.setSize( dimension ); 685 } 686 } 687 688 Point getLocation() { 689 return new Point ( location ); 690 } 691 } | Popular Tags |