1010import java .awt .Toolkit ;
1111import java .util .Arrays ;
1212import java .util .HashMap ;
13+ import java .util .IdentityHashMap ;
1314import java .util .LinkedHashMap ;
1415import java .util .Map ;
1516import java .util .Set ;
@@ -439,6 +440,21 @@ void setNoDefaults( boolean noDefaults ) {
439440 this .noDefaults = noDefaults ;
440441 }
441442
443+ /**
444+ * Get span bounds in pixels.
445+ * @param col any column of span
446+ * @param row any row of span
447+ * @param includeSpacing if false, return the true cell bounds
448+ * computed by subtracting the intercell spacing from the height
449+ * and widths of the column and row models
450+ * @return span bounds in pixels
451+ * @see javax.swing.JTable#getCellRect
452+ */
453+ public Rectangle getSpanCoordinatesInPixels ( int col , int row , boolean includeSpacing ) {
454+ Rectangle rect = getSpanCoordinates ( col , row );
455+ return table .getCellRect ( rect .y , rect .x , includeSpacing ).union ( table .getCellRect ( rect .y + rect .height - 1 , rect .x + rect .width - 1 , includeSpacing ) );
456+ }
457+
442458 /**
443459 * Find a span at position ( col, row ). Return its starting point and size in cells.
444460 * The value returned is <b>not</b> the span bounds in pixels.
@@ -449,72 +465,138 @@ void setNoDefaults( boolean noDefaults ) {
449465 */
450466 public Rectangle getSpanCoordinates ( int col , int row ) {
451467 Rectangle ret = new Rectangle ( col , row , 1 , 1 );
452- if ( col < 0 || row < 0 )
468+ SpanWithId spanWithId = getSpanWithId ( col , row );
469+ if ( spanWithId == null )
453470 return ret ;
454471 TableColumnModel cm = table .getColumnModel ();
472+ int columnCount = cm .getColumnCount ();
473+ int rowCount = table .getRowCount ();
474+ ModelData data = ( ( JBroTable )table ).getData ();
475+ int minRow = row ;
476+ for ( int i = row - 1 ; i >= 0 ; i -- ) {
477+ if ( spanWithId .id .equals ( data .getValue ( table .convertRowIndexToModel ( i ), spanWithId .idColumnIdx ) ) )
478+ minRow = i ;
479+ else
480+ break ;
481+ }
482+ int maxRow = row ;
483+ for ( int i = row + 1 ; i < rowCount ; i ++ ) {
484+ if ( spanWithId .id .equals ( data .getValue ( table .convertRowIndexToModel ( i ), spanWithId .idColumnIdx ) ) )
485+ maxRow = i ;
486+ else
487+ break ;
488+ }
489+ Set < String > columns = spanWithId .span .getColumns ();
490+ int minCol = col ;
491+ for ( int i = col - 1 ; i >= 0 ; i -- ) {
492+ TableColumn spanCoveredColumn = cm .getColumn ( i );
493+ if ( columns .contains ( ( String )spanCoveredColumn .getIdentifier () ) )
494+ minCol = i ;
495+ else
496+ break ;
497+ }
498+ int maxCol = col ;
499+ for ( int i = col + 1 ; i < columnCount ; i ++ ) {
500+ TableColumn spanCoveredColumn = cm .getColumn ( i );
501+ if ( columns .contains ( ( String )spanCoveredColumn .getIdentifier () ) )
502+ maxCol = i ;
503+ else
504+ break ;
505+ }
506+ ret .setBounds ( minCol , minRow , maxCol - minCol + 1 , maxRow - minRow + 1 );
507+ return ret ;
508+ }
509+
510+ public ModelSpan getSpan ( int col , int row ) {
511+ SpanWithId spanWithId = getSpanWithId ( col , row );
512+ return spanWithId == null ? null : spanWithId .span ;
513+ }
514+
515+ public Object getSpanValue ( int col , int row ) {
516+ ModelSpan span = getSpan ( col , row );
517+ if ( span == null )
518+ return table .getValueAt ( col , row );
519+ int modelRow = table .convertRowIndexToModel ( row );
520+ ModelData data = ( ( JBroTable )table ).getData ();
521+ return data .getValue ( modelRow , span .getValueColumn () );
522+ }
523+
524+ private SpanWithId getSpanWithId ( int col , int row ) {
525+ if ( col < 0 || row < 0 )
526+ return null ;
527+ TableColumnModel cm = table .getColumnModel ();
455528 if ( cm == null )
456- return ret ;
529+ return null ;
457530 int columnCount = cm .getColumnCount ();
458531 if ( col >= columnCount )
459- return ret ;
532+ return null ;
460533 TableColumn aColumn = cm .getColumn ( col );
461534 if ( aColumn == null )
462- return ret ;
535+ return null ;
463536 String columnName = ( String )aColumn .getIdentifier ();
464537 Map < String , ModelSpan > columnSpans = spans .get ( columnName );
465538 if ( columnSpans == null )
466- return ret ;
539+ return null ;
467540 int rowCount = table .getRowCount ();
468541 if ( row >= rowCount )
469- return ret ;
542+ return null ;
470543 int modelRow = table .convertRowIndexToModel ( row );
471544 if ( modelRow < 0 )
472- return ret ;
545+ return null ;
473546 ModelData data = ( ( JBroTable )table ).getData ();
474547 if ( data == null || modelRow >= data .getRowsCount () )
475- return ret ;
548+ return null ;
476549 for ( Map .Entry < String , ModelSpan > spanWithId : columnSpans .entrySet () ) {
477550 int idColumnIdx = data .getIndexOfModelField ( spanWithId .getKey () );
478551 if ( idColumnIdx < 0 )
479552 continue ;
480553 Object id = data .getValue ( modelRow , idColumnIdx );
481554 if ( id == null )
482555 continue ;
483- int minRow = row ;
484- for ( int i = row - 1 ; i >= 0 ; i -- ) {
485- if ( id .equals ( data .getValue ( table .convertRowIndexToModel ( i ), idColumnIdx ) ) )
486- minRow = i ;
487- else
488- break ;
489- }
490- int maxRow = row ;
491- for ( int i = row + 1 ; i < rowCount ; i ++ ) {
492- if ( id .equals ( data .getValue ( table .convertRowIndexToModel ( i ), idColumnIdx ) ) )
493- maxRow = i ;
494- else
495- break ;
496- }
497- ModelSpan span = spanWithId .getValue ();
498- Set < String > columns = span .getColumns ();
499- int minCol = col ;
500- for ( int i = col - 1 ; i >= 0 ; i -- ) {
501- TableColumn spanCoveredColumn = cm .getColumn ( i );
502- if ( columns .contains ( ( String )spanCoveredColumn .getIdentifier () ) )
503- minCol = i ;
504- else
505- break ;
506- }
507- int maxCol = col ;
508- for ( int i = col + 1 ; i < columnCount ; i ++ ) {
509- TableColumn spanCoveredColumn = cm .getColumn ( i );
510- if ( columns .contains ( ( String )spanCoveredColumn .getIdentifier () ) )
511- maxCol = i ;
512- else
513- break ;
556+ return new SpanWithId ( spanWithId .getValue (), id , idColumnIdx );
557+ }
558+ return null ;
559+ }
560+
561+ public Iterable < ModelSpan > getSpans () {
562+ IdentityHashMap < ModelSpan , String > ret = new IdentityHashMap < ModelSpan , String >();
563+ for ( Map < String , ModelSpan > value : spans .values () )
564+ for ( ModelSpan span : value .values () )
565+ ret .put ( span , null );
566+ return ret .keySet ();
567+ }
568+
569+ void onRowsSelected ( int firstIndex , int lastIndex ) {
570+ if ( spans .isEmpty () )
571+ return ;
572+ int rc = table .getRowCount ();
573+ int cc = table .getColumnCount ();
574+ firstIndex = Math .min ( Math .max ( firstIndex , 0 ), rc - 1 );
575+ lastIndex = Math .min ( Math .max ( lastIndex , 0 ), rc - 1 );
576+ Rectangle firstRowRect = table .getCellRect ( firstIndex , 0 , false );
577+ Rectangle lastRowRect = table .getCellRect ( lastIndex , cc - 1 , false );
578+ Rectangle dirtyRegion = firstRowRect .union ( lastRowRect );
579+ for ( int s = 0 ; s < 2 ; s ++ ) {
580+ for ( int i = cc - 1 ; i >= 0 ; i -- ) {
581+ Rectangle rect = getSpanCoordinates ( i , s == 0 ? firstIndex : lastIndex );
582+ if ( rect .width > 1 || rect .height > 1 ) {
583+ dirtyRegion = dirtyRegion .union ( table .getCellRect ( rect .y , rect .x , false ) );
584+ dirtyRegion = dirtyRegion .union ( table .getCellRect ( rect .y + rect .height - 1 , rect .x + rect .width - 1 , false ) );
585+ }
514586 }
515- ret .setBounds ( minCol , minRow , maxCol - minCol + 1 , maxRow - minRow + 1 );
516- break ;
517587 }
518- return ret ;
588+ table .repaint ( dirtyRegion );
589+ }
590+
591+ private static class SpanWithId {
592+ private final ModelSpan span ;
593+ private final Object id ;
594+ private final int idColumnIdx ;
595+
596+ public SpanWithId ( ModelSpan span , Object id , int idColumnIdx ) {
597+ this .span = span ;
598+ this .id = id ;
599+ this .idColumnIdx = idColumnIdx ;
600+ }
519601 }
520602}
0 commit comments