/*
* File : TableCellImpl.java
* Created : 24 nov. 2003
* By : Olivier
* Originally PluginItem.java, and changed to be more generic.
*
* Copyright (C) 2004, 2005, 2006 Aelitis SAS, All rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details ( see the LICENSE file ).
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* AELITIS, SAS au capital de 46,603.30 euros,
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*/
package org.gudy.azureus2.ui.swt.views.table.impl;
import java.util.Comparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.Item;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.logging.LogEvent;
import org.gudy.azureus2.core3.logging.LogIDs;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.Constants;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.plugins.ui.Graphic;
import org.gudy.azureus2.plugins.ui.tables.TableColumn;
import org.gudy.azureus2.plugins.ui.tables.TableRow;
import org.gudy.azureus2.ui.swt.Utils;
import org.gudy.azureus2.ui.swt.components.*;
import org.gudy.azureus2.ui.swt.plugins.UISWTGraphic;
import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTGraphicImpl;
import org.gudy.azureus2.ui.swt.views.table.*;
import org.gudy.azureus2.ui.swt.views.table.utils.TableColumnSWTUtils;
import com.aelitis.azureus.ui.common.table.TableColumnCore;
import com.aelitis.azureus.ui.common.table.TableRowCore;
/** TableCellImpl represents one cell in the table.
* Table access is provided by BufferedTableItem.
* TableCellImpl is stored in and accessed by TableRowCore.
* Drawing control gets passed to listeners.
*
* For plugins, this object is the implementation to TableCell.
*
* This object is needed to split core code from plugin code.
*/
public class TableCellImpl
extends TableCellSWTBase
{
private static final LogIDs LOGID = LogIDs.GUI;
private static final boolean canUseQuickDraw = Constants.isWindows;
private BufferedTableItem bufferedTableItem;
// Getting the cell's bounds can be slow. QUICK_WIDTH uses TableColumn's width
private static final boolean QUICK_WIDTH = true;
public TableCellImpl(TableRowCore _tableRow, TableColumnCore _tableColumn,
int position, BufferedTableItem item) {
super(_tableRow, _tableColumn);
if (item != null) {
bufferedTableItem = item;
} else {
createBufferedTableItem(position);
}
//bDebug = (position == 1) && tableColumn.getTableID().equalsIgnoreCase("Peers");
constructionCompleter();
}
protected void
constructionCompleter()
{
constructionComplete();
tableColumn.invokeCellAddedListeners(TableCellImpl.this);
}
/**
* Initialize
*
* @param _tableRow
* @param _tableColumn
* @param position
*/
public TableCellImpl(TableRowSWT _tableRow, TableColumnCore _tableColumn,
int position) {
this(_tableRow, _tableColumn, position, null);
}
private void createBufferedTableItem(int position) {
BufferedTableRow bufRow = (BufferedTableRow)tableRow;
if (tableColumn.getType() == TableColumnCore.TYPE_GRAPHIC) {
bufferedTableItem = new BufferedGraphicTableItem1(bufRow, position) {
public void refresh() {
TableCellImpl.this.refresh();
}
public void invalidate() {
clearFlag(FLAG_VALID);
this.redraw();
// or this redraw? TableCellImpl.this.redraw();
}
protected void quickRedrawCell(TableOrTreeSWT table, Rectangle dirty, Rectangle cellBounds) {
TableItemOrTreeItem item = row.getItem();
boolean ourQuickRedraw = canUseQuickDraw && tableRow != null
&& !tableRow.isMouseOver() && !tableRow.isSelected();
if (ourQuickRedraw) {
TableCellImpl.this.quickRedrawCell2(table, item, dirty, cellBounds);
} else {
super.quickRedrawCell(table, dirty, cellBounds);
}
}
};
setOrientationViaColumn();
} else {
bufferedTableItem = new BufferedTableItemImpl(bufRow, position) {
public void refresh() {
TableCellImpl.this.refresh();
}
public void invalidate() {
clearFlag(FLAG_VALID);
}
protected void quickRedrawCell(TableOrTreeSWT table, Rectangle dirty,
Rectangle cellBounds) {
TableItemOrTreeItem item = row.getItem();
boolean ourQuickRedraw = canUseQuickDraw && tableRow != null
&& !tableRow.isMouseOver() && !tableRow.isSelected();
if (ourQuickRedraw) {
TableCellImpl.this.quickRedrawCell2(table, item, dirty, cellBounds);
} else {
super.quickRedrawCell(table, dirty, cellBounds);
}
}
};
}
}
protected void quickRedrawCell2(TableOrTreeSWT table,
TableItemOrTreeItem tableItemOrTreeItem, Rectangle dirty,
Rectangle cellBounds) {
if (bufferedTableItem.isInPaintItem()) {
return;
}
Rectangle bounds = new Rectangle(0, 0, cellBounds.width, cellBounds.height);
Point pt = new Point(cellBounds.x, cellBounds.y);
Image img = new Image(table.getDisplay(), bounds);
int colPos = bufferedTableItem.getPosition();
Item item = tableItemOrTreeItem.getItem();
table.setData("inPaintInfo", new InPaintInfo(item, colPos, bounds));
table.setData("fullPaint", Boolean.TRUE);
GC gc = new GC(img);
try {
TableViewSWTImpl<?> tv = (TableViewSWTImpl<?>) tableRow.getView();
TableViewSWT_EraseItem.eraseItem(null, gc, tableItemOrTreeItem, colPos,
false, bounds, tv, true);
//gc.setBackground(ColorCache.getRandomColor());
//gc.fillRectangle(bounds);
Color fg = getForegroundSWT();
if (fg != null) {
gc.setForeground(fg);
}
gc.setBackground(getBackgroundSWT());
TableViewSWT_PaintItem.paintItem(gc, (TableRowSWT) tableRow, colPos,
tableRow.getIndex(), bounds, tv, true);
} finally {
gc.dispose();
}
gc = new GC(table.getComposite());
try {
//System.out.println("draw " + bounds);
gc.drawImage(img, pt.x, pt.y);
} finally {
img.dispose();
gc.dispose();
}
table.setData("inPaintInfo", null);
table.setData("fullPaint", Boolean.FALSE);
}
protected void quickRedrawCell(TableOrTreeSWT table,
TableItemOrTreeItem tableItemOrTreeItem, Rectangle dirty,
Rectangle cellBounds) {
if (bufferedTableItem.isInPaintItem()) {
return;
}
int colPos = bufferedTableItem.getPosition();
Item item = tableItemOrTreeItem.getItem();
table.setData("inPaintInfo", new InPaintInfo(item, colPos, cellBounds));
table.setData("fullPaint", Boolean.TRUE);
GC gc = new GC(table.getComposite());
try {
TableViewSWTImpl<?> tv = (TableViewSWTImpl<?>) tableRow.getView();
TableViewSWT_EraseItem.eraseItem(null, gc, tableItemOrTreeItem,
bufferedTableItem.getPosition(), true, cellBounds, tv, true);
Color fg = getForegroundSWT();
if (fg != null) {
gc.setForeground(fg);
}
gc.setBackground(getBackgroundSWT());
TableViewSWT_PaintItem.paintItem(gc, (TableRowSWT) tableRow,
bufferedTableItem.getPosition(), tableRow.getIndex(), cellBounds, tv, true);
} finally {
gc.dispose();
}
table.setData("inPaintInfo", null);
table.setData("fullPaint", Boolean.FALSE);
}
protected void pluginError(Throwable e) {
String sTitleLanguageKey = (tableColumn==null?"?":tableColumn.getTitleLanguageKey());
String sPosition = (bufferedTableItem == null)
? "null"
: "" + bufferedTableItem.getPosition() +
" (" + MessageText.getString(sTitleLanguageKey) + ")";
Logger.log(new LogEvent(LOGID, "Table Cell Plugin for Column #" + sPosition
+ " generated an exception ", e));
}
protected void pluginError(String s) {
String sTitleLanguageKey = (tableColumn==null?"?":tableColumn.getTitleLanguageKey());
String sPosition = "r"
+ tableRow.getIndex()
+ (bufferedTableItem == null ? "null" : "c"
+ bufferedTableItem.getPosition() + " ("
+ MessageText.getString(sTitleLanguageKey) + ")");
Logger.log(new LogEvent(LOGID, LogEvent.LT_ERROR,
"Table Cell Plugin for Column #" + sPosition + ":" + s + "\n "
+ Debug.getStackTrace(true, true)));
}
/* Public API */
////////////////
public Object getDataSource() {
// if we've been disposed then row/col are null
TableRowCore row = tableRow;
TableColumnCore col = tableColumn;
if ( row == null || col == null){
return( null );
}
return row.getDataSource(col.getUseCoreDataSource());
}
public TableColumn getTableColumn() {
return tableColumn;
}
public TableRow getTableRow() {
return tableRow;
}
public String getTableID() {
return tableRow.getTableID();
}
public Color getForegroundSWT() {
if (isDisposed()) {
return null;
}
return bufferedTableItem.getForeground();
}
public Color getBackgroundSWT() {
if (isDisposed()) {
return null;
}
return bufferedTableItem.getBackground();
}
public boolean setForeground(Color color) {
if (isDisposed()) {
return false;
}
// Don't need to set when not visible
if (isInvisibleAndCanRefresh())
return false;
boolean set = bufferedTableItem.setForeground(color);
if (set) {
setFlag(FLAG_VISUALLY_CHANGED_SINCE_REFRESH);
}
return set;
}
@Override
public boolean uiSetText(String text) {
return bufferedTableItem.setText(text);
}
@Override
public boolean setGraphic(Graphic img) {
boolean changed = super.setGraphic(img);
if (changed && img != null) {
Image imgSWT = ((UISWTGraphic)img).getImage();
((BufferedGraphicTableItem)bufferedTableItem).setGraphic(imgSWT);
}
return changed;
}
public String getText() {
if (hasFlag(FLAG_SORTVALUEISTEXT) && sortValue instanceof String)
return (String)sortValue;
if (bufferedTableItem == null) {
return null;
}
return bufferedTableItem.getText();
}
public boolean isShown() {
if (bufferedTableItem == null || tableRow == null ) {
return false;
}
return bufferedTableItem.isShown()
&& tableRow.getView().isColumnVisible(tableColumn);
}
public Comparable<?> getSortValue() {
Comparable<?> v = super.getSortValue();
if (v == null) {
if (bufferedTableItem != null)
return bufferedTableItem.getText();
return "";
}
return v;
}
// @see org.gudy.azureus2.plugins.ui.tables.TableCell#getMaxLines()
public int getMaxLines() {
if (bufferedTableItem == null) {
// use 1 in case some plugin borks on div by zero
return 1;
}
return bufferedTableItem.getMaxLines();
}
/* Start TYPE_GRAPHIC Functions */
public Point getSize() {
if (!(bufferedTableItem instanceof BufferedGraphicTableItem))
return null;
return ((BufferedGraphicTableItem)bufferedTableItem).getSize();
}
public int getWidthRaw() {
return tableColumn.getWidth() - 2;
}
public int getWidth() {
if (isDisposed()) {
return -1;
}
if (QUICK_WIDTH) {
return tableColumn.getWidth() - 2 - (getMarginWidth() * 2);
} else {
Point pt = null;
if (bufferedTableItem instanceof BufferedGraphicTableItem) {
pt = ((BufferedGraphicTableItem)bufferedTableItem).getSize();
} else {
Rectangle bounds = bufferedTableItem.getBounds();
if (bounds != null) {
pt = new Point(bounds.width, bounds.height);
}
}
if (pt == null)
return -1;
return pt.x;
}
}
public int getHeight() {
return bufferedTableItem.getHeight();
}
/* (non-Javadoc)
* @see org.gudy.azureus2.plugins.ui.tables.TableCell#setFillCell(boolean)
*/
public void setFillCell(boolean bFillCell) {
super.setFillCell(bFillCell);
if (isDisposed()) {
return;
}
if (!(bufferedTableItem instanceof BufferedGraphicTableItem))
return;
if (bFillCell)
((BufferedGraphicTableItem)bufferedTableItem).setOrientation(SWT.FILL);
else
setOrientationViaColumn();
setFlag(FLAG_VISUALLY_CHANGED_SINCE_REFRESH);
}
public void setMarginHeight(int height) {
if (isDisposed()) {
return;
}
if (!(bufferedTableItem instanceof BufferedGraphicTableItem))
return;
((BufferedGraphicTableItem)bufferedTableItem).setMargin(-1, height);
setFlag(FLAG_VISUALLY_CHANGED_SINCE_REFRESH);
}
public void setMarginWidth(int width) {
if (isDisposed()) {
return;
}
if (!(bufferedTableItem instanceof BufferedGraphicTableItem))
return;
((BufferedGraphicTableItem)bufferedTableItem).setMargin(width, -1);
setFlag(FLAG_VISUALLY_CHANGED_SINCE_REFRESH);
}
public int getMarginHeight() {
if (!(bufferedTableItem instanceof BufferedGraphicTableItem))
return 0;
return ((BufferedGraphicTableItem)bufferedTableItem).getMarginHeight();
}
public int getMarginWidth() {
if (!(bufferedTableItem instanceof BufferedGraphicTableItem))
return 0;
return ((BufferedGraphicTableItem)bufferedTableItem).getMarginWidth();
}
/* End TYPE_GRAPHIC Functions */
/* Start of Core-Only function */
//////////////////////////////////
public void redraw() {
if (!tableRow.isVisible()) {
return;
}
if (bufferedTableItem != null) {
bufferedTableItem.redraw();
}
}
public void invalidate(final boolean bMustRefresh) {
super.invalidate(bMustRefresh);
if (bMustRefresh) {
if (bufferedTableItem != null) {
bufferedTableItem.invalidate();
}
}
}
public void dispose() {
super.dispose();
if (bufferedTableItem != null) {
//bufferedTableItem.setForeground(null);
bufferedTableItem.dispose();
}
bufferedTableItem = null;
}
public boolean needsPainting() {
if (isDisposed()) {
return false;
}
if (cellSWTPaintListeners != null || tableColumn.hasCellOtherListeners("SWTPaint")) {
return true;
}
if (bufferedTableItem == null) {
return false;
}
return bufferedTableItem.needsPainting();
}
public void locationChanged() {
if (bufferedTableItem != null) {
bufferedTableItem.locationChanged();
}
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return "TableCell {"
+ (tableColumn == null ? "disposed" : tableColumn.getName())
+ ","
+ (tableRow == null ? "" : "r" + tableRow.getIndex())
+ (bufferedTableItem == null ? "c?" : "c"
+ bufferedTableItem.getPosition()) + "," + getText() + ","
+ getSortValue() + "}";
}
/* Comparable Implementation */
public static final Comparator TEXT_COMPARATOR = new TextComparator();
private static class TextComparator implements Comparator {
public int compare(Object arg0, Object arg1) {
return arg0.toString().compareToIgnoreCase(arg1.toString());
}
}
public Rectangle getBounds() {
if (isDisposed()) {
return new Rectangle(0, 0, 0, 0);
}
Rectangle bounds = bufferedTableItem.getBounds();
if (bounds == null) {
return new Rectangle(0, 0, 0, 0);
}
return bounds;
}
private void setOrientationViaColumn() {
if (!(bufferedTableItem instanceof BufferedGraphicTableItem))
return;
int align = tableColumn.getAlignment();
BufferedGraphicTableItem ti = (BufferedGraphicTableItem) bufferedTableItem;
ti.setOrientation(TableColumnSWTUtils.convertColumnAlignmentToSWT(align));
}
/* (non-Javadoc)
* @see org.gudy.azureus2.plugins.ui.tables.TableCell#getBackgroundGraphic()
*/
public Graphic getBackgroundGraphic() {
if (bufferedTableItem == null) {
return null;
}
return new UISWTGraphicImpl(bufferedTableItem.getBackgroundImage());
}
/* (non-Javadoc)
* @see org.gudy.azureus2.ui.swt.views.table.TableCellSWT#getBackgroundImage()
*/
public Image getBackgroundImage() {
if (bufferedTableItem == null) {
return null;
}
return bufferedTableItem.getBackgroundImage();
}
public BufferedTableItem getBufferedTableItem() {
return bufferedTableItem;
}
/* (non-Javadoc)
* @see com.aelitis.azureus.ui.common.table.TableCellCore#setCursorID(int)
*/
public boolean setCursorID(int cursorID) {
if (!super.setCursorID(cursorID)) {
return false;
}
Utils.execSWTThread(new AERunnable() {
public void runSupport() {
if (isMouseOver()) {
bufferedTableItem.setCursor(getCursorID());
}
}
});
return true;
}
public boolean isMouseOver() {
if (bufferedTableItem == null) {
return false;
}
if (!tableRow.isVisible()) {
return false;
}
return bufferedTableItem.isMouseOver();
}
public Rectangle getBoundsOnDisplay() {
Rectangle bounds = getBounds();
Point pt = ((TableViewSWT<?>) tableRow.getView()).getTableOrTreeSWT().toDisplay(bounds.x, bounds.y);
bounds.x = pt.x;
bounds.y = pt.y;
return bounds;
}
@Override
public boolean refresh(boolean bDoGraphics, boolean bRowVisible,
boolean bCellVisible) {
return super.refresh(bDoGraphics, bRowVisible, bCellVisible);
}
}