package org.gudy.azureus2.ui.swt.views.table.painted; import java.util.LinkedHashMap; import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.gudy.azureus2.core3.config.ParameterListener; import org.gudy.azureus2.core3.util.*; import org.gudy.azureus2.plugins.ui.tables.TableCell; import org.gudy.azureus2.plugins.ui.tables.TableColumn; import org.gudy.azureus2.ui.swt.Utils; import org.gudy.azureus2.ui.swt.mainwindow.Colors; import org.gudy.azureus2.ui.swt.shells.GCStringPrinter; import org.gudy.azureus2.ui.swt.views.table.TableCellSWT; import org.gudy.azureus2.ui.swt.views.table.TableViewSWT; import org.gudy.azureus2.ui.swt.views.table.impl.TableCellSWTBase; import org.gudy.azureus2.ui.swt.views.table.impl.TableRowSWTBase; import org.gudy.azureus2.ui.swt.views.table.utils.TableColumnSWTUtils; import com.aelitis.azureus.ui.common.table.TableCellCore; import com.aelitis.azureus.ui.common.table.TableColumnCore; import com.aelitis.azureus.ui.common.table.TableRowCore; import com.aelitis.azureus.ui.swt.utils.FontUtils; public class TableRowPainted extends TableRowSWTBase { private static final boolean DEBUG_SUBS = true; private Point drawOffset = new Point(0, 0); private int numSubItems; private Object[] subDataSources; private TableRowPainted[] subRows; private Object subRows_sync; private int subRowsHeight; private TableCellCore cellSort; final static public Color[] alternatingColors = new Color[] { null, Colors.colorAltRow }; static{ Colors.getInstance().addColorsChangedListener( new ParameterListener() { public void parameterChanged(String parameterName) { alternatingColors[1] = Colors.colorAltRow; } }); } private int height = 0; private boolean initializing = true; private Color colorFG = null; public TableRowPainted(TableRowCore parentRow, TableViewPainted tv, Object dataSource, boolean triggerHeightChange) { // in theory, TableRowPainted could have its own sync // but in practice, I end up calling code within the sync which inevitably // calls the TableView and causes locks. So, use the TableView's sync! super(tv.getSyncObject(), parentRow, tv, dataSource); subRows_sync = tv.getSyncObject(); TableColumnCore sortColumn = tv.getSortColumn(); if (sortColumn != null && (parentRow == null || sortColumn.handlesDataSourceType(getDataSource( false).getClass()))) { cellSort = new TableCellPainted(TableRowPainted.this, sortColumn, sortColumn.getPosition()); } if (height == 0) { setHeight(tv.getRowDefaultHeight(), false); } initializing = false; if (triggerHeightChange) { heightChanged(0, height); } } private void buildCells() { //debug("buildCells " + Debug.getCompressedStackTrace()); TableColumnCore[] visibleColumns = getView().getVisibleColumns(); if (visibleColumns == null) { return; } synchronized (lock) { mTableCells = new LinkedHashMap<String, TableCellCore>( visibleColumns.length, 1); TableColumn currentSortColumn = null; if (cellSort != null) { currentSortColumn = cellSort.getTableColumn(); } TableRowCore parentRow = getParentRowCore(); // create all the cells for the column for (int i = 0; i < visibleColumns.length; i++) { if (visibleColumns[i] == null) { continue; } if (parentRow != null && !visibleColumns[i].handlesDataSourceType(getDataSource(false).getClass())) { mTableCells.put(visibleColumns[i].getName(), null); continue; } //System.out.println(dataSource + ": " + tableColumns[i].getName() + ": " + tableColumns[i].getPosition()); TableCellCore cell = (currentSortColumn != null && visibleColumns[i].equals(currentSortColumn)) ? cellSort : new TableCellPainted(TableRowPainted.this, visibleColumns[i], i); mTableCells.put(visibleColumns[i].getName(), cell); //if (i == 10) cell.bDebug = true; } } } private void destroyCells() { synchronized (lock) { if (mTableCells != null) { for (TableCellCore cell : mTableCells.values()) { if (cell != null && cell != cellSort) { if ( !cell.isDisposed()){ cell.dispose(); } } } mTableCells = null; } } } public TableViewPainted getViewPainted() { return (TableViewPainted) getView(); } /** * @param gc GC to draw to * @param drawBounds Area that needs redrawing * @param rowStartX where in the GC this row's x-axis starts * @param rowStartY where in the GC this row's y-axis starts * @param pos */ public void swt_paintGC(GC gc, Rectangle drawBounds, int rowStartX, int rowStartY, int pos) { if (isRowDisposed() || gc == null || gc.isDisposed() || drawBounds == null) { return; } // done by caller //if (!drawBounds.intersects(rowStartX, rowStartY, 9999, getHeight())) { // return; //} TableColumnCore[] visibleColumns = getView().getVisibleColumns(); if (visibleColumns == null || visibleColumns.length == 0) { return; } boolean isSelected = isSelected(); boolean isSelectedNotFocused = isSelected && !getViewPainted().isTableSelected(); Color origBG = gc.getBackground(); Color origFG = gc.getForeground(); Color altColor = alternatingColors[pos >= 0 ? pos % 2 : 0]; if (altColor == null) { altColor = gc.getDevice().getSystemColor(SWT.COLOR_LIST_BACKGROUND); } if (isSelected) { Color color; color = gc.getDevice().getSystemColor(SWT.COLOR_LIST_SELECTION); gc.setBackground(color); } else { gc.setBackground(altColor); } Color bg = getBackground(); if (bg == null) { bg = gc.getBackground(); } else { gc.setBackground(bg); } Color fg = getForeground(); Color shadowColor = null; if (isSelected) { shadowColor = fg; fg = gc.getDevice().getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT); gc.setForeground(fg); } else { if (fg == null) { fg = gc.getDevice().getSystemColor(SWT.COLOR_LIST_FOREGROUND); gc.setForeground(fg); } else { gc.setForeground(fg); } } int rowAlpha = getAlpha(); Font font = gc.getFont(); Rectangle clipping = gc.getClipping(); int x = rowStartX; //boolean paintedRow = false; synchronized (lock) { if (mTableCells == null) { // not sure if this is wise, but visibleRows seems to keep up to date.. so, it must be ok! setShown(true, true); } if (mTableCells != null) { for (TableColumn tc : visibleColumns) { TableCellCore cell = mTableCells.get(tc.getName()); int w = tc.getWidth(); if (!(cell instanceof TableCellPainted) || cell.isDisposed()) { gc.fillRectangle(x, rowStartY, w, getHeight()); x += w; continue; } TableCellPainted cellSWT = (TableCellPainted) cell; Rectangle r = new Rectangle(x, rowStartY, w, getHeight()); cellSWT.setBoundsRaw(r); if (drawBounds.intersects(r)) { //paintedRow = true; gc.setAlpha(255); if (isSelectedNotFocused) { gc.setBackground(altColor); gc.fillRectangle(r); gc.setAlpha(100); gc.setBackground(bg); gc.fillRectangle(r); } else { gc.setBackground(bg); gc.fillRectangle(r); if (isSelected) { gc.setAlpha(80); gc.setForeground(altColor); gc.fillGradientRectangle(r.x, r.y, r.width, r.height, true); gc.setForeground(fg); } } gc.setAlpha(rowAlpha); if (swt_paintCell(gc, cellSWT.getBounds(), cellSWT, shadowColor)) { // row color may have changed; this would update the color // for all new cells. However, setting color triggers a // row redraw that will fix up the UI //Color fgNew = getForeground(); //if (fgNew != null && fgNew != fg) { // fg = fgNew; //} gc.setBackground(bg); gc.setForeground(fg); gc.setFont(font); gc.setClipping(clipping); } if (DEBUG_ROW_PAINT) { ((TableCellSWTBase) cell).debug("painted " + (cell.getVisuallyChangedSinceRefresh() ? "VC" : "!P") + " @ " + r); } } else { if (DEBUG_ROW_PAINT) { ((TableCellSWTBase) cell).debug("Skip paintItem; no intersects; r=" + r + ";dB=" + drawBounds + " from " + Debug.getCompressedStackTrace(4)); } } x += w; } } int w = drawBounds.width - x; if (w > 0) { Rectangle r = new Rectangle(x, rowStartY, w, getHeight()); if (clipping.intersects(r)) { gc.setAlpha(255); if (isSelectedNotFocused) { gc.setBackground(altColor); gc.fillRectangle(r); gc.setAlpha(100); gc.setBackground(bg); gc.fillRectangle(r); } else { gc.fillRectangle(r); if (isSelected) { gc.setAlpha(80); gc.setForeground(altColor); gc.fillGradientRectangle(r.x, r.y, r.width, r.height, true); gc.setForeground(fg); } } gc.setAlpha(rowAlpha); } } } //synchronized (lock) //if (paintedRow) { // debug("Paint " + e.x + "x" + e.y + " " + e.width + "x" + e.height + ".." + e.count + ";clip=" + e.gc.getClipping() +";drawOffset=" + drawOffset + " via " + Debug.getCompressedStackTrace()); //} if (isFocused()) { gc.setAlpha(40); gc.setForeground(origFG); gc.setLineStyle(SWT.LINE_DOT); gc.drawRectangle(0, rowStartY, getViewPainted().getClientArea().width - 1, getHeight() - 1); gc.setLineStyle(SWT.LINE_SOLID); } gc.setAlpha(255); gc.setBackground(origBG); gc.setForeground(origFG); } private boolean swt_paintCell(GC gc, Rectangle cellBounds, TableCellSWTBase cell, Color shadowColor) { // Only called from swt_PaintGC, so we can assume GC, cell are valid if (cellBounds == null) { return false; } boolean gcChanged = false; try { gc.setTextAntialias(SWT.DEFAULT); TableViewSWT<?> view = (TableViewSWT<?>) getView(); TableColumnCore column = (TableColumnCore) cell.getTableColumn(); view.invokePaintListeners(gc, this, column, cellBounds); int fontStyle = getFontStyle(); Font oldFont = null; if (fontStyle == SWT.BOLD) { oldFont = gc.getFont(); gc.setFont(FontUtils.getAnyFontBold(gc)); gcChanged = true; } if (!cell.isUpToDate()) { //System.out.println("R " + rowIndex + ":" + iColumnNo); cell.refresh(true, true); //return; } String text = cell.getText(); Color fg = cell.getForegroundSWT(); if (fg != null) { gcChanged = true; if (isSelected()) { shadowColor = fg; } else { gc.setForeground(fg); } } Color bg = cell.getBackgroundSWT(); if (bg != null) { gcChanged = true; gc.setBackground(bg); } //if (cell.getTableColumn().getClass().getSimpleName().equals("ColumnUnopened")) { // System.out.println("FOOO" + cell.needsPainting()); //} if (cell.needsPainting()) { Image graphicSWT = cell.getGraphicSWT(); if (graphicSWT != null && !graphicSWT.isDisposed()) { Rectangle imageBounds = graphicSWT.getBounds(); Rectangle graphicBounds = new Rectangle(cellBounds.x, cellBounds.y, cellBounds.width, cellBounds.height); if (cell.getFillCell()) { if (!graphicBounds.isEmpty()) { gc.setAdvanced(true); //System.out.println(imageBounds + ";" + graphicBounds); gc.drawImage(graphicSWT, 0, 0, imageBounds.width, imageBounds.height, graphicBounds.x, graphicBounds.y, graphicBounds.width, graphicBounds.height); } } else { if (imageBounds.width < graphicBounds.width) { int alignment = column.getAlignment(); if ((alignment & TableColumn.ALIGN_CENTER) > 0) { graphicBounds.x += (graphicBounds.width - imageBounds.width) / 2; } else if ((alignment & TableColumn.ALIGN_TRAIL) > 0) { graphicBounds.x = (graphicBounds.x + graphicBounds.width) - imageBounds.width; } } if (imageBounds.height < graphicBounds.height) { graphicBounds.y += (graphicBounds.height - imageBounds.height) / 2; } gc.drawImage(graphicSWT, graphicBounds.x, graphicBounds.y); } } cell.doPaint(gc); gcChanged = true; } if (text.length() > 0) { int ofsx = 0; Image image = cell.getIcon(); Rectangle imageBounds = null; if (image != null && !image.isDisposed()) { imageBounds = image.getBounds(); int ofs = imageBounds.width; ofsx += ofs; cellBounds.x += ofs; cellBounds.width -= ofs; } //System.out.println("PS " + rowIndex + ";" + cellBounds + ";" + cell.getText()); int style = TableColumnSWTUtils.convertColumnAlignmentToSWT(column.getAlignment()); if (cellBounds.height > 20) { style |= SWT.WRAP; } int textOpacity = cell.getTextAlpha(); //gc.setFont(getRandomFont()); //textOpacity = 130; if (textOpacity < 255) { //gc.setTextAntialias(SWT.ON); gc.setAlpha(textOpacity); gcChanged = true; } else if (textOpacity > 255) { gc.setFont(FontUtils.getAnyFontBold(gc)); //gc.setTextAntialias(SWT.ON); //gc.setAlpha(textOpacity & 255); gcChanged = true; } // put some padding on text ofsx += 6; cellBounds.x += 3; cellBounds.width -= 6; cellBounds.y += 2; cellBounds.height -= 4; if (!cellBounds.isEmpty()) { GCStringPrinter sp = new GCStringPrinter(gc, text, cellBounds, true, cellBounds.height > 20, style); boolean fit; if (shadowColor != null) { Color oldFG = gc.getForeground(); gc.setForeground(shadowColor); cellBounds.x += 1; cellBounds.y += 1; int alpha = gc.getAlpha(); gc.setAlpha(0x40); sp.printString(gc, cellBounds, style); gc.setAlpha(alpha); gc.setForeground(oldFG); cellBounds.x -= 1; cellBounds.y -= 1; fit = sp.printString2(gc, cellBounds, style); } else { fit = sp.printString(); } if (fit) { cell.setDefaultToolTip(null); } else { cell.setDefaultToolTip(text); } Point size = sp.getCalculatedSize(); size.x += ofsx; TableColumn tableColumn = cell.getTableColumn(); if (tableColumn != null && tableColumn.getPreferredWidth() < size.x) { tableColumn.setPreferredWidth(size.x); } if (imageBounds != null) { int drawToY = cellBounds.y + (cellBounds.height / 2) - (imageBounds.height / 2); boolean hack_adv = Constants.isWindows8OrHigher && gc.getAdvanced(); if ( hack_adv ){ // problem with icon transparency on win8 gc.setAdvanced( false ); } if ((style & SWT.RIGHT) != 0) { int drawToX = cellBounds.x + cellBounds.width - size.x; gc.drawImage(image, drawToX, drawToY); } else { gc.drawImage(image, cellBounds.x - imageBounds.width - 3, drawToY); } if ( hack_adv ){ gc.setAdvanced( true ); } } } else { cell.setDefaultToolTip(null); } } cell.clearVisuallyChangedSinceRefresh(); if (oldFont != null) { gc.setFont(oldFont); } } catch (Exception e) { e.printStackTrace(); } return gcChanged; } private Font getRandomFont() { FontData[] fontList = Display.getDefault().getFontList(null, (Math.random() > 0.5)); FontData fontData = fontList[(int)(Math.random() * fontList.length)]; fontData.setStyle((int)(Math.random() * 4)); fontData.height = (float) (Math.random() * 50f); return new Font(Display.getDefault(), fontData); } @Override public List<TableCellCore> refresh(boolean bDoGraphics, boolean bVisible) { final List<TableCellCore> invalidCells = super.refresh(bDoGraphics, bVisible); //System.out.print(SystemTime.getCurrentTime() + "] InvalidCells: "); if (invalidCells.size() > 0) { //for (TableCellCore cell : invalidCells) { // System.out.print(cell.getTableColumn().getName() + ", "); //} //System.out.println(); Utils.execSWTThread(new AERunnable() { public void runSupport() { Composite composite = getViewPainted().getComposite(); if (composite == null || composite.isDisposed() || !isVisible()) { return; } boolean allCells; synchronized( lock ){ allCells = (mTableCells != null)&& invalidCells.size() == mTableCells.size(); } if (allCells) { getViewPainted().swt_updateCanvasImage(getDrawBounds(), false); } else { for (Object o : invalidCells) { if (o instanceof TableCellPainted) { TableCellPainted cell = (TableCellPainted) o; Rectangle bounds = cell.getBoundsRaw(); if (bounds != null) { getViewPainted().swt_updateCanvasImage(bounds, false); } } } } } }); //} else { //System.out.println("NONE"); } return invalidCells; } public void redraw(boolean doChildren) { redraw(doChildren, false); } public void redraw(boolean doChildren, boolean immediateRedraw) { if (isRowDisposed()) { return; } getViewPainted().redrawRow(this, immediateRedraw); if (!doChildren) { return; } synchronized (subRows_sync) { if (subRows != null) { for (TableRowPainted subrow : subRows) { subrow.redraw(); } } } } protected void debug(String s) { AEDiagnosticsLogger diag_logger = AEDiagnostics.getLogger("table"); String prefix = SystemTime.getCurrentTime() + ":" + getTableID() + ": r" + getIndex(); if (getParentRowCore() != null) { prefix += "of" + getParentRowCore().getIndex(); } prefix += ": "; diag_logger.log(prefix + s); System.out.println(prefix + s); } /* (non-Javadoc) * @see org.gudy.azureus2.ui.swt.views.table.impl.TableRowSWTBase#getBounds() */ @Override public Rectangle getBounds() { //TableViewPainted view = (TableViewPainted) getView(); //Rectangle clientArea = view.getClientArea(); return new Rectangle(0, drawOffset.y, 9990, getHeight()); } public Rectangle getDrawBounds() { TableViewPainted view = (TableViewPainted) getView(); Rectangle clientArea = view.getClientArea(); Rectangle bounds = new Rectangle(0, drawOffset.y - clientArea.y, 9990, getHeight()); return bounds; } public int getFullHeight() { int h = getHeight(); if (numSubItems > 0 && isExpanded()) { h += subRowsHeight; } return h; } public Point getDrawOffset() { return drawOffset; } /* (non-Javadoc) * @see org.gudy.azureus2.ui.swt.views.table.impl.TableRowSWTBase#heightChanged(int, int) */ public void heightChanged(int oldHeight, int newHeight) { getViewPainted().rowHeightChanged(this, oldHeight, newHeight); TableRowCore row = getParentRowCore(); if (row instanceof TableRowPainted) { ((TableRowPainted) row).subRowHeightChanged(this, oldHeight, newHeight); } } public void subRowHeightChanged(TableRowCore row, int oldHeight, int newHeight) { subRowsHeight += (newHeight - oldHeight); } public boolean setDrawOffset(Point drawOffset) { if (drawOffset.equals(this.drawOffset)) { return false; } this.drawOffset = drawOffset; return true; } @Override public void setWidgetSelected(boolean selected) { redraw(false, true); } @Override public boolean setShown(boolean b, boolean force) { if (b == wasShown && !force) { return false; } synchronized (lock) { if (b && mTableCells == null) { buildCells(); } } boolean ret = super.setShown(b, force); if (b) { invalidate(); redraw(false, false); } synchronized (lock) { if (!b && mTableCells != null) { destroyCells(); } } return ret; } @Override public void delete() { super.delete(); synchronized (lock) { if ( cellSort != null && !cellSort.isDisposed()){ cellSort.dispose(); cellSort = null; } } deleteExistingSubRows(); } private void deleteExistingSubRows() { synchronized (subRows_sync) { if (subRows != null) { for (TableRowPainted subrow : subRows) { subrow.delete(); } } subRows = null; } } public void setSubItemCount(int length) { numSubItems = length; if (isExpanded() && subDataSources.length == length) { if (DEBUG_SUBS) { debug("setSubItemCount to " + length); } deleteExistingSubRows(); TableRowPainted[] newSubRows = new TableRowPainted[length]; TableViewPainted tv = getViewPainted(); int h = 0; for (int i = 0; i < newSubRows.length; i++) { newSubRows[i] = new TableRowPainted(this, tv, subDataSources[i], false); newSubRows[i].setTableItem(i, false); h += newSubRows[i].getHeight(); } int oldHeight = getFullHeight(); subRowsHeight = h; getViewPainted().rowHeightChanged(this, oldHeight, getFullHeight()); getViewPainted().triggerListenerRowAdded(newSubRows); subRows = newSubRows; } } public int getSubItemCount() { return numSubItems; } /* (non-Javadoc) * @see com.aelitis.azureus.ui.common.table.TableRowCore#linkSubItem(int) */ public TableRowCore linkSubItem(int indexOf) { // Not used by TableViewPainted return null; } public void setSubItems(Object[] datasources) { deleteExistingSubRows(); synchronized (subRows_sync) { subDataSources = datasources; subRowsHeight = 0; setSubItemCount(datasources.length); } } public TableRowCore[] getSubRowsWithNull() { synchronized (subRows_sync) { return subRows == null ? new TableRowCore[0] : subRows; } } public void removeSubRow(Object datasource) { synchronized (subRows_sync) { for (int i = 0; i < subDataSources.length; i++) { Object ds = subDataSources[i]; if (ds == datasource) { // use .equals instead? TableRowPainted rowToDel = subRows[i]; TableRowPainted[] newSubRows = new TableRowPainted[subRows.length - 1]; System.arraycopy(subRows, 0, newSubRows, 0, i); System.arraycopy(subRows, i + 1, newSubRows, i, subRows.length - i - 1); subRows = newSubRows; Object[] newDatasources = new Object[subRows.length]; System.arraycopy(subDataSources, 0, newDatasources, 0, i); System.arraycopy(subDataSources, i + 1, newDatasources, i, subDataSources.length - i - 1); subDataSources = newDatasources; rowToDel.delete(); setSubItemCount(subRows.length); break; } } } } @Override public void setExpanded(boolean b) { int oldHeight = getFullHeight(); super.setExpanded(b); synchronized (subRows_sync) { TableRowPainted[] newSubRows = null; if (b && (subRows == null || subRows.length != numSubItems) && subDataSources != null && subDataSources.length == numSubItems) { if (DEBUG_SUBS) { debug("building subrows " + numSubItems); } deleteExistingSubRows(); newSubRows = new TableRowPainted[numSubItems]; TableViewPainted tv = getViewPainted(); int h = 0; for (int i = 0; i < newSubRows.length; i++) { newSubRows[i] = new TableRowPainted(this, tv, subDataSources[i], false); newSubRows[i].setTableItem(i, false); h += newSubRows[i].getHeight(); } subRowsHeight = h; subRows = newSubRows; } getViewPainted().rowHeightChanged(this, oldHeight, getFullHeight()); if (newSubRows != null) { getViewPainted().triggerListenerRowAdded(newSubRows); } } if (isVisible()) { getViewPainted().visibleRowsChanged(); getViewPainted().redrawTable(); } } public TableRowCore getSubRow(int pos) { synchronized (subRows_sync) { if (subRows == null) { return null; } if (pos >= 0 && pos < subRows.length) { return subRows[pos]; } return null; } } /* (non-Javadoc) * @see org.gudy.azureus2.ui.swt.views.table.impl.TableRowSWTBase#setForeground(org.eclipse.swt.graphics.Color) */ @Override public boolean setForeground(Color color) { if (isRowDisposed()) { return false; } if (color == colorFG || (color != null && color.equals(colorFG)) || (colorFG != null && colorFG.equals(color))) { return false; } colorFG = color; //delays redraw until after. Could use execSWTThreadLater Utils.getOffOfSWTThread(new AERunnable() { public void runSupport() { redraw(false, false); } }); return true; } @Override public boolean setIconSize(Point pt) { //TODO return false; } @Override public Color getForeground() { return colorFG; } @Override public Color getBackground() { return null; } @Override public void setBackgroundImage(Image image) { //TODO } /* (non-Javadoc) * @see com.aelitis.azureus.ui.common.table.TableRowCore#getHeight() */ public int getHeight() { return height == 0 ? getView().getRowDefaultHeight() : height; } /* (non-Javadoc) * @see com.aelitis.azureus.ui.common.table.TableRowCore#setHeight(int) */ public boolean setHeight(int newHeight) { TableRowCore parentRowCore = getParentRowCore(); boolean trigger = parentRowCore == null || parentRowCore.isExpanded(); return setHeight(newHeight, trigger); } public boolean setHeight(int newHeight, boolean trigger) { if (height == newHeight) { return false; } int oldHeight = height; height = newHeight; if (trigger && !initializing) { heightChanged(oldHeight, newHeight); } return true; } @Override public TableCellCore getTableCellCore(String name) { if (isRowDisposed()) { return null; } synchronized (lock) { if (mTableCells == null) { if (cellSort != null && !cellSort.isDisposed() && cellSort.getTableColumn().getName().equals(name)) { return cellSort; } else { return null; } } return mTableCells.get(name); } } @Override public TableCellSWT getTableCellSWT(String name) { TableCellCore cell = getTableCellCore(name); return (cell instanceof TableCellSWT) ? (TableCellSWT) cell : null; } @Override public TableCell getTableCell(String field) { return getTableCellCore(field); } public TableCellCore getSortColumnCell(String hint) { synchronized (lock) { return cellSort; } } public void setSortColumn(String columnID) { synchronized (lock) { if (mTableCells == null) { if (cellSort != null && !cellSort.isDisposed()) { if (cellSort.getTableColumn().getName().equals(columnID)) { return; } cellSort.dispose(); cellSort = null; } TableColumnCore sortColumn = (TableColumnCore) getView().getTableColumn( columnID); if (getParentRowCore() == null || sortColumn.handlesDataSourceType(getDataSource(false).getClass())) { cellSort = new TableCellPainted(TableRowPainted.this, sortColumn, sortColumn.getPosition()); } else { cellSort = null; } } else { cellSort = mTableCells.get(columnID); } } } }