4949import java .awt .event .MouseEvent ;
5050import java .beans .PropertyChangeEvent ;
5151import java .beans .PropertyChangeListener ;
52+ import java .util .BitSet ;
5253import java .util .Enumeration ;
5354
5455import javax .swing .Action ;
@@ -107,7 +108,7 @@ public class JSTableUI extends JSPanelUI {
107108 private int oldWidth ;
108109 private int oldHeight ;
109110 private Object oldFont ;
110-
111+
111112 private boolean isScrolling , justLaidOut ;
112113
113114 public void setScrolling () {
@@ -134,7 +135,7 @@ public DOMNode updateDOMNode() {
134135 if (domNode == null ) {
135136 domNode = newDOMObject ("div" , id );
136137 enableJSKeys (true );
137- DOMNode .setStyles (domNode , "outline" , "none" );
138+ DOMNode .setStyle (domNode , "outline" , "none" );
138139 // bindJSKeyEvents(domNode, true);
139140 }
140141 if (rebuild ) {
@@ -319,7 +320,7 @@ protected void addChildrenToDOM(Component[] children, int n) {
319320 havePainted = false ;
320321 int ncols = table .getColumnCount ();
321322 int rowCount = table .getRowCount ();
322- int [] cw = getColumnWidths ();
323+ getColumnWidths (true );
323324 int rminy , rmaxy , rminx , rmaxx ;
324325 table .computeVisibleRect (tmpRect );
325326 rminx = tmpRect .x ;
@@ -340,24 +341,37 @@ protected void addChildrenToDOM(Component[] children, int n) {
340341 rmaxy = tmpRect .y + tmpRect .height ;
341342 if (tmpRect .height != 0 ) {
342343 currentRowMin = 0 ;
343- addElements (rminx , rminy , rmaxx , rmaxy , cw , h , 0 , rowCount , 0 , ncols );
344+ addElements (rminx , rminy , rmaxx , rmaxy , h , 0 , rowCount , 0 , ncols );
344345 }
345346 }
346347 }
347348
348349 private void setHidden (boolean b ) {
349- DOMNode .setStyles (domNode , "visibility" , b ? "hidden" : "visible" );
350+ DOMNode .setStyle (domNode , "visibility" , b ? "hidden" : "visible" );
350351 }
351352
352353 private int [] cw = new int [10 ];
353-
354- private int [] getColumnWidths () {
354+ private int [] cwOld = new int [10 ];
355+
356+ private void getColumnWidths (boolean isNew ) {
355357 int ncols = table .getColumnCount ();
356- if (ncols > cw .length )
358+ if (ncols > cw .length ) {
357359 cw = new int [ncols ];
358- for (int col = 0 ; col < ncols ; col ++)
359- cw [col ] = table .getColumnModel ().getColumn (col ).getWidth ();
360- return cw ;
360+ cwOld = new int [ncols ];
361+ }
362+ if (isNew )
363+ bsRowTainted .clear ();
364+ boolean colTainted = false ;
365+ TableColumnModel cm = table .getColumnModel ();
366+ for (int col = 0 ; col < ncols ; col ++) {
367+ int w = cw [col ] = cm .getColumn (col ).getWidth ();
368+ if (!isNew && cwOld [col ] != w ) {
369+ colTainted = true ;
370+ }
371+ cwOld [col ] = w ;
372+ }
373+ if (colTainted )
374+ bsRowTainted .set (0 , table .getRowCount ());
361375 }
362376
363377 /**
@@ -375,7 +389,7 @@ private int[] getColumnWidths() {
375389 * @param col1
376390 * @param col2
377391 */
378- private DOMNode addElements (int rminx , int rminy , int rmaxx , int rmaxy , int [] cw , int h , int row1 , int row2 ,
392+ private DOMNode addElements (int rminx , int rminy , int rmaxx , int rmaxy , int h , int row1 , int row2 ,
379393 int col1 , int col2 ) {
380394 int col , tx0 ;
381395 for (col = 0 , tx0 = 0 ; col < col1 ; tx0 += cw [col ++]) {
@@ -385,13 +399,15 @@ private DOMNode addElements(int rminx, int rminy, int rmaxx, int rmaxy, int[] cw
385399 if (ty + h < rminy )
386400 continue ;
387401 String rid = id + "_tab_row" + row ;
402+ // Note that rows will end up in unpredictable order, but that does not matter.
403+ // All that matters is that they have the right y and height value.
388404 DOMNode tr = DOMNode .getElement (rid );
389405 boolean rowExists = (tr != null );
390406 if (!rowExists ) {
391407 tr = DOMNode .createElement ("div" , rid );
392408 domNode .appendChild (tr );
393409 }
394- DOMNode .setStyles (tr , "height" , h + "px" );
410+ DOMNode .setStyle (tr , "height" , h + "px" );
395411 col = col1 ;
396412 for (int w , tx = tx0 ; col < col2 && tx < rmaxx ; col ++, tx += w ) {
397413 w = cw [col ];
@@ -402,7 +418,7 @@ private DOMNode addElements(int rminx, int rminy, int rmaxx, int rmaxy, int[] cw
402418 td = CellHolder .createCellOuterNode (this , row , col );
403419 tr .appendChild (td );
404420 }
405- DOMNode .setStyles (td , "width " , w + "px" , "height " , h + "px" , "left " , tx + "px " , "top" , ty + "px" );
421+ DOMNode .setStyles (td , "left " , tx + "px" , "width " , w + "px" , "height " , "inherit " , "top" , ty + "px" );
406422 updateCellNode (td , row , col , w , h );
407423 if (rminx < 0 )
408424 return td ;
@@ -2114,15 +2130,18 @@ public void paint(Graphics g, JComponent c) {
21142130 // or from JComponent.paintComponent (initially, or from resize, for instance)
21152131
21162132 //table.getFillsViewportHeight();
2117- Rectangle clip = getClip ();
21182133 int rc = table .getRowCount ();
2134+ int cc = table .getColumnCount ();
2135+ checkRemoveCells (rc , cc );
2136+ // 2020.08.04 g.getClipBounds works now, no need for the hack.
2137+ Rectangle clip = g .getClipBounds (myClip );
21192138 int rh = table .getRowHeight ();
21202139 if (getScrollPane () != null ) {
21212140 DOMNode .setStyles (outerNode , "overflow" , "hidden" , "height" , (rc * rh ) + "px" );
21222141 }
21232142 table .computeVisibleRect (tmpRect );
21242143
2125- if (rc <= 0 || table . getColumnCount () <= 0 ||
2144+ if (rc <= 0 || cc <= 0 ||
21262145 // this check prevents us from painting the entire table
21272146 // when the clip doesn't intersect our bounds at all
21282147 !tmpRect .intersects (clip )) {
@@ -2226,67 +2245,108 @@ public void paint(Graphics g, JComponent c) {
22262245 setHidden (false );
22272246 }
22282247
2229- private Rectangle myClip = new Rectangle ();
2230- private Rectangle getClip () {
2231- if (table .parent instanceof JViewport ) {
2232- JSViewportUI ui = ((JSViewportUI )table .parent .getUI ());
2233- if (isNewModel ) {
2234- ui .myClip .x = ui .myClip .y = 0 ;
2235- isNewModel = false ;
2248+ private int lastRowCount , lastColCount ;
2249+
2250+ private void checkRemoveCells (int nrows , int ncols ) {
2251+ if (nrows < lastRowCount ) {
2252+ // remove all missing rows
2253+ for (int r = nrows ; r < lastRowCount ; r ++) {
2254+ DOMNode node = CellHolder .findCellNode (this , null , r , -1 );
2255+ if (node != null ) {
2256+ DOMNode .remove (node );
2257+ }
22362258 }
2237- return ui .myClip ;
22382259 }
2239- myClip .width = table .getWidth ();
2240- myClip .height = table .getHeight ();
2241- return myClip ;
2260+ if (ncols < lastColCount ) {
2261+ // remove all extra columns for visible rows only
2262+ for (int r = 0 ; r < nrows ; r ++) {
2263+ for (int c = ncols ; c < lastColCount ; c ++) {
2264+ DOMNode node = CellHolder .findCellNode (this , null , r , c );
2265+ if (node != null ) {
2266+ DOMNode .remove (node );
2267+ // if (j == 0)
2268+ // bsRowTainted.set(i);
2269+ // DOMNode.setVisible(node, false);
2270+ }
2271+ }
2272+ }
2273+ }
2274+ lastColCount = ncols ;
2275+ lastRowCount = nrows ;
22422276 }
22432277
2278+ private Rectangle myClip = new Rectangle ();
2279+ // private Rectangle getClip(Graphics g) {
2280+ // if (table.parent instanceof JViewport) {
2281+ //// abandoned -- not necessary
2282+ // JSViewportUI ui = ((JSViewportUI)table.parent.getUI());
2283+ // if (isNewModel) {
2284+ // ui.myClip.x = ui.myClip.y = 0;
2285+ // isNewModel = false;
2286+ // }
2287+ // return ui.myClip;
2288+ // } else {
2289+ // myClip.width = table.getWidth();
2290+ // myClip.height = table.getHeight();
2291+ // }
2292+ // return myClip;
2293+ // }
2294+
2295+ /**
2296+ * In SwingJS, track when columns have been resized so that we can ensure that, when cells
2297+ * are painted, their TD elements are correctly positioned and sized.
2298+ */
2299+ private BitSet bsRowTainted = new BitSet ();
2300+
22442301 private void paintCells (Graphics g , int rMin0 , int rMax0 , int rMin , int rMax , int cMin , int cMax ) {
22452302 TableColumnModel cm = table .getColumnModel ();
22462303 int columnMargin = cm .getColumnMargin ();
22472304
22482305 int h = table .getRowHeight ();
2249- int [] cw = getColumnWidths ();
2306+
2307+ boolean forceNew = (dragging || justLaidOut );
22502308
2251- TableColumn aColumn ;
2309+ getColumnWidths ( false ) ;
22522310 int columnWidth ;
22532311
2254- boolean forceNew = (dragging || justLaidOut );// || rMin == rMax && cMin == cMax);
2255-
22562312 if (table .getComponentOrientation ().isLeftToRight ()) {
22572313 for (int row = rMin0 ; row <= rMax0 ; row ++) {
22582314 table ._getCellRect (row , cMin , false , cellRect );
2315+ boolean colTainted = bsRowTainted .get (row );
22592316 DOMNode tr = DOMNode .getElement (id + "_tab_row" + row );
22602317 for (int column = cMin ; column <= cMax ; column ++) {
2261- aColumn = cm .getColumn (column );
2262- columnWidth = aColumn .getWidth ();
2318+ columnWidth = cw [column ];
22632319 cellRect .width = columnWidth - columnMargin ;
22642320// if (aColumn != draggedColumn) {
2265- paintCell (g , cellRect , row , column , cw , h , tr , forceNew );
2321+ paintCell (g , cellRect , row , column , h , tr , forceNew , colTainted );
22662322// }
22672323 cellRect .x += columnWidth ;
22682324 }
2325+ if (colTainted )
2326+ bsRowTainted .clear (row );
22692327 }
22702328 } else {
22712329 for (int row = rMin0 ; row <= rMax0 ; row ++) {
22722330 table ._getCellRect (row , cMin , false , cellRect );
2273- aColumn = cm .getColumn (cMin );
2331+ // aColumn = cm.getColumn(cMin);
22742332// if (aColumn != draggedColumn) {
22752333// columnWidth = aColumn.getWidth();
22762334// cellRect.width = columnWidth - columnMargin;
22772335// paintCell(g, cellRect, row, cMin, cw, h);
22782336// }
22792337 DOMNode tr = DOMNode .getElement (id + "_tab_row" + row );
2338+ boolean colTainted = bsRowTainted .get (row );
22802339 for (int column = cMin ; column <= cMax ; column ++) {
2281- aColumn = cm .getColumn (column );
2282- columnWidth = aColumn .getWidth ();
2340+ columnWidth = cw [column ];
22832341 cellRect .width = columnWidth - columnMargin ;
22842342 if (column != cMin )
22852343 cellRect .x -= columnWidth ;
22862344// if (aColumn != draggedColumn) {
2287- paintCell (g , cellRect , row , column , cw , h , tr , forceNew );
2345+ paintCell (g , cellRect , row , column , h , tr , forceNew , colTainted );
22882346// }
22892347 }
2348+ if (colTainted )
2349+ bsRowTainted .clear (row );
22902350 }
22912351 }
22922352
@@ -2304,8 +2364,8 @@ private void paintCells(Graphics g, int rMin0, int rMax0, int rMin, int rMax, in
23042364 havePainted = true ;
23052365 }
23062366
2307- private void paintCell (Graphics g , Rectangle cellRect , int row , int col , int [] cw , int h , DOMNode tr ,
2308- boolean forceNew ) {
2367+ private void paintCell (Graphics g , Rectangle cellRect , int row , int col , int h , DOMNode tr ,
2368+ boolean forceNew , boolean colTainted ) {
23092369
23102370 if (table .isEditing () && table .getEditingRow () == row && table .getEditingColumn () == col ) {
23112371 Component component = table .getEditorComponent ();
@@ -2319,8 +2379,12 @@ private void paintCell(Graphics g, Rectangle cellRect, int row, int col, int[] c
23192379 DOMNode td = (forceNew || tr == null ? null : CellHolder .findCellNode (this , null , row , col ));
23202380 boolean newtd = (td == null );
23212381 if (newtd ) {
2322- td = addElements (Integer .MIN_VALUE , Integer .MIN_VALUE , Integer .MAX_VALUE , Integer .MAX_VALUE , cw , h , row ,
2382+ td = addElements (Integer .MIN_VALUE , Integer .MIN_VALUE , Integer .MAX_VALUE , Integer .MAX_VALUE , h , row ,
23232383 row + 1 , col , col + 1 );
2384+ } else if (colTainted ) {
2385+ DOMNode .setStyles (td , "left" , cellRect .x + "px" , "width" , cw [col ] + "px" , "display" , null );
2386+ } else {
2387+ DOMNode .setStyle (td , "display" , null );
23242388 }
23252389 boolean fullPaint = (newtd || !havePainted || !isScrolling || table .getSelectedRowCount () > 0 );
23262390 TableCellRenderer renderer = (fullPaint ? table .getCellRenderer (row , col )
0 commit comments