Skip to content

Commit 4652fc3

Browse files
committed
Performance boost.
1 parent 8ebd111 commit 4652fc3

File tree

4 files changed

+89
-67
lines changed

4 files changed

+89
-67
lines changed

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ package org.quinto.swing.table.view;
6464

6565
import java.awt.FlowLayout;
6666
import javax.swing.JFrame;
67-
import javax.swing.JScrollPane;
6867
import javax.swing.UIManager;
6968
import org.quinto.swing.table.model.IModelFieldGroup;
7069
import org.quinto.swing.table.model.ModelData;
@@ -117,7 +116,7 @@ public class Sample {
117116
JFrame frame = new JFrame( "Test" );
118117
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
119118
frame.setLayout( new FlowLayout() );
120-
frame.add( new JScrollPane( table ) );
119+
frame.add( table.getScrollPane() );
121120
frame.pack();
122121
frame.setLocationRelativeTo( null );
123122
frame.setVisible( true );

src/org/quinto/swing/table/model/ModelData.java

+13-5
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
import java.io.IOException;
44
import java.io.ObjectInputStream;
55
import java.io.Serializable;
6+
import java.util.ArrayDeque;
67
import java.util.ArrayList;
78
import java.util.Arrays;
89
import java.util.Collections;
10+
import java.util.Deque;
911
import java.util.HashMap;
1012
import java.util.HashSet;
1113
import java.util.Iterator;
12-
import java.util.LinkedList;
1314
import java.util.List;
1415
import java.util.Map;
1516
import java.util.Set;
@@ -300,7 +301,7 @@ public String getHeaderString() {
300301
*/
301302
public Iterable< IModelFieldGroup > getAllFieldGroupsFromBottom( final boolean depthFirst ) {
302303
return new Iterable< IModelFieldGroup >() {
303-
private final LinkedList< IModelFieldGroup > list = new LinkedList< IModelFieldGroup >( Arrays.asList( fields ) );
304+
private final Deque< IModelFieldGroup > list = new ArrayDeque< IModelFieldGroup >( Arrays.asList( fields ) );
304305
private final Set< String > visited = new HashSet< String >();
305306

306307
@Override
@@ -335,7 +336,7 @@ public IModelFieldGroup next() {
335336
*/
336337
public Iterable< IModelFieldGroup > getAllFieldGroupsFromTop( final boolean depthFirst ) {
337338
return new Iterable< IModelFieldGroup >() {
338-
private final LinkedList< IModelFieldGroup > list = new LinkedList< IModelFieldGroup >( fieldGroups.isEmpty() ? Collections.EMPTY_LIST : Arrays.asList( fieldGroups.get( 0 ) ) );
339+
private final Deque< IModelFieldGroup > list = new ArrayDeque< IModelFieldGroup >( fieldGroups.isEmpty() ? Collections.EMPTY_LIST : Arrays.asList( fieldGroups.get( 0 ) ) );
339340

340341
@Override
341342
public Iterator< IModelFieldGroup > iterator() {
@@ -348,8 +349,15 @@ public boolean hasNext() {
348349
@Override
349350
public IModelFieldGroup next() {
350351
IModelFieldGroup ret = list.pollFirst();
351-
if ( ret instanceof ModelFieldGroup )
352-
list.addAll( depthFirst ? 0 : list.size(), ( ( ModelFieldGroup )ret ).getChildren() );
352+
if ( ret instanceof ModelFieldGroup ) {
353+
if ( depthFirst ) {
354+
List< IModelFieldGroup > children = ( ( ModelFieldGroup )ret ).getChildren();
355+
for ( int i = children.size() - 1; i >= 0; i-- )
356+
list.addFirst( children.get( i ) );
357+
} else
358+
for ( IModelFieldGroup child : ( ( ModelFieldGroup )ret ).getChildren() )
359+
list.addLast( child );
360+
}
353361
return ret;
354362
}
355363
};

src/org/quinto/swing/table/view/JBroTableColumnModel.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package org.quinto.swing.table.view;
22

3+
import java.util.ArrayDeque;
34
import java.util.ArrayList;
5+
import java.util.Collection;
46
import java.util.Collections;
7+
import java.util.Deque;
58
import java.util.Enumeration;
69
import java.util.HashMap;
710
import java.util.HashSet;
8-
import java.util.LinkedList;
911
import java.util.List;
1012
import java.util.Map;
1113
import java.util.Set;
@@ -14,10 +16,10 @@
1416
import javax.swing.table.DefaultTableColumnModel;
1517
import javax.swing.table.TableColumn;
1618
import javax.swing.table.TableColumnModel;
19+
import org.quinto.swing.table.model.IModelFieldGroup;
1720
import org.quinto.swing.table.model.ModelData;
1821
import org.quinto.swing.table.model.ModelField;
1922
import org.quinto.swing.table.model.ModelFieldGroup;
20-
import org.quinto.swing.table.model.IModelFieldGroup;
2123

2224
public class JBroTableColumnModel extends DefaultTableColumnModel {
2325
private final List< List< JBroTableColumn > > columns = new ArrayList< List< JBroTableColumn > >();
@@ -127,8 +129,8 @@ public JBroTableColumn getColumnParent( JBroTableColumn column ) {
127129
return getTableColumn( parent );
128130
}
129131

130-
public List< JBroTableColumn > getColumnParents( JBroTableColumn column, boolean includeThis ) {
131-
LinkedList< JBroTableColumn > ret = new LinkedList< JBroTableColumn >();
132+
public Collection< JBroTableColumn > getColumnParents( JBroTableColumn column, boolean includeThis ) {
133+
Deque< JBroTableColumn > ret = new ArrayDeque< JBroTableColumn >();
132134
JBroTableColumn col = includeThis ? column : column == null ? null : getColumnParent( column );
133135
while ( col != null ) {
134136
ret.addFirst( col );

src/org/quinto/swing/table/view/JBroTableHeaderUI.java

+69-56
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import java.lang.reflect.InvocationTargetException;
1515
import java.lang.reflect.Method;
1616
import java.util.ArrayList;
17+
import java.util.Arrays;
18+
import java.util.Collection;
1719
import java.util.Enumeration;
1820
import java.util.HashMap;
1921
import java.util.List;
@@ -52,6 +54,7 @@ public class JBroTableHeaderUI extends BasicTableHeaderUI {
5254
private ComponentUI headerDelegate;
5355
private ReverseBorder lastBorder;
5456
private CustomTableHeaderRenderer customRenderer;
57+
private int heightsCache[];
5558

5659
public JBroTableHeaderUI( JBroTable table ) {
5760
this.table = table;
@@ -248,6 +251,7 @@ public void updateModel() {
248251
Method createUImethod = uiClass.getMethod( "createUI", JComponent.class );
249252
headerDelegate = ( ComponentUI )createUImethod.invoke( null, header );
250253
call( "installUI", new Class[]{ JComponent.class }, headerDelegate, new Object[]{ header } );
254+
Arrays.fill( heightsCache, -1 );
251255
for ( int level = delegates.size(); level < levelsCnt; level++ ) {
252256
ComponentUI delegate = ( ComponentUI )createUImethod.invoke( null, header );
253257
delegates.add( delegate );
@@ -277,6 +281,8 @@ public void installUI( JComponent c ) {
277281
delegates = new ArrayList< ComponentUI >( levelsCnt );
278282
headers = new ArrayList< JTableHeader >( levelsCnt );
279283
rendererPanes = new ArrayList< CellRendererPane >( levelsCnt );
284+
if ( heightsCache == null || heightsCache.length < levelsCnt )
285+
heightsCache = new int[ levelsCnt ];
280286
updateModel();
281287
super.installUI( c );
282288
SwingUtilities.updateComponentTreeUI( header );
@@ -308,22 +314,44 @@ public void paint( Graphics g, JComponent c ) {
308314
JBroTableColumnModel groupModel = getTableColumnModel();
309315
if ( groupModel == null )
310316
return;
317+
Rectangle clip = g.getClipBounds();
318+
Point left = clip.getLocation();
319+
Point right = new Point( clip.x + clip.width - 1, clip.y );
320+
int cMin = header.columnAtPoint( left );
321+
int cMax = header.columnAtPoint( right );
322+
int columnCount = groupModel.getColumnCount();
323+
if ( cMax < 0 || cMax >= columnCount ) {
324+
cMax = columnCount - 1;
325+
if ( cMin > cMax )
326+
cMin = cMax;
327+
}
328+
if ( cMin < 0 )
329+
cMin = 0;
311330
JBroTableHeader header = getHeader();
312331
int headerHeight = header.getSize().height;
313332
Rectangle cellRect = new Rectangle();
314333
JBroTableColumn draggedColumn = header.getDraggedGroup();
315-
Enumeration< TableColumn > enumeration = groupModel.getColumns();
316334
List< JBroTableColumn > currentColumns = new ArrayList< JBroTableColumn >();
317335
List< Integer > coords = new ArrayList< Integer >();
318336
currentColumns.add( null );
319337
boolean draggedColumnMet = false;
320-
while ( enumeration.hasMoreElements() ) {
321-
JBroTableColumn column = ( JBroTableColumn )enumeration.nextElement();
322-
List< JBroTableColumn > columnParents = groupModel.getColumnParents( column, true );
338+
int calcStartXFrom = 0;
339+
for ( int cIdx = cMin; cIdx <= cMax; cIdx++ ) {
340+
JBroTableColumn column = groupModel.getColumn( cIdx );
341+
Collection< JBroTableColumn > columnParents = groupModel.getColumnParents( column, true );
323342
int level = 0;
324343
boolean addAbsent = false;
325344
boolean doNotPaintCells = draggedColumnMet && columnParents.contains( draggedColumn );
345+
boolean firstColumnParentsNeedToBeRepainted = cIdx == cMin && cMin > 0;
326346
for ( JBroTableColumn columnParent : columnParents ) {
347+
if ( firstColumnParentsNeedToBeRepainted ) {
348+
int calcStartXTo = groupModel.getColumnAbsoluteIndex( columnParent );
349+
for ( int i = calcStartXFrom; i < calcStartXTo; i++ ) {
350+
JBroTableColumn col = groupModel.getColumn( i );
351+
cellRect.x += col.getWidth();
352+
}
353+
calcStartXFrom = calcStartXTo;
354+
}
327355
if ( !addAbsent ) {
328356
JBroTableColumn currentColumn = currentColumns.get( level );
329357
if ( columnParent != currentColumn ) {
@@ -338,10 +366,11 @@ public void paint( Graphics g, JComponent c ) {
338366
if ( addAbsent ) {
339367
currentColumns.add( columnParent );
340368
cellRect.y = coords.isEmpty() ? 0 : coords.get( coords.size() - 1 );
341-
Dimension cellSize = getGroupSize( columnParent );
369+
cellRect.width = getGroupWidth( columnParent );
342370
if ( columnParent == column )
343-
cellSize.height = headerHeight - cellRect.y;
344-
cellRect.setSize( cellSize );
371+
cellRect.height = headerHeight - cellRect.y;
372+
else
373+
cellRect.height = getGroupHeight( columnParent );
345374
if ( draggedColumn == columnParent ) {
346375
g.setColor( header.getParent().getBackground() );
347376
g.fillRect( cellRect.x, cellRect.y, cellRect.width, headerHeight - cellRect.y );
@@ -350,7 +379,7 @@ public void paint( Graphics g, JComponent c ) {
350379
} else if ( !doNotPaintCells )
351380
paintCell( g, cellRect, columnParent );
352381
if ( columnParent != column ) {
353-
cellRect.y += cellSize.height;
382+
cellRect.y += cellRect.height;
354383
coords.add( cellRect.y );
355384
}
356385
}
@@ -451,62 +480,45 @@ private void paintCell( Graphics g, Rectangle cellRect, JBroTableColumn group )
451480
paintCell( g, comp, cellRect );
452481
}
453482

454-
public Dimension getGroupSize( JBroTableColumn group ) {
455-
Dimension size = new Dimension();
483+
public int getGroupHeight( JBroTableColumn group ) {
484+
int height = 0;
485+
for ( int level = group.getY(); level < group.getY() + group.getRowspan(); level++ )
486+
height += getRowHeight( level );
487+
return height;
488+
}
489+
490+
public int getGroupWidth( JBroTableColumn group ) {
491+
int width = 0;
456492
JBroTableColumnModel groupModel = getTableColumnModel();
457-
for ( int level = group.getY(); level < group.getY() + group.getRowspan(); level++ ) {
458-
if ( rowHeights != null && rowHeights.size() > level ) {
459-
Integer height = rowHeights.get( level );
460-
if ( height != null ) {
461-
size.height += height;
462-
continue;
463-
}
464-
}
465-
TableCellRenderer renderer = headers.get( level ).getDefaultRenderer();
466-
Component comp = renderer.getTableCellRendererComponent( header.getTable(), group.getHeaderValue(), false, false, -1, -1 );
467-
size.height += comp.getPreferredSize().height;
468-
}
469493
List< JBroTableColumn > children = groupModel.getColumnChildren( group );
470494
if ( children.isEmpty() )
471-
size.width = group.getWidth();
495+
width = group.getWidth();
472496
else
473497
for ( JBroTableColumn column : children )
474-
size.width += groupModel.getWidth( column );
475-
return size;
498+
width += groupModel.getWidth( column );
499+
return width;
500+
}
501+
502+
public Dimension getGroupSize( JBroTableColumn group ) {
503+
return new Dimension( getGroupWidth( group ), getGroupHeight( group ) );
476504
}
477505

478506
private int calculateHeaderHeight() {
479-
int mHeight = 0;
480-
JBroTableColumnModel groupModel = getTableColumnModel();
481-
for ( int column = 0; column < groupModel.getColumnCount(); column++ ) {
482-
int cHeight = 0;
483-
JBroTableColumn parent = groupModel.getColumn( column );
484-
while ( parent != null ) {
485-
for ( int level = parent.getY(); level < parent.getY() + parent.getRowspan(); level++ ) {
486-
if ( rowHeights != null && rowHeights.size() > level ) {
487-
Integer height = rowHeights.get( level );
488-
if ( height != null ) {
489-
cHeight += height;
490-
continue;
491-
}
492-
}
493-
TableCellRenderer renderer = headers.get( level ).getDefaultRenderer();
494-
Component comp = renderer.getTableCellRendererComponent( header.getTable(), parent.getHeaderValue(), false, false, -1, column );
495-
cHeight += comp.getPreferredSize().height;
496-
}
497-
parent = groupModel.getColumnParent( parent );
498-
}
499-
mHeight = Math.max( mHeight, cHeight );
500-
}
501-
return mHeight;
507+
int height = 0;
508+
int levelsCnt = table.getData() == null ? 0 : table.getData().getFieldGroups().size();
509+
for ( int level = 0; level < levelsCnt; level++ )
510+
height += getRowHeight( level );
511+
return height;
502512
}
503513

504514
public int getRowHeight( int level ) {
505-
int extra = level == headers.size() - 1 ? getHeader().getPreferredSize().height - calculateHeaderHeight() : 0;
515+
int ret = heightsCache[ level ];
516+
if ( ret >= 0 )
517+
return ret;
506518
if ( rowHeights != null && rowHeights.size() > level ) {
507519
Integer height = rowHeights.get( level );
508520
if ( height != null )
509-
return extra + height;
521+
return heightsCache[ level ] = height;
510522
}
511523
int mHeight = 0;
512524
JBroTableColumnModel groupModel = getTableColumnModel();
@@ -521,7 +533,7 @@ public int getRowHeight( int level ) {
521533
parent = groupModel.getColumnParent( parent );
522534
}
523535
}
524-
return extra + mHeight;
536+
return heightsCache[ level ] = mHeight;
525537
}
526538

527539
@Override
@@ -673,6 +685,7 @@ public void setRowHeight( int level, Integer height ) {
673685
while ( rowHeights.size() <= level )
674686
rowHeights.add( null );
675687
rowHeights.set( level, height );
688+
heightsCache[ level ] = -1;
676689
}
677690

678691
public Rectangle getGroupHeaderBoundsFor( JBroTableColumn group ) {
@@ -683,7 +696,7 @@ public Rectangle getGroupHeaderBoundsFor( JBroTableColumn group ) {
683696
Rectangle bounds = new Rectangle( size );
684697
bounds.y = 0;
685698
for ( JBroTableColumn parent : columnModel.getColumnParents( group, false ) )
686-
bounds.y += getGroupSize( parent ).height;
699+
bounds.y += getGroupHeight( parent );
687700
int lastColumnIndex = columnModel.getColumnIndex( group.getIdentifier() );
688701
for ( int index = 0; index < lastColumnIndex; index++ ) {
689702
JBroTableColumn tc = columnModel.getColumn( index );
@@ -780,9 +793,9 @@ public void mousePressed( MouseEvent e ) {
780793
if ( canResize( point, resizingColumn, header ) ) {
781794
header.setResizingColumn( resizingColumn );
782795
if ( header.getComponentOrientation().isLeftToRight() )
783-
mouseXOffset = point.x - getGroupSize( resizingColumn ).width;
796+
mouseXOffset = point.x - getGroupWidth( resizingColumn );
784797
else
785-
mouseXOffset = point.x + getGroupSize( resizingColumn ).width;
798+
mouseXOffset = point.x + getGroupWidth( resizingColumn );
786799
} else if ( header.getReorderingAllowed() ) {
787800
JBroTableColumn column = getColumnAtPoint( point );
788801
if ( column != null ) {
@@ -868,7 +881,7 @@ public void mouseDragged( MouseEvent e ) {
868881
shouldMove = false;
869882
}
870883
if ( shouldMove ) {
871-
int width = getGroupSize( newGroup ).width;
884+
int width = getGroupWidth( newGroup );
872885
int groupStartIndex = groupModel.getColumnAbsoluteIndex( newGroup );
873886
int groupEndIndex = newGroup.getColspan() + groupStartIndex - 1;
874887
if ( direction < 0 )
@@ -895,7 +908,7 @@ public void mouseDragged( MouseEvent e ) {
895908
} else if ( resizingColumn != null ) {
896909
// TODO: child column resizing should affect only columns inside a parent group.
897910
// TODO: parent column resizing should proportionally affect all child columns.
898-
int oldWidth = getGroupSize( resizingColumn ).width;
911+
int oldWidth = getGroupWidth( resizingColumn );
899912
int newWidth;
900913
if ( headerLeftToRight )
901914
newWidth = mouseX - mouseXOffset;

0 commit comments

Comments
 (0)