The source of a custom table class for Java SWT applications : Table « SWT JFace Eclipse « Java






The source of a custom table class for Java SWT applications

The source of a custom table class for Java SWT applications

/*

de.kupzog.ktable.*  Version 1.4
_______________________________________________________________________

This is the source of a custom table class for Java SWT applications.

The original version of this table was written by Konstantin Scheglov. 
KTable is a complete new implementation but uses the structure and
some code fragments from the old version.

The features of this table implementation in short terms:

- a table model provides the data for the table (comparable
  to the Swing table model)
  
- cell rendering is done by extern classes and thus can easily
  be changed to any rendering one could imagine...
  
- Columns and rows can be resized by mouse. Note that all rows
  except the first row will have the same size.
  
- There can be horizontal and vertical headers (fixed cells)
  as many as needed.
  
- Different selection modes are available

- In place editing is possibel by using editor classes that
  can easily be adjusted to special needs.
  
  
For a detailed function description refer to the api documentation that 
is included in the sourcefiles.

For examples how to use KTable, see the "ExampleGUI" class. You can 
run this class and see different examples of KTables.

Text Table    Shows a Table with 1,000,000 rows and 100 columns.
        The use of cell editors is shown.
        You can resize rows and columns.
        Selection Listeners are used (see the console output).
        
Color Palette  Here you can see that a table does not have to
        look like a table...
        See how the cell renderer is implemented and 
        what the table model does.
        
Towns      This example shows how images can be included in
        table cells together with text. It also shows the use
        of the multi line cell editor.
        


The author welcomes any feedback:  fkmk@kupzog.de








Changes in Version 1.1 compared to previous version:

- empty table without header looks better now
- right-click on cell also changes the selection

Changes in Version 1.2
- License changed from GPL to LGPL
- Table does no longer throw NullPointerException if no model is set.
- minor other bug fixes

Changes in Version 1.3
- License changed from LGPL to Eclipse Public License (EPL) (what will be next?)
- Keyboard access for combo editors added (thanks to Larry Moore)
- minor other bug fixes

Changed in Version 1.4
- FLAT style allows more border flexibility: if specified,
  no border lines will be drawn.
- Click on fixed cells now also changes the row selection 
  (only in row selection mode with cells on the left border)
- bug fixes thanks to Chris Grant
*/

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Friederich Kupzog - initial API and implementation
 *      fkmk@kupzog.de
 *    www.kupzog.de/fkmk
 *******************************************************************************/

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;

/**
 * KTable example GUI
 * 
 * 
 */

public class ExampleGUI {
  public static void main(String[] args) {
    // create a shell...
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    shell.setText("KTable examples");

    // put a tab folder in it...
    TabFolder tabFolder = new TabFolder(shell, SWT.NONE);

    // Item 1: a Text Table
    TabItem item1 = new TabItem(tabFolder, SWT.NONE);
    item1.setText("Text Table");
    Composite comp1 = new Composite(tabFolder, SWT.NONE);
    item1.setControl(comp1);
    comp1.setLayout(new FillLayout());

    // put a table in tabItem1...
    KTable table = new KTable(comp1, SWT.V_SCROLL | SWT.H_SCROLL);
    // table.setRowSelectionMode(true);
    table.setMultiSelectionMode(true);
    table.setModel(new KTableModelExample());
    table.addCellSelectionListener(new KTableCellSelectionListener() {
      public void cellSelected(int col, int row, int statemask) {
        System.out.println("Cell [" + col + ";" + row + "] selected.");
      }

      public void fixedCellSelected(int col, int row, int statemask) {
        System.out
            .println("Header [" + col + ";" + row + "] selected.");
      }

    });

    table.addCellResizeListener(new KTableCellResizeListener() {
      public void columnResized(int col, int newWidth) {
        System.out.println("Column " + col + " resized to " + newWidth);
      }

      public void rowResized(int newHeight) {
        System.out.println("Rows resized to " + newHeight);
      }

    });

    // Item 2: a Color Palette
    TabItem item2 = new TabItem(tabFolder, SWT.NONE);
    item2.setText("Color Palette");
    Composite comp2 = new Composite(tabFolder, SWT.NONE);
    item2.setControl(comp2);
    comp2.setLayout(new FillLayout());

    // put a table in tabItem2...
    final KTable table2 = new KTable(comp2, SWT.NONE);
    table2.setModel(new PaletteExampleModel());
    table2.setRowSelectionMode(false);
    table2.setMultiSelectionMode(false);
    final Label label = new Label(comp2, SWT.NONE);
    label.setText("Click a cell...");
    table2.addCellSelectionListener(new KTableCellSelectionAdapter() {
      public void cellSelected(int col, int row, int statemask) {
        RGB rgb = (RGB) table2.getModel().getContentAt(col, row);
        label.setText("R: " + rgb.red + "\nG: " + rgb.green + "\nB: "
            + rgb.blue);
      }
    });

    // Item 3: Town table
    TabItem item3 = new TabItem(tabFolder, SWT.NONE);
    item3.setText("Towns");
    Composite comp3 = new Composite(tabFolder, SWT.NONE);
    item3.setControl(comp3);
    comp3.setLayout(new FillLayout());

    // put a table in tabItem3...
    final KTable table3 = new KTable(comp3, SWT.FLAT | SWT.H_SCROLL);
    table3.setBackground(Display.getCurrent().getSystemColor(
        SWT.COLOR_LIST_BACKGROUND));
    table3.setModel(new TownExampleModel());
    table3.setRowSelectionMode(true);
    table3.setMultiSelectionMode(false);

    // display the shell...
    shell.setSize(600, 600);
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

/**
 * Custom drawn tabel widget for SWT GUIs.
 * 
 * 
 * @see de.kupzog.ktable.KTableModel
 * @see de.kupzog.ktable.KTableCellRenderer
 * @see de.kupzog.ktable.KTableCellEditor
 * @see de.kupzog.ktable.KTableCellSelectionListener
 * 
 * The idea of KTable is to have a flexible grid of cells to display data in it.
 * The class focuses on displaying data and not on collecting the data to
 * display. The latter is done by the KTableModel which has to be implemented
 * for each specific case. The table asks the table model for the amount of
 * columns and rows, the sizes of columns and rows and for the content of the
 * cells which are currently drawn. Even if the table has a million rows, it
 * won't get slower because it only requests those cells it currently draws.
 * Only a bad table model can influence the drawing speed negatively.
 * 
 * When drawing a cell, the table calls a KTableCellRenderer to do this work.
 * The table model determines which cell renderer is used for which cell. A
 * default renderer is available (KTableCellRenderer.defaultRenderer), but the
 * creation of self-written renderers for specific purposes is assumed.
 * 
 * KTable allows to resize columns and rows. Each column can have an individual
 * size while the rows are all of the same height except the first row. Multiple
 * column and row headers are possible. These "fixed" cells will not be scrolled
 * out of sight. The column and row count always starts in the upper left corner
 * with 0, independent of the number of column headers or row headers.
 * 
 * @author Friederich Kupzog
 * 
 */
class KTable extends Canvas {

  // Daten und Datendarstellung
  protected KTableModel m_Model;

  protected KTableCellEditor m_CellEditor;

  // aktuelle Ansicht
  protected int m_TopRow;

  protected int m_LeftColumn;

  // Selection
  protected boolean m_RowSelectionMode;

  protected boolean m_MultiSelectMode;

  protected HashMap m_Selection;

  protected int m_FocusRow;

  protected int m_FocusCol;

  protected int m_ClickColumnIndex;

  protected int m_ClickRowIndex;

  // wichtige MaBe
  protected int m_RowsVisible;

  protected int m_RowsFullyVisible;

  protected int m_ColumnsVisible;

  protected int m_ColumnsFullyVisible;

  // SpaltengroBe
  protected int m_ResizeColumnIndex;

  protected int m_ResizeColumnLeft;

  protected int m_ResizeRowIndex;

  protected int m_ResizeRowTop;

  protected int m_NewRowSize;

  protected boolean m_Capture;

  protected Image m_LineRestore;

  protected int m_LineX;

  protected int m_LineY;

  // sonstige
  protected GC m_GC;

  protected Display m_Display;

  protected ArrayList cellSelectionListeners;

  protected ArrayList cellResizeListeners;

  protected boolean flatStyleSpecified;

  // ////////////////////////////////////////////////////////////////////////////
  // KONSTRUKTOR
  // ////////////////////////////////////////////////////////////////////////////

  /**
   * Creates a new KTable.
   * 
   * possible styles: SWT.V_SCROLL - show vertical scrollbar and allow
   * vertical scrolling by arrow keys SWT.H_SCROLL - show horizontal scrollbar
   * and allow horizontal scrolling by arrow keys SWT.FLAT - no border
   * drawing.
   * 
   * After creation a table model should be added using setModel().
   */
  public KTable(Composite parent, int style) {
    // Oberklasse initialisieren
    super(parent, SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE | style);

    // inits
    m_GC = new GC(this);
    m_Display = Display.getCurrent();
    m_Selection = new HashMap();
    m_CellEditor = null;

    flatStyleSpecified = ((style | SWT.FLAT) == style);

    m_RowSelectionMode = false;
    m_MultiSelectMode = false;
    m_TopRow = 0;
    m_LeftColumn = 0;
    m_FocusRow = 0;
    m_FocusCol = 0;
    m_RowsVisible = 0;
    m_RowsFullyVisible = 0;
    m_ColumnsVisible = 0;
    m_ColumnsFullyVisible = 0;
    m_ResizeColumnIndex = -1;
    m_ResizeRowIndex = -1;
    m_ResizeRowTop = -1;
    m_NewRowSize = -1;
    m_ResizeColumnLeft = -1;
    m_Capture = false;
    m_ClickColumnIndex = -1;
    m_ClickRowIndex = -1;

    m_LineRestore = null;
    m_LineX = 0;
    m_LineY = 0;

    cellSelectionListeners = new ArrayList(10);
    cellResizeListeners = new ArrayList(10);

    // Listener
    createListeners();

  }

  protected void createListeners() {

    addPaintListener(new PaintListener() {
      public void paintControl(PaintEvent event) {
        onPaint(event);
      }
    });

    addControlListener(new ControlAdapter() {
      public void controlResized(ControlEvent e) {
        redraw();
      }
    });

    addMouseListener(new MouseAdapter() {
      public void mouseDown(MouseEvent e) {
        onMouseDown(e);
      }

      public void mouseUp(MouseEvent e) {
        onMouseUp(e);
      }

      public void mouseDoubleClick(MouseEvent e) {
        onMouseDoubleClick(e);
      }
    });

    addMouseMoveListener(new MouseMoveListener() {
      public void mouseMove(MouseEvent e) {
        onMouseMove(e);
      }
    });

    if (getVerticalBar() != null) {
      getVerticalBar().addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
          m_TopRow = getVerticalBar().getSelection();
          redraw();
        }

      });
    }

    if (getHorizontalBar() != null) {
      getHorizontalBar().addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
          m_LeftColumn = getHorizontalBar().getSelection();
          redraw();
        }
      });
    }
    addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        onKeyDown(e);
      }
    });
  }

  // ////////////////////////////////////////////////////////////////////////////
  // Berechnungen
  // ////////////////////////////////////////////////////////////////////////////

  protected int getFixedWidth() {
    int width = 0;
    for (int i = 0; i < m_Model.getFixedColumnCount(); i++)
      width += m_Model.getColumnWidth(i);
    return width;
  }

  protected int getColumnLeft(int index) {
    if (index < m_Model.getFixedColumnCount()) {
      int x = 0;
      for (int i = 0; i < index; i++) {
        x += m_Model.getColumnWidth(i);
      }
      return x;
    }
    if (index < m_LeftColumn)
      return -1;
    int x = getFixedWidth();
    for (int i = m_LeftColumn; i < index; i++) {
      x += m_Model.getColumnWidth(i);
    }
    return x;
  }

  protected int getColumnRight(int index) {
    if (index < 0)
      return 0;
    return getColumnLeft(index) + m_Model.getColumnWidth(index);
  }

  protected int getLastColumnRight() {
    return getColumnRight(m_Model.getColumnCount() - 1);
  }

  protected void doCalculations() {
    if (m_Model == null) {
      ScrollBar sb = getHorizontalBar();
      if (sb != null) {
        sb.setMinimum(0);
        sb.setMaximum(1);
        sb.setPageIncrement(1);
        sb.setThumb(1);
        sb.setSelection(1);
      }
      sb = getVerticalBar();
      if (sb != null) {
        sb.setMinimum(0);
        sb.setMaximum(1);
        sb.setPageIncrement(1);
        sb.setThumb(1);
        sb.setSelection(1);
      }
      return;
    }

    int m_HeaderHeight = m_Model.getFirstRowHeight();
    int m_RowHeight = m_Model.getRowHeight();

    Rectangle rect = getClientArea();
    if (m_LeftColumn < m_Model.getFixedColumnCount()) {
      m_LeftColumn = m_Model.getFixedColumnCount();
    }

    if (m_TopRow < m_Model.getFixedRowCount()) {
      m_TopRow = m_Model.getFixedRowCount();
    }

    int fixedWidth = getFixedWidth();
    int fixedHeight = m_HeaderHeight + (m_Model.getFixedRowCount() - 1)
        * m_Model.getRowHeight();
    m_ColumnsVisible = 0;
    m_ColumnsFullyVisible = 0;

    if (m_Model.getColumnCount() > m_Model.getFixedColumnCount()) {
      int runningWidth = getColumnLeft(m_LeftColumn);
      for (int col = m_LeftColumn; col < m_Model.getColumnCount(); col++) {
        if (runningWidth < rect.width + rect.x)
          m_ColumnsVisible++;
        runningWidth += m_Model.getColumnWidth(col);
        if (runningWidth < rect.width + rect.x)
          m_ColumnsFullyVisible++;
        else
          break;
      }
    }

    ScrollBar sb = getHorizontalBar();
    if (sb != null) {
      if (m_Model.getColumnCount() <= m_Model.getFixedColumnCount()) {
        sb.setMinimum(0);
        sb.setMaximum(1);
        sb.setPageIncrement(1);
        sb.setThumb(1);
        sb.setSelection(1);
      } else {
        sb.setMinimum(m_Model.getFixedColumnCount());
        sb.setMaximum(m_Model.getColumnCount());
        sb.setIncrement(1);
        sb.setPageIncrement(2);
        sb.setThumb(m_ColumnsFullyVisible);
        sb.setSelection(m_LeftColumn);
      }
    }

    m_RowsFullyVisible = Math.max(0, (rect.height - fixedHeight)
        / m_RowHeight);
    m_RowsFullyVisible = Math.min(m_RowsFullyVisible, m_Model.getRowCount()
        - m_Model.getFixedRowCount());
    m_RowsFullyVisible = Math.max(0, m_RowsFullyVisible);

    m_RowsVisible = m_RowsFullyVisible + 1;

    if (m_TopRow + m_RowsFullyVisible > m_Model.getRowCount()) {
      m_TopRow = Math.max(m_Model.getFixedRowCount(), m_Model
          .getRowCount()
          - m_RowsFullyVisible);
    }

    if (m_TopRow + m_RowsFullyVisible >= m_Model.getRowCount()) {
      m_RowsVisible--;
    }

    sb = getVerticalBar();
    if (sb != null) {
      if (m_Model.getRowCount() <= m_Model.getFixedRowCount()) {
        sb.setMinimum(0);
        sb.setMaximum(1);
        sb.setPageIncrement(1);
        sb.setThumb(1);
        sb.setSelection(1);
      } else {
        sb.setMinimum(m_Model.getFixedRowCount());
        sb.setMaximum(m_Model.getRowCount());
        sb.setPageIncrement(m_RowsVisible);
        sb.setIncrement(1);
        sb.setThumb(m_RowsFullyVisible);
        sb.setSelection(m_TopRow);
      }
    }
  }

  /**
   * Returns the area that is occupied by the given cell
   * 
   * @param col
   * @param row
   * @return Rectangle
   */
  public Rectangle getCellRect(int col, int row) {
    int m_HeaderHeight = m_Model.getFirstRowHeight();
    if ((col < 0) || (col >= m_Model.getColumnCount()))
      return new Rectangle(-1, -1, 0, 0);

    int x = getColumnLeft(col) + 1;
    int y;

    if (row == 0)
      y = 0;
    else if (row < m_Model.getFixedRowCount())
      y = m_HeaderHeight + ((row - 1) * m_Model.getRowHeight());
    else
      y = m_HeaderHeight
          + (m_Model.getFixedRowCount() - 1 + row - m_TopRow)
          * m_Model.getRowHeight();
    int width = m_Model.getColumnWidth(col) - 1;
    int height = m_Model.getRowHeight() - 1;
    if (row == 0)
      height = m_Model.getFirstRowHeight() - 1;

    return new Rectangle(x, y, width, height);
  }

  protected boolean canDrawCell(int col, int row, Rectangle clipRect) {
    Rectangle r = getCellRect(col, row);
    return canDrawCell(r, clipRect);
  }

  protected boolean canDrawCell(Rectangle r, Rectangle clipRect) {
    if (r.y + r.height < clipRect.y)
      return false;
    if (r.y > clipRect.y + clipRect.height)
      return false;
    if (r.x + r.width < clipRect.x)
      return false;
    if (r.x > clipRect.x + clipRect.width)
      return false;
    return true;
  }

  // ////////////////////////////////////////////////////////////////////////////
  // ZEICHNEN
  // ////////////////////////////////////////////////////////////////////////////

  // Paint-Ereignis

  protected void onPaint(PaintEvent event) {
    Rectangle rect = getClientArea();
    GC gc = event.gc;

    doCalculations();

    if (m_Model != null) {

      drawBottomSpace(gc);
      drawCells(gc, gc.getClipping(), 0, m_Model.getFixedColumnCount(),
          0, m_Model.getFixedRowCount());
      drawCells(gc, gc.getClipping(), m_LeftColumn, m_Model
          .getColumnCount(), 0, m_Model.getFixedRowCount());
      drawCells(gc, gc.getClipping(), 0, m_Model.getFixedColumnCount(),
          m_TopRow, m_TopRow + m_RowsVisible);
      drawCells(gc, gc.getClipping(), m_LeftColumn, m_Model
          .getColumnCount(), m_TopRow, m_TopRow + m_RowsVisible);
    } else {
      gc.fillRectangle(rect);
    }
  }

  // Bottom-Space

  protected void drawBottomSpace(GC gc) {
    Rectangle r = getClientArea();
    if (m_Model.getRowCount() > 0) {
      r.y = m_Model.getFirstRowHeight()
          + (m_Model.getFixedRowCount() - 1 + m_RowsVisible)
          * m_Model.getRowHeight() + 1;
    }

    gc.setBackground(getBackground());
    gc.fillRectangle(r);
    gc.fillRectangle(getLastColumnRight() + 2, 0, r.width, r.height);

    if (m_Model.getRowCount() > 0) {
      if (flatStyleSpecified)
        // gc.setForeground(this.getBackground());
        gc.setForeground(m_Display
            .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
      else
        gc.setForeground(m_Display
            .getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
      // Linke Schattenlinie
      gc.drawLine(0, 0, 0, r.y - 1);
    }

    if (!flatStyleSpecified)
      gc.setForeground(this.getBackground());
    else
      gc.setForeground(m_Display.getSystemColor(SWT.COLOR_WHITE));
    // Untere Abschlusslinie
    gc.drawLine(0, r.y - 1, getLastColumnRight() + 1, r.y - 1);

    // Rechte Abschlusslinie
    gc.drawLine(getLastColumnRight() + 1, 0, getLastColumnRight() + 1,
        r.y - 1);
  }

  // Cells

  /**
   * Redraws the the cells only in the given area.
   * 
   * @param cellsToRedraw
   *            Defines the area to redraw. The rectangles elements are not
   *            pixels but cell numbers.
   */
  public void redraw(Rectangle cellsToRedraw) {
    redraw(cellsToRedraw.x, cellsToRedraw.y, cellsToRedraw.width,
        cellsToRedraw.height);
  }

  /**
   * Redraws the the cells only in the given area.
   * 
   * @param firstCol
   * @param firstRow
   * @param numOfCols
   * @param numOfRows
   */
  public void redraw(int firstCol, int firstRow, int numOfCols, int numOfRows) {
    Rectangle clipRect = getClientArea();
    drawCells(new GC(this), clipRect, firstCol, firstCol + numOfCols,
        firstRow, firstRow + numOfRows);
  }

  protected void drawCells(GC gc, Rectangle clipRect, int fromCol, int toCol,
      int fromRow, int toRow) {
    int cnt = 0;
    Rectangle r;

    if (m_CellEditor != null) {
      if (!isCellVisible(m_CellEditor.m_Col, m_CellEditor.m_Row)) {
        Rectangle hide = new Rectangle(-101, -101, 100, 100);
        m_CellEditor.setBounds(hide);
      } else {
        m_CellEditor.setBounds(getCellRect(m_CellEditor.m_Col,
            m_CellEditor.m_Row));
      }
    }

    for (int row = fromRow; row < toRow; row++) {
      r = getCellRect(0, row);
      if (r.y + r.height < clipRect.y) {
        continue;
      }
      if (r.y > clipRect.y + clipRect.height) {
        break;
      }

      for (int col = fromCol; col < toCol; col++) {
        r = getCellRect(col, row);
        if (r.x > clipRect.x + clipRect.width) {
          break;
        }
        if (canDrawCell(col, row, clipRect)) {
          drawCell(gc, col, row);
          cnt++;
        }
      }
    }
  }

  protected void drawCell(GC gc, int col, int row) {
    if ((row < 0) || (row >= m_Model.getRowCount())) {
      return;
    }

    Rectangle rect = getCellRect(col, row);

    m_Model.getCellRenderer(col, row).drawCell(
        gc,
        rect,
        col,
        row,
        m_Model.getContentAt(col, row),
        showAsSelected(col, row),
        col < m_Model.getFixedColumnCount()
            || row < m_Model.getFixedRowCount(),
        col == m_ClickColumnIndex && row == m_ClickRowIndex);

  }

  protected boolean showAsSelected(int col, int row) {
    // A cell with an open editor should be drawn without focus
    if (m_CellEditor != null) {
      if (col == m_CellEditor.m_Col && row == m_CellEditor.m_Row)
        return false;
    }
    return isCellSelected(col, row);
  }

  protected void drawRow(GC gc, int row) {
    Rectangle clipRect = getClientArea();
    drawCells(gc, getClientArea(), 0, m_Model.getFixedColumnCount(), row,
        row + 1);
    drawCells(gc, getClientArea(), m_LeftColumn, m_Model.getColumnCount(),
        row, row + 1);
  }

  protected void drawCol(GC gc, int col) {
    Rectangle clipRect = getClientArea();
    drawCells(gc, clipRect, col, col + 1, 0, m_Model.getFixedRowCount());
    drawCells(gc, clipRect, col, col + 1, m_TopRow, m_TopRow
        + m_RowsVisible);
  }

  // ////////////////////////////////////////////////////////////////////////////
  // REAKTION AUF BENUTZER
  // ////////////////////////////////////////////////////////////////////////////

  /* gibt die Nummer einer Modellspalte zuruck */
  protected int getColumnForResize(int x, int y) {
    if (m_Model == null)
      return -1;
    if ((y <= 0)
        || (y >= m_Model.getFirstRowHeight()
            + (m_Model.getFixedRowCount() - 1)
            * m_Model.getRowHeight()))
      return -1;

    if (x < getFixedWidth() + 3) {
      for (int i = 0; i < m_Model.getFixedColumnCount(); i++)
        if (Math.abs(x - getColumnRight(i)) < 3) {
          if (m_Model.isColumnResizable(i))
            return i;
          return -1;
        }
    }

    for (int i = m_LeftColumn; i < m_Model.getColumnCount(); i++) {
      int left = getColumnLeft(i);
      int right = left + m_Model.getColumnWidth(i);
      if (Math.abs(x - right) < 3) {
        if (m_Model.isColumnResizable(i))
          return i;
        return -1;
      }
      if ((x >= left + 3) && (x <= right - 3))
        break;
    }
    return -1;
  }

  /* gibt die Nummer einer Zeile der Ansicht(!) zuruck */
  protected int getRowForResize(int x, int y) {
    if (m_Model == null)
      return -1;
    if ((x <= 0) || (x >= getFixedWidth()))
      return -1;

    if (y < m_Model.getFirstRowHeight())
      return -1;

    int row = 1 + ((y - m_Model.getFirstRowHeight()) / m_Model
        .getRowHeight());
    int rowY = m_Model.getFirstRowHeight() + row * m_Model.getRowHeight();

    if (Math.abs(rowY - y) < 3 && m_Model.isRowResizable())
      return row;

    return -1;
  }

  /**
   * Returns the number of the row that is present at position y or -1, if out
   * of area.
   * 
   * @param y
   * @return int
   */
  public int calcRowNum(int y) {
    if (m_Model == null)
      return -1;
    if (y < m_Model.getFirstRowHeight())
      return (m_Model.getFixedRowCount() == 0 ? m_TopRow : 0);
    y -= m_Model.getFirstRowHeight();
    int row = 1 + (y / m_Model.getRowHeight());
    if ((row < 0) || (row >= m_Model.getRowCount()))
      return -1;
    if (row >= m_Model.getFixedRowCount())
      return m_TopRow + row - m_Model.getFixedRowCount();
    return row;
  }

  /**
   * Returns the number of the column that is present at position x or -1, if
   * out of area.
   * 
   * @param y
   * @return int
   */
  public int calcColumnNum(int x) {
    if (m_Model == null)
      return -1;
    int col = 0;

    int z = 0;
    for (int i = 0; i < m_Model.getFixedColumnCount(); i++) {
      if ((x >= z) && (x <= z + m_Model.getColumnWidth(i))) {
        return i;
      }
      z += m_Model.getColumnWidth(i);
    }

    col = -1;
    z = getFixedWidth();
    for (int i = m_LeftColumn; i < m_Model.getColumnCount(); i++) {
      if ((x >= z) && (x <= z + m_Model.getColumnWidth(i))) {
        col = i;
        break;
      }
      z += m_Model.getColumnWidth(i);
    }
    return col;
  }

  public boolean isCellVisible(int col, int row) {
    if (m_Model == null)
      return false;
    return ((col >= m_LeftColumn && col < m_LeftColumn + m_ColumnsVisible
        && row >= m_TopRow && row < m_TopRow + m_RowsVisible)

    || (col < m_Model.getFixedColumnCount() && row < m_Model
        .getFixedRowCount()));
  }

  public boolean isCellFullyVisible(int col, int row) {
    if (m_Model == null)
      return false;
    return ((col >= m_LeftColumn
        && col < m_LeftColumn + m_ColumnsFullyVisible
        && row >= m_TopRow && row < m_TopRow + m_RowsFullyVisible)

    || (col < m_Model.getFixedColumnCount() && row < m_Model
        .getFixedRowCount()));
  }

  public boolean isRowVisible(int row) {
    if (m_Model == null)
      return false;
    return ((row >= m_TopRow && row < m_TopRow + m_RowsVisible) || row < m_Model
        .getFixedRowCount());

  }

  public boolean isRowFullyVisible(int row) {
    if (m_Model == null)
      return false;
    return ((row >= m_TopRow && row < m_TopRow + m_RowsFullyVisible) || row < m_Model
        .getFixedRowCount());
  }

  /*
   * Focusses the given Cell. Assumes that the given cell is in the viewable
   * area. Does all neccessary redraws.
   */
  protected void focusCell(int col, int row, int stateMask) {
    GC gc = new GC(this);

    // close cell editor if active
    if (m_CellEditor != null)
      m_CellEditor.close(true);

    /*
     * Special rule: in row selection mode the selection if a fixed cell in
     * a non-fixed row is allowed and handled as a selection of a non-fixed
     * cell.
     */

    if (row >= m_Model.getFixedRowCount()
        && (col >= m_Model.getFixedColumnCount() || m_RowSelectionMode)) {

      if ((stateMask & SWT.CTRL) == 0 && (stateMask & SWT.SHIFT) == 0) {
        // case: no modifier key
        boolean redrawAll = (m_Selection.size() > 1);
        int oldFocusRow = m_FocusRow;
        int oldFocusCol = m_FocusCol;
        clearSelectionWithoutRedraw();
        addToSelection(col, row);
        m_FocusRow = row;
        m_FocusCol = col;

        if (redrawAll)
          redraw();
        else if (m_RowSelectionMode) {
          if (isRowVisible(oldFocusRow))
            drawRow(gc, oldFocusRow);
          if (isRowVisible(m_FocusRow))
            drawRow(gc, m_FocusRow);
        } else {
          if (isCellVisible(oldFocusCol, oldFocusRow))
            drawCell(gc, oldFocusCol, oldFocusRow);
          if (isCellVisible(m_FocusCol, m_FocusRow))
            drawCell(gc, m_FocusCol, m_FocusRow);
        }
      }

      else if ((stateMask & SWT.CTRL) != 0) {
        // case: CTRL key pressed
        if (toggleSelection(col, row)) {
          m_FocusCol = col;
          m_FocusRow = row;
        }

        if (m_RowSelectionMode) {
          drawRow(gc, row);
        } else {
          drawCell(gc, col, row);
        }
      }

      else if ((stateMask & SWT.SHIFT) != 0) {
        // case: SHIFT key pressed

        if (m_RowSelectionMode) {
          if (row < m_FocusRow) {
            // backword selection
            while (row != m_FocusRow) {
              addToSelection(0, --m_FocusRow);
            }
          } else {
            // foreward selection
            while (row != m_FocusRow) {
              addToSelection(0, ++m_FocusRow);
            }
          }
        } else // cell selection mode
        {
          if (row < m_FocusRow
              || (row == m_FocusRow && col < m_FocusCol)) {
            // backword selection
            while (row != m_FocusRow || col != m_FocusCol) {
              m_FocusCol--;
              if (m_FocusCol < m_Model.getFixedColumnCount()) {
                m_FocusCol = m_Model.getColumnCount();
                m_FocusRow--;
              }
              addToSelection(m_FocusCol, m_FocusRow);
            }
          } else {
            // foreward selection
            while (row != m_FocusRow || col != m_FocusCol) {
              m_FocusCol++;
              if (m_FocusCol == m_Model.getColumnCount()) {
                m_FocusCol = m_Model.getFixedColumnCount();
                m_FocusRow++;
              }
              addToSelection(m_FocusCol, m_FocusRow);
            }
          }

        }

        redraw();
      }

      // notify non-fixed cell listeners
      fireCellSelection(col, row, stateMask);
    } else {
      // a fixed cell was focused
      drawCell(gc, col, row);
      // notify fixed cell listeners
      fireFixedCellSelection(col, row, stateMask);
    }

    gc.dispose();
  }

  protected void onMouseDown(MouseEvent e) {
    if (e.button == 1) {
      // deactivateEditor(true);
      setCapture(true);
      m_Capture = true;

      // Resize column?
      int columnIndex = getColumnForResize(e.x, e.y);
      if (columnIndex >= 0) {
        m_ResizeColumnIndex = columnIndex;
        m_ResizeColumnLeft = getColumnLeft(columnIndex);
        return;
      }

      // Resize row?
      int rowIndex = getRowForResize(e.x, e.y);
      if (rowIndex >= 0) {
        m_ResizeRowIndex = rowIndex;
        m_ResizeRowTop = m_Model.getFirstRowHeight() + (rowIndex - 1)
            * m_Model.getRowHeight();
        m_NewRowSize = m_Model.getRowHeight();
        return;
      }
    }

    // focus change
    int col = calcColumnNum(e.x);
    int row = calcRowNum(e.y);

    if (col == -1 || row == -1)
      return;

    m_ClickColumnIndex = col;
    m_ClickRowIndex = row;

    focusCell(col, row, e.stateMask);

  }

  protected void onMouseMove(MouseEvent e) {
    if (m_Model == null)
      return;

    // show resize cursor?
    if ((m_ResizeColumnIndex != -1) || (getColumnForResize(e.x, e.y) >= 0))
      setCursor(new Cursor(m_Display, SWT.CURSOR_SIZEWE));
    else if ((m_ResizeRowIndex != -1) || (getRowForResize(e.x, e.y) >= 0))
      setCursor(new Cursor(m_Display, SWT.CURSOR_SIZENS));
    else
      setCursor(null);

    if (e.button == 1) {
      // extend selection?
      if (m_ClickColumnIndex != -1 && m_MultiSelectMode) {
        int row = calcRowNum(e.y);
        int col = calcColumnNum(e.x);

        if (row >= m_Model.getFixedRowCount()
            && col >= m_Model.getFixedColumnCount()) {

          m_ClickColumnIndex = col;
          m_ClickRowIndex = row;

          focusCell(col, row, (e.stateMask | SWT.SHIFT));
        }
      }

    }
    // column resize?
    if (m_ResizeColumnIndex != -1) {
      Rectangle rect = getClientArea();
      int oldSize = m_Model.getColumnWidth(m_ResizeColumnIndex);
      if (e.x > rect.x + rect.width - 1)
        e.x = rect.x + rect.width - 1;
      int newSize = e.x - m_ResizeColumnLeft;
      if (newSize < 5)
        newSize = 5;

      int leftX = getColumnLeft(m_ResizeColumnIndex);
      int rightX = getColumnRight(m_ResizeColumnIndex);

      m_Model.setColumnWidth(m_ResizeColumnIndex, newSize);
      newSize = m_Model.getColumnWidth(m_ResizeColumnIndex);

      GC gc = new GC(this);
      gc.copyArea(rightX, 0, rect.width - rightX, rect.height, leftX
          + newSize, 0);
      drawCol(gc, m_ResizeColumnIndex);
      if (newSize < oldSize) {
        int delta = oldSize - newSize;
        redraw(rect.width - delta, 0, delta, rect.height, false);
      }
      gc.dispose();
    }

    // row resize?
    if (m_ResizeRowIndex != -1) {
      Rectangle rect = getClientArea();
      GC gc = new GC(this);

      // calculate new size
      if (e.y > rect.y + rect.height - 1)
        e.y = rect.y + rect.height - 1;
      m_NewRowSize = e.y - m_ResizeRowTop;
      if (m_NewRowSize < m_Model.getRowHeightMinimum())
        m_NewRowSize = m_Model.getRowHeightMinimum();

      // restore old line area
      if (m_LineRestore != null) {
        gc.drawImage(m_LineRestore, m_LineX, m_LineY);
      }

      // safe old picture and draw line
      gc.setForeground(Display.getCurrent().getSystemColor(
          SWT.COLOR_BLACK));
      int lineEnd = getColumnRight(m_LeftColumn + m_ColumnsVisible - 1);
      m_LineRestore = new Image(m_Display, lineEnd, 1);
      m_LineX = rect.x + 1;
      m_LineY = m_ResizeRowTop + m_NewRowSize - 1;
      gc.copyArea(m_LineRestore, m_LineX, m_LineY);
      gc.drawLine(m_LineX, m_LineY, rect.x + lineEnd, m_LineY);
      gc.dispose();

    }

  }

  protected void onMouseUp(MouseEvent e) {
    // if (e.button == 1)
    {
      if (m_Model == null)
        return;

      setCapture(false);
      m_Capture = false;

      if (m_ResizeColumnIndex != -1) {
        fireColumnResize(m_ResizeColumnIndex, m_Model
            .getColumnWidth(m_ResizeColumnIndex));
        m_ResizeColumnIndex = -1;
        redraw();

      }
      if (m_ResizeRowIndex != -1) {
        m_ResizeRowIndex = -1;
        m_Model.setRowHeight(m_NewRowSize);
        m_LineRestore = null;
        fireRowResize(m_NewRowSize);
        redraw();
      }
      if (m_ClickColumnIndex != -1) {
        int col = m_ClickColumnIndex;
        int row = m_ClickRowIndex;
        m_ClickColumnIndex = -1;
        m_ClickRowIndex = -1;
        if (m_CellEditor == null) {
          drawCell(new GC(this), col, row);
        }
      }

    }
  }

  protected void onKeyDown(KeyEvent e) {
    boolean focusChanged = false;
    int newFocusRow = m_FocusRow;
    int newFocusCol = m_FocusCol;

    if (m_Model == null)
      return;

    if ((e.character == ' ') || (e.character == '\r')) {
      openEditorInFocus();
      return;
    } else if (e.keyCode == SWT.HOME) {
      newFocusCol = m_Model.getFixedColumnCount();
      if (newFocusRow == -1)
        newFocusRow = m_Model.getFixedRowCount();
      focusChanged = true;
    } else if (e.keyCode == SWT.END) {
      newFocusCol = m_Model.getColumnCount() - 1;
      if (newFocusRow == -1)
        newFocusRow = m_Model.getFixedRowCount();
      focusChanged = true;
    } else if (e.keyCode == SWT.ARROW_LEFT) {
      if (!m_RowSelectionMode) {
        if (newFocusCol > m_Model.getFixedColumnCount())
          newFocusCol--;
      }
      focusChanged = true;
    } else if (e.keyCode == SWT.ARROW_RIGHT) {
      if (!m_RowSelectionMode) {
        if (newFocusCol == -1) {
          newFocusCol = m_Model.getFixedColumnCount();
          newFocusRow = m_Model.getFixedRowCount();
        } else if (newFocusCol < m_Model.getColumnCount() - 1)
          newFocusCol++;
      }
      focusChanged = true;
    } else if (e.keyCode == SWT.ARROW_DOWN) {
      if (newFocusRow == -1) {
        newFocusRow = m_Model.getFixedRowCount();
        newFocusCol = m_Model.getFixedColumnCount();
      } else if (newFocusRow < m_Model.getRowCount() - 1)
        newFocusRow++;
      focusChanged = true;
    } else if (e.keyCode == SWT.ARROW_UP) {
      if (newFocusRow > m_Model.getFixedRowCount())
        newFocusRow--;
      focusChanged = true;
    } else if (e.keyCode == SWT.PAGE_DOWN) {
      newFocusRow += m_RowsVisible - 1;
      if (newFocusRow >= m_Model.getRowCount())
        newFocusRow = m_Model.getRowCount() - 1;
      if (newFocusCol == -1)
        newFocusCol = m_Model.getFixedColumnCount();
      focusChanged = true;
    } else if (e.keyCode == SWT.PAGE_UP) {
      newFocusRow -= m_RowsVisible - 1;
      if (newFocusRow < m_Model.getFixedRowCount())
        newFocusRow = m_Model.getFixedRowCount();
      if (newFocusCol == -1)
        newFocusCol = m_Model.getFixedColumnCount();
      focusChanged = true;
    }

    if (focusChanged) {

      focusCell(newFocusCol, newFocusRow, e.stateMask);

      if (!isCellFullyVisible(m_FocusCol, m_FocusRow))
        scrollToFocus();
    }
  }

  protected void onMouseDoubleClick(MouseEvent e) {
    if (m_Model == null)
      return;
    if (e.button == 1) {

      if (e.y < m_Model.getFirstRowHeight()
          + ((m_Model.getFixedRowCount() - 1) * m_Model
              .getRowHeight())) {
        // double click in header area
        int columnIndex = getColumnForResize(e.x, e.y);
        resizeColumnOptimal(columnIndex);
        return;
      } else
        openEditorInFocus();
    }
  }

  /**
   * Resizes the given column to its optimal width.
   * 
   * Is also called if user doubleclicks in the resize area of a resizable
   * column.
   * 
   * The optimal width is determined by asking the CellRenderers for the
   * visible cells of the column for the optimal with and taking the minimum
   * of the results. Note that the optimal width is only determined for the
   * visible area of the table because otherwise this could take very long
   * time.
   * 
   * @param column
   *            The column to resize
   * @return int The optimal with that was determined or -1, if column out of
   *         range.
   */
  public int resizeColumnOptimal(int column) {
    if (column >= 0 && column < m_Model.getColumnCount()) {
      int optWidth = 5;
      for (int i = 0; i < m_Model.getFixedRowCount(); i++) {
        int width = m_Model.getCellRenderer(column, i).getOptimalWidth(
            m_GC, column, i, m_Model.getContentAt(column, i), true);
        if (width > optWidth)
          optWidth = width;
      }
      for (int i = m_TopRow; i < m_TopRow + m_RowsVisible; i++) {
        int width = m_Model.getCellRenderer(column, i).getOptimalWidth(
            m_GC, column, i, m_Model.getContentAt(column, i), true);
        if (width > optWidth)
          optWidth = width;
      }
      m_Model.setColumnWidth(column, optWidth);
      redraw();
      return optWidth;
    }
    return -1;
  }

  /**
   * This method activated the cell editor on the current focus cell, if the
   * table model allows cell editing for this cell.
   */
  public void openEditorInFocus() {
    m_CellEditor = m_Model.getCellEditor(m_FocusCol, m_FocusRow);
    if (m_CellEditor != null) {
      Rectangle r = getCellRect(m_FocusCol, m_FocusRow);
      m_CellEditor.open(this, m_FocusCol, m_FocusRow, r);
    }
  }

  /*
   * Tries to open KTableCellEditor on the given cell. If the cell exists, the
   * model is asked for an editor and if there is one, the table scrolls the
   * cell into the view and openes the editor on the cell. @param col @param
   * row
   * 
   * public void tryToOpenEditorAt(int col, int row) { if (col >= 0 && col <
   * m_Model.getColumnCount() && row >= 0 && row < m_Model.getRowCount()) {
   * m_CellEditor = m_Model.getCellEditor(col, row); if (m_CellEditor != null) {
   * m_FocusCol = col; m_FocusRow = row; scrollToFocus(); Rectangle r =
   * getCellRect(col, row); m_CellEditor.open(this, m_FocusCol, m_FocusRow,
   * r); } } }
   */

  protected void scrollToFocus() {
    boolean change = false;

    // vertical scroll allowed?
    if (getVerticalBar() != null) {
      if (m_FocusRow < m_TopRow) {
        m_TopRow = m_FocusRow;
        change = true;
      }

      if (m_FocusRow >= m_TopRow + m_RowsFullyVisible) {
        m_TopRow = m_FocusRow - m_RowsFullyVisible + 1;
        change = true;
      }

    }

    // horizontal scroll allowed?
    if (getHorizontalBar() != null) {
      if (m_FocusCol < m_LeftColumn) {
        m_LeftColumn = m_FocusCol;
        change = true;
      }

      if (m_FocusCol >= m_LeftColumn + m_ColumnsFullyVisible) {
        int oldLeftCol = m_LeftColumn;
        Rectangle rect = getClientArea();
        while (m_LeftColumn < m_FocusCol
            && getColumnRight(m_FocusCol) > rect.width + rect.x) {
          m_LeftColumn++;
        }
        change = (oldLeftCol != m_LeftColumn);
      }
    }

    if (change)
      redraw();
  }

  protected void fireCellSelection(int col, int row, int statemask) {
    for (int i = 0; i < cellSelectionListeners.size(); i++) {
      ((KTableCellSelectionListener) cellSelectionListeners.get(i))
          .cellSelected(col, row, statemask);
    }
  }

  protected void fireFixedCellSelection(int col, int row, int statemask) {
    for (int i = 0; i < cellSelectionListeners.size(); i++) {
      ((KTableCellSelectionListener) cellSelectionListeners.get(i))
          .fixedCellSelected(col, row, statemask);
    }
  }

  protected void fireColumnResize(int col, int newSize) {
    for (int i = 0; i < cellResizeListeners.size(); i++) {
      ((KTableCellResizeListener) cellResizeListeners.get(i))
          .columnResized(col, newSize);
    }
  }

  protected void fireRowResize(int newSize) {
    for (int i = 0; i < cellResizeListeners.size(); i++) {
      ((KTableCellResizeListener) cellResizeListeners.get(i))
          .rowResized(newSize);
    }
  }

  /**
   * Adds a listener that is notified when a cell is selected.
   * 
   * This can happen either by a click on the cell or by arrow keys. Note that
   * the listener is not called for each cell that the user selects in one
   * action using Shift+Click. To get all these cells use the listener and
   * getCellSelecion() or getRowSelection().
   * 
   * @param listener
   */
  public void addCellSelectionListener(KTableCellSelectionListener listener) {
    cellSelectionListeners.add(listener);
  }

  /**
   * Adds a listener that is notified when a cell is resized. This happens
   * when the mouse button is released after a resizing.
   * 
   * @param listener
   */
  public void addCellResizeListener(KTableCellResizeListener listener) {
    cellResizeListeners.add(listener);
  }

  /**
   * Removes the listener if present. Returns true, if found and removed from
   * the list of listeners.
   */
  public boolean removeCellSelectionListener(
      KTableCellSelectionListener listener) {
    return cellSelectionListeners.remove(listener);
  }

  /**
   * Removes the listener if present. Returns true, if found and removed from
   * the list of listeners.
   */
  public boolean removeCellResizeListener(KTableCellResizeListener listener) {
    return cellResizeListeners.remove(listener);
  }

  // ////////////////////////////////////////////////////////////////////////////
  // SELECTION
  // ////////////////////////////////////////////////////////////////////////////

  /**
   * Sets the "Row Selection Mode". The current selection is cleared when this
   * method is called.
   * 
   * @param rowSelectMode
   *            In the "Row Selection Mode", the table always selects a
   *            complete row. Otherwise, each individual cell can be selected.
   * 
   * This mode can be combined with the "Multi Selection Mode".
   * 
   */
  public void setRowSelectionMode(boolean rowSelectMode) {
    m_RowSelectionMode = rowSelectMode;
    clearSelection();
  }

  /**
   * Sets the "Multi Selection Mode". The current selection is cleared when
   * this method is called.
   * 
   * @param multiSelectMode
   *            In the "Multi Select Mode", more than one cell or row can be
   *            selected. The user can achieve this by shift-click and
   *            ctrl-click. The selected cells/rows can be scattored ofer the
   *            complete table. If you pass false, only a single cell or row
   *            can be selected.
   * 
   * This mode can be combined with the "Row Selection Mode".
   */
  public void setMultiSelectionMode(boolean multiSelectMode) {
    m_MultiSelectMode = multiSelectMode;
    clearSelection();
  }

  /**
   * Returns true if in "Row Selection Mode".
   * 
   * @see setSelectionMode
   * @return boolean
   */
  public boolean isRowSelectMode() {
    return m_RowSelectionMode;
  }

  /**
   * Returns true if in "Multi Selection Mode".
   * 
   * @see setSelectionMode
   * @return boolean
   */
  public boolean isMultiSelectMode() {
    return m_MultiSelectMode;
  }

  protected void clearSelectionWithoutRedraw() {
    m_Selection.clear();
  }

  /**
   * Clears the current selection (in all selection modes).
   */
  public void clearSelection() {
    /*
     * if (m_MultiSelectMode) { if (m_Selection.size() < m_RowsFullyVisible *
     * m_ColumnsVisible) { if (m_RowSelectionMode) { for (Iterator iter =
     * m_Selection.values().iterator(); iter.hasNext();) { int row =
     * ((Integer) iter.next()).intValue(); if (row >= m_TopRow && row <
     * m_TopRow+m_RowsFullyVisible) { } } } else { for (Iterator iter =
     * m_Selection.values().iterator(); iter.hasNext();) { Point element =
     * (Point) iter.next(); } } } }
     */
    clearSelectionWithoutRedraw();
    m_FocusCol = -1;
    m_FocusRow = -1;
    if (m_MultiSelectMode)
      redraw();
  }

  /*
   * works in both modes: Cell and Row Selection. Has no redraw functionality!
   * 
   * Returns true, if added to selection.
   */
  protected boolean toggleSelection(int col, int row) {

    if (m_MultiSelectMode) {
      Object o;
      if (m_RowSelectionMode) {
        o = new Integer(row);
      } else {
        o = new Point(col, row);
      }
      if (m_Selection.get(o) != null) {
        m_Selection.remove(o);
        return false;
      } else {
        m_Selection.put(o, o);
        return true;
      }
    }
    return false;
  }

  /*
   * works in both modes: Cell and Row Selection. Has no redraw functionality!
   */
  protected void addToSelection(int col, int row) {
    if (m_MultiSelectMode) {
      if (m_RowSelectionMode) {
        Integer o = new Integer(row);
        m_Selection.put(o, o);
      } else {
        Point o = new Point(col, row);
        m_Selection.put(o, o);
      }
    }
    // System.out.println(m_Selection.size()+" "+col+"/"+row);
  }

  /**
   * Selects the given cell. If scroll is true, it scrolls to show this cell
   * if neccessary. In Row Selection Mode, the given row is selected and a
   * scroll to the given column is done. Does nothing if the cell does not
   * exist.
   * 
   * @param col
   * @param row
   * @param scroll
   */
  public void setSelection(int col, int row, boolean scroll) {
    if (col < m_Model.getColumnCount()
        && col >= m_Model.getFixedColumnCount()
        && row < m_Model.getRowCount()
        && row >= m_Model.getFixedRowCount()) {
      focusCell(col, row, 0);
      if (scroll) {
        scrollToFocus();
      }
    }
  }

  /**
   * Returns true, if the given cell is selected. Works also in Row Selection
   * Mode.
   * 
   * @param col
   * @param row
   * @return boolean
   */
  public boolean isCellSelected(int col, int row) {
    if (!m_MultiSelectMode) {
      if (m_RowSelectionMode)
        return (row == m_FocusRow);
      return (col == m_FocusCol && row == m_FocusRow);
    }

    if (m_RowSelectionMode)
      return (m_Selection.get(new Integer(row)) != null);
    else
      return (m_Selection.get(new Point(col, row)) != null);
  }

  /**
   * Returns true, if the given row is selected. Returns always false if not
   * in Row Selection Mode!
   * 
   * @param row
   * @return boolean
   */
  public boolean isRowSelected(int row) {
    return (m_Selection.get(new Integer(row)) != null);
  }

  /**
   * Returns an array of the selected row numbers. Returns null if not in Row
   * Selection Mode. Returns an array with one or none element if not in Multi
   * Selection Mode.
   * 
   * @return int[]
   */
  public int[] getRowSelection() {
    if (!m_RowSelectionMode)
      return null;
    if (!m_MultiSelectMode) {
      if (m_FocusRow < 0)
        return new int[0];
      int[] tmp = new int[1];
      tmp[0] = m_FocusRow;
      return tmp;
    }

    Object[] ints = m_Selection.values().toArray();
    int[] erg = new int[ints.length];

    for (int i = 0; i < erg.length; i++) {
      erg[i] = ((Integer) ints[i]).intValue();
    }
    return erg;
  }

  /**
   * Returns an array of the selected cells as Point[]. The columns are stored
   * in the x fields, rows in y fields. Returns null if in Row Selection Mode.
   * Returns an array with one or none element if not in Multi Selection Mode.
   * 
   * @return int[]
   */
  public Point[] getCellSelection() {
    if (m_RowSelectionMode)
      return null;
    if (!m_MultiSelectMode) {
      if (m_FocusRow < 0 || m_FocusCol < 0)
        return new Point[0];
      Point[] tmp = new Point[1];
      tmp[0] = new Point(m_FocusCol, m_FocusRow);
      return tmp;
    }

    return (Point[]) m_Selection.values().toArray(new Point[1]);
  }

  // ////////////////////////////////////////////////////////////////////////////
  // MODEL
  // ////////////////////////////////////////////////////////////////////////////

  /**
   * Sets the table model. The table model provides data to the table.
   * 
   * @see de.kupzog.ktable.KTableModel for more information.
   * @param model
   */
  public void setModel(KTableModel model) {
    m_Model = model;
    m_FocusCol = -1;
    m_FocusRow = -1;
    clearSelectionWithoutRedraw();
    redraw();
  }

  /**
   * returns the current table model
   * 
   * @return KTableModel
   */
  public KTableModel getModel() {
    return m_Model;
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

abstract class KTableCellEditor {

  protected KTableModel m_Model;

  protected KTable m_Table;

  protected Rectangle m_Rect;

  protected int m_Row;

  protected int m_Col;

  protected Control m_Control;

  protected String toolTip;

  /**
   * disposes the editor and its components
   */
  public void dispose() {
    if (m_Control != null) {
      m_Control.dispose();
      m_Control = null;
    }
  }

  /**
   * Activates the editor at the given position.
   * 
   * @param row
   * @param col
   * @param rect
   */
  public void open(KTable table, int col, int row, Rectangle rect) {
    m_Table = table;
    m_Model = table.getModel();
    m_Rect = rect;
    m_Row = row;
    m_Col = col;
    if (m_Control == null) {
      m_Control = createControl();
      m_Control.setToolTipText(toolTip);
      m_Control.addFocusListener(new FocusAdapter() {
        public void focusLost(FocusEvent arg0) {
          close(true);
        }
      });
    }
    setBounds(m_Rect);
    GC gc = new GC(m_Table);
    m_Table.drawCell(gc, m_Col, m_Row);
    gc.dispose();
  }

  /**
   * Deactivates the editor.
   * 
   * @param save
   *            If true, the content is saved to the underlying table.
   */
  public void close(boolean save) {
    m_Table.m_CellEditor = null;
    // m_Control.setVisible(false);
    GC gc = new GC(m_Table);
    m_Table.drawCell(gc, m_Col, m_Row);
    gc.dispose();
    this.dispose();
  }

  /**
   * Returns true if the editor has the focus.
   * 
   * @return boolean
   */
  public boolean isFocused() {
    if (m_Control == null)
      return false;
    return m_Control.isFocusControl();
  }

  /**
   * Sets the editor's position and size
   * 
   * @param rect
   */
  public void setBounds(Rectangle rect) {
    if (m_Control != null)
      m_Control.setBounds(rect);
  }

  /*
   * Creates the editor's control. Has to be overwritten by useful editor
   * implementations.
   */
  protected abstract Control createControl();

  protected void onKeyPressed(KeyEvent e) {
    if ((e.character == '\r') && ((e.stateMask & SWT.SHIFT) == 0)) {
      close(true);
    } else if (e.character == SWT.ESC) {
      close(false);
    } else {
      m_Table.scrollToFocus();
    }
  }

  protected void onTraverse(TraverseEvent e) {
    close(true);
    // m_Table.tryToOpenEditorAt(m_Col+1, m_Row);
  }

  /**
   * @param toolTip
   */
  public void setToolTipText(String toolTip) {
    this.toolTip = toolTip;
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

class KTableCellEditorCombo extends KTableCellEditor {
  private CCombo m_Combo;

  private String m_Items[];

  public void open(KTable table, int row, int col, Rectangle rect) {
    super.open(table, row, col, rect);
    m_Combo.setFocus();
    m_Combo.setText((String) m_Model.getContentAt(m_Col, m_Row));
  }

  public void close(boolean save) {
    if (save)
      m_Model.setContentAt(m_Col, m_Row, m_Combo.getText());
    super.close(save);
    m_Combo = null;
  }

  protected Control createControl() {
    m_Combo = new CCombo(m_Table, SWT.READ_ONLY);
    m_Combo.setBackground(Display.getCurrent().getSystemColor(
        SWT.COLOR_LIST_BACKGROUND));
    if (m_Items != null)
      m_Combo.setItems(m_Items);
    m_Combo.addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        try {
          onKeyPressed(e);
        } catch (Exception ex) {
        }
      }
    });
    /*
     * m_Combo.addTraverseListener(new TraverseListener() { public void
     * keyTraversed(TraverseEvent arg0) { onTraverse(arg0); } });
     */
    return m_Combo;
  }

  public void setBounds(Rectangle rect) {
    super.setBounds(new Rectangle(rect.x, rect.y + 1, rect.width,
        rect.height - 2));
  }

  public void setItems(String items[]) {
    m_Items = items;
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/
class KTableCellEditorMultilineText extends KTableCellEditor {
  private Text m_Text;

  public void open(KTable table, int col, int row, Rectangle rect) {
    super.open(table, col, row, rect);
    m_Text.setText(m_Model.getContentAt(m_Col, m_Row).toString());
    m_Text.selectAll();
    m_Text.setVisible(true);
    m_Text.setFocus();
  }

  public void close(boolean save) {
    if (save)
      m_Model.setContentAt(m_Col, m_Row, m_Text.getText());
    m_Text = null;
    super.close(save);
  }

  protected Control createControl() {
    m_Text = new Text(m_Table, SWT.MULTI | SWT.V_SCROLL);
    m_Text.addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        try {
          onKeyPressed(e);
        } catch (Exception ex) {
        }
      }
    });
    m_Text.addTraverseListener(new TraverseListener() {
      public void keyTraversed(TraverseEvent arg0) {
        onTraverse(arg0);
      }
    });
    return m_Text;
  }

  /*
   * overridden from superclass
   */
  public void setBounds(Rectangle rect) {
    super.setBounds(new Rectangle(rect.x, rect.y, rect.width, rect.height));
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/
class KTableCellEditorMultilineWrapText extends KTableCellEditor {
  private Text m_Text;

  public void open(KTable table, int col, int row, Rectangle rect) {
    super.open(table, col, row, rect);
    m_Text.setText(m_Model.getContentAt(m_Col, m_Row).toString());
    m_Text.selectAll();
    m_Text.setVisible(true);
    m_Text.setFocus();
  }

  public void close(boolean save) {
    if (save)
      m_Model.setContentAt(m_Col, m_Row, m_Text.getText());
    m_Text = null;
    super.close(save);
  }

  protected Control createControl() {
    m_Text = new Text(m_Table, SWT.MULTI | SWT.V_SCROLL | SWT.WRAP);
    m_Text.addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        try {
          onKeyPressed(e);
        } catch (Exception ex) {
        }
      }
    });
    m_Text.addTraverseListener(new TraverseListener() {
      public void keyTraversed(TraverseEvent arg0) {
        onTraverse(arg0);
      }
    });
    return m_Text;
  }

  /*
   * overridden from superclass
   */
  public void setBounds(Rectangle rect) {
    super.setBounds(new Rectangle(rect.x, rect.y, rect.width, rect.height));
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

class KTableCellEditorText extends KTableCellEditor {
  private Text m_Text;

  public void open(KTable table, int col, int row, Rectangle rect) {
    super.open(table, col, row, rect);
    m_Text.setText(m_Model.getContentAt(m_Col, m_Row).toString());
    m_Text.selectAll();
    m_Text.setVisible(true);
    m_Text.setFocus();
  }

  public void close(boolean save) {
    if (save)
      m_Model.setContentAt(m_Col, m_Row, m_Text.getText());
    super.close(save);
    m_Text = null;
    // System.out.println("set to null.");
  }

  protected Control createControl() {
    // System.out.println("Created a new one.");
    m_Text = new Text(m_Table, SWT.NONE);
    m_Text.addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        try {
          onKeyPressed(e);
        } catch (Exception ex) {
        }
      }
    });
    m_Text.addTraverseListener(new TraverseListener() {
      public void keyTraversed(TraverseEvent arg0) {
        onTraverse(arg0);
      }
    });
    return m_Text;
  }

  /*
   * overridden from superclass
   */
  public void setBounds(Rectangle rect) {
    super.setBounds(new Rectangle(rect.x, rect.y + (rect.height - 15) / 2
        + 1, rect.width, 15));
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/
class KTableCellRenderer {

  public static KTableCellRenderer defaultRenderer = new KTableCellRenderer();

  /**
   * 
   */
  protected Display m_Display;

  public KTableCellRenderer() {
    m_Display = Display.getCurrent();
  }

  /**
   * Returns the optimal width of the given cell (used by column resizing)
   * 
   * @param col
   * @param row
   * @param content
   * @param fixed
   * @return int
   */
  public int getOptimalWidth(GC gc, int col, int row, Object content,
      boolean fixed) {
    return gc.stringExtent(content.toString()).x + 8;
  }

  /**
   * Standard implementation for CellRenderer. Draws a cell at the given
   * position. Uses the .getString() method of content to get a String
   * representation to draw.
   * 
   * @param gc
   *            The gc to draw on
   * @param rect
   *            The coordinates and size of the cell (add 1 to width and hight
   *            to include the borders)
   * @param col
   *            The column
   * @param row
   *            The row
   * @param content
   *            The content of the cell (as given by the table model)
   * @param focus
   *            True if the cell is selected
   * @param fixed
   *            True if the cell is fixed (unscrollable header cell)
   * @param clicked
   *            True if the cell is currently clicked (useful e.g. to paint a
   *            pressed button)
   */
  public void drawCell(GC gc, Rectangle rect, int col, int row,
      Object content, boolean focus, boolean fixed, boolean clicked) {
    if (fixed) {

      rect.height += 1;
      rect.width += 1;
      gc.setForeground(Display.getCurrent().getSystemColor(
          SWT.COLOR_LIST_FOREGROUND));
      if (clicked) {
        SWTX
            .drawButtonDown(gc, content.toString(),
                SWTX.ALIGN_HORIZONTAL_LEFT
                    | SWTX.ALIGN_VERTICAL_CENTER, null,
                SWTX.ALIGN_HORIZONTAL_RIGHT
                    | SWTX.ALIGN_VERTICAL_CENTER, rect);
      } else {
        SWTX
            .drawButtonUp(gc, content.toString(),
                SWTX.ALIGN_HORIZONTAL_LEFT
                    | SWTX.ALIGN_VERTICAL_CENTER, null,
                SWTX.ALIGN_HORIZONTAL_RIGHT
                    | SWTX.ALIGN_VERTICAL_CENTER, rect);
      }

      return;
    }

    Color textColor;
    Color backColor;
    Color vBorderColor;
    Color hBorderColor;

    if (focus) {
      textColor = m_Display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT);
      backColor = (m_Display.getSystemColor(SWT.COLOR_LIST_SELECTION));
      vBorderColor = m_Display.getSystemColor(SWT.COLOR_LIST_SELECTION);
      hBorderColor = m_Display.getSystemColor(SWT.COLOR_LIST_SELECTION);
    } else {
      textColor = m_Display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
      backColor = m_Display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
      vBorderColor = m_Display
          .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
      hBorderColor = m_Display
          .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
    }

    gc.setForeground(hBorderColor);
    gc.drawLine(rect.x, rect.y + rect.height, rect.x + rect.width, rect.y
        + rect.height);

    gc.setForeground(vBorderColor);
    gc.drawLine(rect.x + rect.width, rect.y, rect.x + rect.width, rect.y
        + rect.height);

    gc.setBackground(backColor);
    gc.setForeground(textColor);

    gc.fillRectangle(rect);

    SWTX.drawTextImage(gc, content.toString(), SWTX.ALIGN_HORIZONTAL_CENTER
        | SWTX.ALIGN_VERTICAL_CENTER, null,
        SWTX.ALIGN_HORIZONTAL_CENTER | SWTX.ALIGN_VERTICAL_CENTER,
        rect.x + 3, rect.y, rect.width - 3, rect.height);

  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

class KTableCellResizeAdapter implements KTableCellResizeListener {

  public void columnResized(int col, int newWidth) {
  }

  public void rowResized(int newHeight) {
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

interface KTableCellResizeListener {

  /**
   * Is called when a row is resized.
   */
  public void rowResized(int newHeight);

  /**
   * Is called when a column is resized.
   */
  public void columnResized(int col, int newWidth);

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

class KTableCellSelectionAdapter implements KTableCellSelectionListener {
  /**
   * Is called if a non-fixed cell is selected (gets the focus).
   * 
   * @see KTable for an explanation of the term "fixed cells".
   * @param col
   *            the column of the cell
   * @param row
   *            the row of the cell
   * @param statemask
   *            the modifier keys that where pressed when the selection
   *            happened.
   */
  public void cellSelected(int col, int row, int statemask) {
  }

  /**
   * Is called if a fixed cell is selected (is clicked).
   * 
   * @see KTable for an explanation of the term "fixed cells".
   * @param col
   *            the column of the cell
   * @param row
   *            the row of the cell
   * @param statemask
   *            the modifier keys that where pressed when the selection
   *            happened.
   */
  public void fixedCellSelected(int col, int row, int statemask) {
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

interface KTableCellSelectionListener {

  /**
   * Is called if a non-fixed cell is selected (gets the focus).
   * 
   * @see KTable for an explanation of the term "fixed cells".
   * @param col
   *            the column of the cell
   * @param row
   *            the row of the cell
   * @param statemask
   *            the modifier keys that where pressed when the selection
   *            happened.
   */
  public void cellSelected(int col, int row, int statemask);

  /**
   * Is called if a fixed cell is selected (is clicked).
   * 
   * @see KTable for an explanation of the term "fixed cells".
   * @param col
   *            the column of the cell
   * @param row
   *            the row of the cell
   * @param statemask
   *            the modifier keys that where pressed when the selection
   *            happened.
   */
  public void fixedCellSelected(int col, int row, int statemask);

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

/**
 * @author kupzog (c) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * The table model is the most important part of KTable. It provides - content
 * information - layout information - rendering information to the KTable.
 * 
 * Generally speaking, all functions should return their results as quick as
 * possible. If the table is slow, check it with KTableModelBasic. It is no
 * longer slow, your model should be tuned.
 * 
 */

interface KTableModel {

  /**
   * This function should return the content at the given position. The
   * content is an Object, that means it can be everything.
   * 
   * The returned Object is handed over to the KTableCellRenderer. You can
   * deciede which renderer is used in getCellRenderer. Usually, the renderer
   * expects the content being of a certain type.
   */
  Object getContentAt(int col, int row);

  /**
   * A table cell will be "in place editable" if this method returns a valid
   * cell editor for the given cell. For no edit functionalitity return null.
   * 
   * @param col
   * @param row
   * @return KTableCellEditor
   */
  KTableCellEditor getCellEditor(int col, int row);

  /**
   * If getCellEditor() does return eny editors instead of null, the table
   * will use this method to set the changed cell values.
   * 
   * @param col
   * @param row
   */
  void setContentAt(int col, int row, Object value);

  /**
   * This function tells the KTable how many rows have to be displayed. KTable
   * counts header rows as normal rows, so the number of header rows has to be
   * added to the number of data rows. The function must at least return the
   * number of fixed rows.
   * 
   * @return int
   */
  int getRowCount();

  /**
   * This function tells the KTable how many rows form the "column header".
   * These rows are always displayed and not scrolled.
   * 
   * @return int
   */
  int getFixedRowCount();

  /**
   * This function tells the KTable how many columns have to be displayed. It
   * must at least return the number of fixed Columns.
   */
  int getColumnCount();

  /**
   * This function tells the KTable how many columns form the "row header".
   * These columns are always displayed and not scrolled.
   * 
   * @return int
   */
  int getFixedColumnCount();

  /**
   * Each column can have its individual width. The model has to manage these
   * widths and return the values with this function.
   * 
   * @param col
   * @return int
   */
  int getColumnWidth(int col);

  /**
   * This function should return true if the user should be allowed to resize
   * the given column. (all rows have the same height except the first)
   * 
   * @param col
   * @return boolean
   */
  boolean isColumnResizable(int col);

  /**
   * Each column can have its individual width. The model has to manage these
   * widths. If the user resizes a column, the model has to keep track of
   * these changes. The model is informed about such a resize by this method.
   * (view updates are managed by the table)
   * 
   * @param col
   * @param value
   */
  void setColumnWidth(int col, int value);

  /**
   * All rows except the first row have the same height.
   * 
   * @return int
   */
  int getRowHeight();

  /**
   * Returns the height of the first row, usually the header row. If no header
   * is needed, this function should return the same value as getRowHeight.
   * 
   * @return int
   */
  int getFirstRowHeight();

  /**
   * This function should return true if the user should be allowed to resize
   * the rows.
   * 
   * @param col
   * @return boolean
   */
  boolean isRowResizable();

  /**
   * This function should return the minimum height of the rows. It is only
   * needed if the rows are resizable.
   * 
   * @return int
   */
  int getRowHeightMinimum();

  /**
   * If the user resizes a row, the model has to keep track of these changes.
   * The model is informed about such a resize by this method. (view updates
   * are managed by the table)
   */
  void setRowHeight(int value);

  /**
   * Returns the cell renderer for the given cell. For a first approach,
   * KTableCellRenderer.defaultRenderer can be returned. Derive
   * KTableCellRenderer to change the tables appearance.
   * 
   * @param col
   * @param row
   * @return KTableCellRenderer
   */
  KTableCellRenderer getCellRenderer(int col, int row);
}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

/**
 * @author Friederich Kupzog
 */
class KTableModelExample implements KTableModel {

  private int[] colWidths;

  private int rowHeight;

  private HashMap content;

  /**
   * 
   */
  public KTableModelExample() {
    colWidths = new int[getColumnCount()];
    for (int i = 0; i < colWidths.length; i++) {
      colWidths[i] = 270;
    }
    rowHeight = 18;
    content = new HashMap();
  }

  // Inhalte

  public Object getContentAt(int col, int row) {
    // System.out.println("col "+col+" row "+row);
    String erg = (String) content.get(col + "/" + row);
    if (erg != null)
      return erg;
    return col + "/" + row;
  }

  /*
   * overridden from superclass
   */
  public KTableCellEditor getCellEditor(int col, int row) {
    if (col % 2 == 0) {
      KTableCellEditorCombo e = new KTableCellEditorCombo();
      e
          .setItems(new String[] { "First text", "Second text",
              "third text" });
      return e;
    } else
      return new KTableCellEditorText();
  }

  /*
   * overridden from superclass
   */
  public void setContentAt(int col, int row, Object value) {
    content.put(col + "/" + row, value);
    //
  }

  // Umfang

  public int getRowCount() {
    return 100;
  }

  public int getFixedRowCount() {
    return 2;
  }

  public int getColumnCount() {
    return 100;
  }

  public int getFixedColumnCount() {
    return 1;
  }

  // GroBen

  public int getColumnWidth(int col) {
    return colWidths[col];
  }

  public int getRowHeight() {
    return rowHeight;
  }

  public boolean isColumnResizable(int col) {
    return true;
  }

  public int getFirstRowHeight() {
    return 22;
  }

  public boolean isRowResizable() {
    return true;
  }

  public int getRowHeightMinimum() {
    return 18;
  }

  public void setColumnWidth(int col, int value) {
    colWidths[col] = value;
  }

  public void setRowHeight(int value) {
    if (value < 2)
      value = 2;
    rowHeight = value;
  }

  // Rendering

  public KTableCellRenderer getCellRenderer(int col, int row) {
    return KTableCellRenderer.defaultRenderer;
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

class PaletteExampleModel implements KTableModel {

  /*
   * overridden from superclass
   */
  public Object getContentAt(int col, int row) {
    return new RGB(col * 16, row * 16, (col + row) * 8);
  }

  /*
   * overridden from superclass
   */
  public KTableCellEditor getCellEditor(int col, int row) {
    return null;
  }

  /*
   * overridden from superclass
   */
  public void setContentAt(int col, int row, Object value) {
  }

  /*
   * overridden from superclass
   */
  public int getRowCount() {
    return 16;
  }

  /*
   * overridden from superclass
   */
  public int getFixedRowCount() {
    return 0;
  }

  /*
   * overridden from superclass
   */
  public int getColumnCount() {
    return 16;
  }

  /*
   * overridden from superclass
   */
  public int getFixedColumnCount() {
    return 0;
  }

  /*
   * overridden from superclass
   */
  public int getColumnWidth(int col) {
    return 10;
  }

  /*
   * overridden from superclass
   */
  public boolean isColumnResizable(int col) {
    return false;
  }

  /*
   * overridden from superclass
   */
  public void setColumnWidth(int col, int value) {
  }

  /*
   * overridden from superclass
   */
  public int getRowHeight() {
    return 10;
  }

  /*
   * overridden from superclass
   */
  public int getFirstRowHeight() {
    return 10;
  }

  /*
   * overridden from superclass
   */
  public boolean isRowResizable() {
    return false;
  }

  /*
   * overridden from superclass
   */
  public int getRowHeightMinimum() {
    return 10;
  }

  /*
   * overridden from superclass
   */
  public void setRowHeight(int value) {
  }

  private static KTableCellRenderer myRenderer = new PaletteExampleRenderer();

  /*
   * overridden from superclass
   */
  public KTableCellRenderer getCellRenderer(int col, int row) {
    return myRenderer;
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

class PaletteExampleRenderer extends KTableCellRenderer {

  /**
   * 
   */
  public PaletteExampleRenderer() {
  }

  /*
   * overridden from superclass
   */
  public int getOptimalWidth(GC gc, int col, int row, Object content,
      boolean fixed) {
    return 16;
  }

  /*
   * overridden from superclass
   */
  public void drawCell(GC gc, Rectangle rect, int col, int row,
      Object content, boolean focus, boolean fixed, boolean clicked) {
    // Performance test:
    /*
     * gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
     * gc.fillRectangle(rect);
     * 
     * int j=1; for (int i = 0; i < 10000000; i++) { j++; }
     */
    Color color = new Color(m_Display, (RGB) content);
    gc.setBackground(m_Display.getSystemColor(SWT.COLOR_WHITE));
    rect.height++;
    rect.width++;
    gc.fillRectangle(rect);

    gc.setBackground(color);
    if (!focus) {
      rect.x += 1;
      rect.y += 1;
      rect.height -= 2;
      rect.width -= 2;
    }
    gc.fillRectangle(rect);
    color.dispose();
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

class TownExampleModel implements KTableModel {

  private int[] colWidths;

  private TownExampleContent[] content;

  public TownExampleModel() {
    colWidths = new int[getColumnCount()];
    colWidths[0] = 120;
    colWidths[1] = 100;
    colWidths[2] = 180;

    content = new TownExampleContent[3];
    content[0] = new TownExampleContent("Aachen", "Germany");
    content[1] = new TownExampleContent("Cologne", "Germany");
    content[2] = new TownExampleContent("Edinburgh", "Scotland");

  }

  /*
   * overridden from superclass
   */
  public Object getContentAt(int col, int row) {
    if (row == 0) // Header
    {
      if (col == 0)
        return "Town";
      else if (col == 1)
        return "Country";
      else
        return "Notes";
    } else {
      return content[row - 1];
    }
  }

  /*
   * overridden from superclass
   */
  public KTableCellEditor getCellEditor(int col, int row) {
    if (row > 0 && col == 2)
      return new KTableCellEditorMultilineText();
    return null;
  }

  /*
   * overridden from superclass
   */
  public void setContentAt(int col, int row, Object value) {
    content[row - 1].notes = (String) value;
  }

  /*
   * overridden from superclass
   */
  public int getRowCount() {
    return 4;
  }

  /*
   * overridden from superclass
   */
  public int getFixedRowCount() {
    return 1;
  }

  /*
   * overridden from superclass
   */
  public int getColumnCount() {
    return 3;
  }

  /*
   * overridden from superclass
   */
  public int getFixedColumnCount() {
    return 0;
  }

  /*
   * overridden from superclass
   */
  public int getColumnWidth(int col) {
    return colWidths[col];
  }

  /*
   * overridden from superclass
   */
  public boolean isColumnResizable(int col) {
    return (col != 0);
  }

  /*
   * overridden from superclass
   */
  public void setColumnWidth(int col, int value) {
    if (value > 120)
      colWidths[col] = value;
  }

  /*
   * overridden from superclass
   */
  public int getRowHeight() {
    return 140;
  }

  /*
   * overridden from superclass
   */
  public int getFirstRowHeight() {
    return 20;
  }

  /*
   * overridden from superclass
   */
  public boolean isRowResizable() {
    return false;
  }

  /*
   * overridden from superclass
   */
  public int getRowHeightMinimum() {
    return 20;
  }

  /*
   * overridden from superclass
   */
  public void setRowHeight(int value) {
  }

  /*
   * overridden from superclass
   */
  public KTableCellRenderer getCellRenderer(int col, int row) {
    if (row > 0)
      return new TownExampleRenderer();
    return KTableCellRenderer.defaultRenderer;
  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

class TownExampleRenderer extends KTableCellRenderer {

  protected Display m_Display;

  public TownExampleRenderer() {
    m_Display = Display.getCurrent();
  }

  public int getOptimalWidth(GC gc, int col, int row, Object content,
      boolean fixed) {
    return Math.max(gc.stringExtent(content.toString()).x + 8, 120);
  }

  public void drawCell(GC gc, Rectangle rect, int col, int row,
      Object content, boolean focus, boolean fixed, boolean clicked) {
    Color textColor;
    Color backColor;
    Color borderColor;
    TownExampleContent myContent = (TownExampleContent) content;

    if (focus) {
      textColor = m_Display.getSystemColor(SWT.COLOR_BLUE);
    } else {
      textColor = m_Display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
    }
    backColor = (m_Display.getSystemColor(SWT.COLOR_LIST_BACKGROUND));
    borderColor = m_Display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);

    gc.setForeground(borderColor);
    gc.drawLine(rect.x, rect.y + rect.height, rect.x + rect.width, rect.y
        + rect.height);

    gc.setForeground(borderColor);
    gc.drawLine(rect.x + rect.width, rect.y, rect.x + rect.width, rect.y
        + rect.height);

    if (col == 0) {
      gc.setBackground(m_Display
          .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
      textColor = m_Display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
      gc.setForeground(textColor);

      gc.drawImage((myContent.image), rect.x, rect.y);

      rect.y += 120;
      rect.height -= 120;
      gc.fillRectangle(rect);
      gc.drawText((myContent.name), rect.x + 25, rect.y + 2);
    }

    else if (col == 1) {
      gc.setBackground(backColor);
      gc.setForeground(textColor);

      gc.fillRectangle(rect);

      SWTX.drawTextImage(gc, myContent.country,
          SWTX.ALIGN_HORIZONTAL_LEFT | SWTX.ALIGN_VERTICAL_TOP, null,
          SWTX.ALIGN_HORIZONTAL_LEFT | SWTX.ALIGN_VERTICAL_CENTER,
          rect.x + 3, rect.y, rect.width - 3, rect.height);

    }

    else if (col == 2) {
      gc.setBackground(backColor);
      gc.setForeground(textColor);

      gc.fillRectangle(rect);
      Rectangle save = gc.getClipping();
      gc.setClipping(rect);
      gc.drawText((myContent.notes), rect.x + 3, rect.y);
      gc.setClipping(save);

    }

  }

}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

class TownExampleContent {
  public String name;

  public Image image;

  public String country;

  public String notes;

  public TownExampleContent(String name, String country) {
    this.name = name;
    this.country = country;
    image = loadImageResource(Display.getCurrent(), "/gfx/" + name + ".gif");
    System.out.println(image);
    notes = "Double click to edit and use \n"
        + "Shift+Enter to start a new line...";
  }

  public Image loadImageResource(Display d, String name) {
    try {

      Image ret = null;
      Class clazz = this.getClass();
      InputStream is = clazz.getResourceAsStream(name);
      if (is != null) {
        ret = new Image(d, is);
        is.close();
      }
      return ret;
    } catch (Exception e1) {
      return null;
    }
  }

  /*
   * overridden from superclass
   */
  public String toString() {
    return notes;
  }

}

/**
 * @author Kosta, Friederich Kupzog
 */
class SWTX {
  public static final int EVENT_SWTX_BASE = 1000;

  public static final int EVENT_TABLE_HEADER = EVENT_SWTX_BASE + 1;

  public static final int EVENT_TABLE_HEADER_CLICK = EVENT_SWTX_BASE + 2;

  public static final int EVENT_TABLE_HEADER_RESIZE = EVENT_SWTX_BASE + 3;

  //
  public static final int ALIGN_HORIZONTAL_MASK = 0x0F;

  public static final int ALIGN_HORIZONTAL_NONE = 0x00;

  public static final int ALIGN_HORIZONTAL_LEFT = 0x01;

  public static final int ALIGN_HORIZONTAL_LEFT_LEFT = ALIGN_HORIZONTAL_LEFT;

  public static final int ALIGN_HORIZONTAL_LEFT_RIGHT = 0x02;

  public static final int ALIGN_HORIZONTAL_LEFT_CENTER = 0x03;

  public static final int ALIGN_HORIZONTAL_RIGHT = 0x04;

  public static final int ALIGN_HORIZONTAL_RIGHT_RIGHT = ALIGN_HORIZONTAL_RIGHT;

  public static final int ALIGN_HORIZONTAL_RIGHT_LEFT = 0x05;

  public static final int ALIGN_HORIZONTAL_RIGHT_CENTER = 0x06;

  public static final int ALIGN_HORIZONTAL_CENTER = 0x07;

  public static final int ALIGN_VERTICAL_MASK = 0xF0;

  public static final int ALIGN_VERTICAL_TOP = 0x10;

  public static final int ALIGN_VERTICAL_BOTTOM = 0x20;

  public static final int ALIGN_VERTICAL_CENTER = 0x30;

  //
  private static GC m_LastGCFromExtend;

  private static Map m_StringExtentCache = new HashMap();

  private static synchronized Point getCachedStringExtent(GC gc, String text) {
    if (m_LastGCFromExtend != gc) {
      m_StringExtentCache.clear();
      m_LastGCFromExtend = gc;
    }
    Point p = (Point) m_StringExtentCache.get(text);
    if (p == null) {
      if (text == null)
        return new Point(0, 0);
      p = gc.stringExtent(text);
      m_StringExtentCache.put(text, p);
    }
    return new Point(p.x, p.y);
  }

  public static int drawTextVerticalAlign(GC gc, String text, int textAlign,
      int x, int y, int w, int h) {
    if (text == null)
      text = "";
    Point textSize = getCachedStringExtent(gc, text);
    {
      boolean addPoint = false;
      while ((text.length() > 0) && (textSize.x >= w)) {
        text = text.substring(0, text.length() - 1);
        textSize = getCachedStringExtent(gc, text + "...");
        addPoint = true;
      }
      if (addPoint)
        text = text + "...";
      textSize = getCachedStringExtent(gc, text);
      if (textSize.x >= w) {
        text = "";
        textSize = getCachedStringExtent(gc, text);
      }
    }
    //
    if ((textAlign & ALIGN_VERTICAL_MASK) == ALIGN_VERTICAL_TOP) {
      gc.drawText(text, x, y);
      gc.fillRectangle(x, y + textSize.y, textSize.x, h - textSize.y);
      return textSize.x;
    }
    if ((textAlign & ALIGN_VERTICAL_MASK) == ALIGN_VERTICAL_BOTTOM) {
      gc.drawText(text, x, y + h - textSize.y);
      gc.fillRectangle(x, y, textSize.x, h - textSize.y);
      return textSize.x;
    }
    if ((textAlign & ALIGN_VERTICAL_MASK) == ALIGN_VERTICAL_CENTER) {
      int yOffset = (h - textSize.y) / 2;
      gc.drawText(text, x, y + yOffset);
      gc.fillRectangle(x, y, textSize.x, yOffset);
      gc.fillRectangle(x, y + yOffset + textSize.y, textSize.x, h
          - (yOffset + textSize.y));
      return textSize.x;
    }
    throw new SWTException(
        "H: "
            + (textAlign & ALIGN_VERTICAL_MASK));
  }

  public static void drawTransparentImage(GC gc, Image image, int x, int y) {
    if (image == null)
      return;
    Point imageSize = new Point(image.getBounds().width,
        image.getBounds().height);
    Image img = new Image(Display.getCurrent(), imageSize.x, imageSize.y);
    GC gc2 = new GC(img);
    gc2.setBackground(gc.getBackground());
    gc2.fillRectangle(0, 0, imageSize.x, imageSize.y);
    gc2.drawImage(image, 0, 0);
    gc.drawImage(img, x, y);
    gc2.dispose();
    img.dispose();
  }

  public static void drawImageVerticalAlign(GC gc, Image image,
      int imageAlign, int x, int y, int h) {
    if (image == null)
      return;
    Point imageSize = new Point(image.getBounds().width,
        image.getBounds().height);
    //
    if ((imageAlign & ALIGN_VERTICAL_MASK) == ALIGN_VERTICAL_TOP) {
      drawTransparentImage(gc, image, x, y);
      gc.fillRectangle(x, y + imageSize.y, imageSize.x, h - imageSize.y);
      return;
    }
    if ((imageAlign & ALIGN_VERTICAL_MASK) == ALIGN_VERTICAL_BOTTOM) {
      drawTransparentImage(gc, image, x, y + h - imageSize.y);
      gc.fillRectangle(x, y, imageSize.x, h - imageSize.y);
      return;
    }
    if ((imageAlign & ALIGN_VERTICAL_MASK) == ALIGN_VERTICAL_CENTER) {
      int yOffset = (h - imageSize.y) / 2;
      drawTransparentImage(gc, image, x, y + yOffset);
      gc.fillRectangle(x, y, imageSize.x, yOffset);
      gc.fillRectangle(x, y + yOffset + imageSize.y, imageSize.x, h
          - (yOffset + imageSize.y));
      return;
    }
    throw new SWTException(
        "H: "
            + (imageAlign & ALIGN_VERTICAL_MASK));
  }

  public static void drawTextImage(GC gc, String text, int textAlign,
      Image image, int imageAlign, int x, int y, int w, int h) {
    Point textSize = getCachedStringExtent(gc, text);
    Point imageSize;
    if (image != null)
      imageSize = new Point(image.getBounds().width,
          image.getBounds().height);
    else
      imageSize = new Point(0, 0);
    //
    /*
     * Rectangle oldClipping = gc.getClipping(); gc.setClipping(x, y, w, h);
     */
    try {
      if ((image == null)
          && ((textAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_CENTER)) {
        Point p = getCachedStringExtent(gc, text);
        int offset = (w - p.x) / 2;
        if (offset > 0) {
          drawTextVerticalAlign(gc, text, textAlign, x + offset, y, w
              - offset, h);
          gc.fillRectangle(x, y, offset, h);
          gc
              .fillRectangle(x + offset + p.x, y, w
                  - (offset + p.x), h);
        } else {
          p.x = drawTextVerticalAlign(gc, text, textAlign, x, y, w, h);
          // gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_YELLOW));
          gc.fillRectangle(x + p.x, y, w - (p.x), h);
          // offset = (w - p.x) / 2;
          // gc.fillRectangle(x, y, offset, h);
          // gc.fillRectangle(x + offset + p.x, y, w - (offset + p.x),
          // h);
        }
        return;
      }
      if (((text == null) || (text.length() == 0))
          && ((imageAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_CENTER)) {
        int offset = (w - imageSize.x) / 2;
        // System.out.println("w: " + w + " imageSize" + imageSize + "
        // offset: " + offset);
        drawImageVerticalAlign(gc, image, imageAlign, x + offset, y, h);
        gc.fillRectangle(x, y, offset, h);
        gc.fillRectangle(x + offset + imageSize.x, y, w
            - (offset + imageSize.x), h);
        return;
      }
      if ((textAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_LEFT) {
        if ((imageAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_NONE) {
          textSize.x = drawTextVerticalAlign(gc, text, textAlign, x,
              y, w, h);
          gc.fillRectangle(x + textSize.x, y, w - textSize.x, h);
          return;
        }
        if ((imageAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_LEFT) {
          textSize.x = drawTextVerticalAlign(gc, text, textAlign, x
              + imageSize.x, y, w - imageSize.x, h);
          drawImageVerticalAlign(gc, image, imageAlign, x, y, h);
          gc.fillRectangle(x + textSize.x + imageSize.x, y, w
              - (textSize.x + imageSize.x), h);
          return;
        }
        if ((imageAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_RIGHT) {
          textSize.x = drawTextVerticalAlign(gc, text, textAlign, x,
              y, w - imageSize.x, h);
          drawImageVerticalAlign(gc, image, imageAlign, x + w
              - imageSize.x, y, h);
          gc.fillRectangle(x + textSize.x, y, w
              - (textSize.x + imageSize.x), h);
          return;
        }
        if ((imageAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_RIGHT_LEFT) {
          textSize.x = drawTextVerticalAlign(gc, text, textAlign, x,
              y, w - imageSize.x, h);
          drawImageVerticalAlign(gc, image, imageAlign, x
              + textSize.x, y, h);
          gc.fillRectangle(x + textSize.x + imageSize.x, y, w
              - (textSize.x + imageSize.x), h);
          return;
        }
        if ((imageAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_RIGHT_CENTER) {
          textSize.x = drawTextVerticalAlign(gc, text, textAlign, x,
              y, w - imageSize.x, h);
          int xOffset = (w - textSize.x - imageSize.x) / 2;
          drawImageVerticalAlign(gc, image, imageAlign, x
              + textSize.x + xOffset, y, h);
          gc.fillRectangle(x + textSize.x, y, xOffset, h);
          gc.fillRectangle(x + textSize.x + xOffset + imageSize.x, y,
              w - (textSize.x + xOffset + imageSize.x), h);
          return;
        }
        throw new SWTException(
            "H: "
                + (imageAlign & ALIGN_HORIZONTAL_MASK));
      } // text align left
      if ((textAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_RIGHT) {
        if ((imageAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_NONE) {
          textSize.x = drawTextVerticalAlign(gc, text, textAlign, x,
              -1000, w, h);
          drawTextVerticalAlign(gc, text, textAlign, x + w
              - textSize.x, y, w, h);
          gc.fillRectangle(x, y, w - textSize.x, h);
          return;
        }
        if ((imageAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_LEFT) {
          textSize.x = drawTextVerticalAlign(gc, text, textAlign, x,
              -1000, w - imageSize.x, h);
          drawTextVerticalAlign(gc, text, textAlign, x + w
              - textSize.x, y, w - imageSize.x, h);
          drawImageVerticalAlign(gc, image, imageAlign, x, y, h);
          gc.fillRectangle(x + imageSize.x, y, w
              - (textSize.x + imageSize.x), h);
          return;
        }
        if ((imageAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_LEFT_RIGHT) {
          textSize.x = drawTextVerticalAlign(gc, text, textAlign, x,
              -1000, w - imageSize.x, h);
          drawTextVerticalAlign(gc, text, textAlign, x + w
              - textSize.x, y, w - imageSize.x, h);
          drawImageVerticalAlign(gc, image, imageAlign, x + w
              - (textSize.x + imageSize.x), y, h);
          gc.fillRectangle(x, y, w - (textSize.x + imageSize.x), h);
          return;
        }
        if ((imageAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_LEFT_CENTER) {
          textSize.x = drawTextVerticalAlign(gc, text, textAlign, x,
              -1000, w - imageSize.x, h);
          drawTextVerticalAlign(gc, text, textAlign, x + w
              - textSize.x, y, w - imageSize.x, h);
          int xOffset = (w - textSize.x - imageSize.x) / 2;
          drawImageVerticalAlign(gc, image, imageAlign, x + xOffset,
              y, h);
          gc.fillRectangle(x, y, xOffset, h);
          gc.fillRectangle(x + xOffset + imageSize.x, y, w
              - (xOffset + imageSize.x + textSize.x), h);
          return;
        }
        if ((imageAlign & ALIGN_HORIZONTAL_MASK) == ALIGN_HORIZONTAL_RIGHT) {
          textSize.x = drawTextVerticalAlign(gc, text, textAlign, x,
              -1000, w - imageSize.x, h);
          drawTextVerticalAlign(gc, text, textAlign, x + w
              - (textSize.x + imageSize.x), y, w - imageSize.x, h);
          drawImageVerticalAlign(gc, image, imageAlign, x + w
              - imageSize.x, y, h);
          gc.fillRectangle(x, y, w - (textSize.x + imageSize.x), h);
          return;
        }
        throw new SWTException(
            "H: "
                + (imageAlign & ALIGN_HORIZONTAL_MASK));
      } // text align right
      throw new SWTException(
          "H: "
              + (textAlign & ALIGN_HORIZONTAL_MASK));
    } // trye
    finally {
      // gc.setClipping(oldClipping);
    }
  }

  public static void drawTextImage(GC gc, String text, int textAlign,
      Image image, int imageAlign, Rectangle r) {
    drawTextImage(gc, text, textAlign, image, imageAlign, r.x, r.y,
        r.width, r.height);
  }

  public static void drawButtonUp(GC gc, String text, int textAlign,
      Image image, int imageAlign, int x, int y, int w, int h,
      Color face, Color shadowHigh, Color shadowNormal, Color shadowDark,
      int leftMargin, int topMargin) {
    Color prevForeground = gc.getForeground();
    Color prevBackground = gc.getBackground();
    try {
      gc.setBackground(face);
      gc.setForeground(shadowHigh);
      gc.drawLine(x, y, x, y + h - 1);
      gc.drawLine(x, y, x + w - 2, y);
      gc.setForeground(shadowDark);
      gc.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
      gc.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
      gc.setForeground(shadowNormal);
      gc.drawLine(x + w - 2, y + 1, x + w - 2, y + h - 2);
      gc.drawLine(x + 1, y + h - 2, x + w - 2, y + h - 2);
      //
      gc.fillRectangle(x + 1, y + 1, leftMargin, h - 3);
      gc.fillRectangle(x + 1, y + 1, w - 3, topMargin);
      gc.setForeground(prevForeground);
      drawTextImage(gc, text, textAlign, image, imageAlign, x + 1
          + leftMargin, y + 1 + topMargin, w - 3 - leftMargin, h - 3
          - topMargin);
    } finally {
      gc.setForeground(prevForeground);
      gc.setBackground(prevBackground);
    }
  }

  public static void drawButtonUp(GC gc, String text, int textAlign,
      Image image, int imageAlign, int x, int y, int w, int h, Color face) {
    Display display = Display.getCurrent();
    drawButtonUp(gc, text, textAlign, image, imageAlign, x, y, w, h, face,
        display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW),
        display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW), display
            .getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW), 2, 2);
  }

  public static void drawButtonUp(GC gc, String text, int textAlign,
      Image image, int imageAlign, Rectangle r, int leftMargin,
      int topMargin) {
    Display display = Display.getCurrent();
    drawButtonUp(gc, text, textAlign, image, imageAlign, r.x, r.y, r.width,
        r.height, display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND),
        display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW),
        display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW), display
            .getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW),
        leftMargin, topMargin);
  }

  public static void drawButtonUp(GC gc, String text, int textAlign,
      Image image, int imageAlign, int x, int y, int w, int h) {
    Display display = Display.getCurrent();
    drawButtonUp(gc, text, textAlign, image, imageAlign, x, y, w, h,
        display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND), display
            .getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW),
        display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW), display
            .getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW), 2, 2);
  }

  public static void drawButtonUp(GC gc, String text, int textAlign,
      Image image, int imageAlign, Rectangle r) {
    Display display = Display.getCurrent();
    drawButtonUp(gc, text, textAlign, image, imageAlign, r.x, r.y, r.width,
        r.height);
  }

  public static void drawButtonDown(GC gc, String text, int textAlign,
      Image image, int imageAlign, int x, int y, int w, int h,
      Color face, Color shadowNormal, int leftMargin, int topMargin) {
    Color prevForeground = gc.getForeground();
    Color prevBackground = gc.getBackground();
    try {
      gc.setBackground(face);
      gc.setForeground(shadowNormal);
      gc.drawRectangle(x, y, w - 1, h - 1);
      gc.fillRectangle(x + 1, y + 1, 1 + leftMargin, h - 2);
      gc.fillRectangle(x + 1, y + 1, w - 2, topMargin + 1);
      gc.setForeground(prevForeground);
      drawTextImage(gc, text, textAlign, image, imageAlign, x + 2
          + leftMargin, y + 2 + topMargin, w - 3 - leftMargin, h - 3
          - topMargin);
    } finally {
      gc.setForeground(prevForeground);
      gc.setBackground(prevBackground);
    }
  }

  public static void drawButtonDown(GC gc, String text, int textAlign,
      Image image, int imageAlign, int x, int y, int w, int h) {
    Display display = Display.getCurrent();
    drawButtonDown(gc, text, textAlign, image, imageAlign, x, y, w, h,
        display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND), display
            .getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW), 2, 2);
  }

  public static void drawButtonDown(GC gc, String text, int textAlign,
      Image image, int imageAlign, Rectangle r) {
    drawButtonDown(gc, text, textAlign, image, imageAlign, r.x, r.y,
        r.width, r.height);
  }

  public static void drawButtonDown(GC gc, String text, int textAlign,
      Image image, int imageAlign, int x, int y, int w, int h, Color face) {
    Display display = Display.getCurrent();
    drawButtonDown(gc, text, textAlign, image, imageAlign, x, y, w, h,
        face, display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW),
        2, 2);
  }

  public static void drawButtonDeepDown(GC gc, String text, int textAlign,
      Image image, int imageAlign, int x, int y, int w, int h) {
    Display display = Display.getCurrent();
    gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
    gc.drawLine(x, y, x + w - 2, y);
    gc.drawLine(x, y, x, y + h - 2);
    gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
    gc.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
    gc.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
    gc.setForeground(display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
    gc.drawLine(x + 1, y + h - 2, x + w - 2, y + h - 2);
    gc.drawLine(x + w - 2, y + h - 2, x + w - 2, y + 1);
    //
    gc.setForeground(display.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND));
    gc.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
    gc.fillRectangle(x + 2, y + 2, w - 4, 1);
    gc.fillRectangle(x + 1, y + 2, 2, h - 4);
    //
    gc.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
    drawTextImage(gc, text, textAlign, image, imageAlign, x + 2 + 1,
        y + 2 + 1, w - 4, h - 3 - 1);
  }

  public static void drawButtonDeepDown(GC gc, String text, int textAlign,
      Image image, int imageAlign, Rectangle r) {
    drawButtonDeepDown(gc, text, textAlign, image, imageAlign, r.x, r.y,
        r.width, r.height);
  }

  public static void drawFlatButtonUp(GC gc, String text, int textAlign,
      Image image, int imageAlign, int x, int y, int w, int h,
      Color face, Color shadowLight, Color shadowNormal, int leftMargin,
      int topMargin) {
    Color prevForeground = gc.getForeground();
    Color prevBackground = gc.getBackground();
    try {
      gc.setForeground(shadowLight);
      gc.drawLine(x, y, x + w - 1, y);
      gc.drawLine(x, y, x, y + h);
      gc.setForeground(shadowNormal);
      gc.drawLine(x + w, y, x + w, y + h);
      gc.drawLine(x + 1, y + h, x + w, y + h);
      //
      gc.setBackground(face);
      gc.fillRectangle(x + 1, y + 1, leftMargin, h - 1);
      gc.fillRectangle(x + 1, y + 1, w - 1, topMargin);
      //
      gc.setBackground(face);
      gc.setForeground(prevForeground);
      drawTextImage(gc, text, textAlign, image, imageAlign, x + 1
          + leftMargin, y + 1 + topMargin, w - 1 - leftMargin, h - 1
          - topMargin);
    } finally {
      gc.setForeground(prevForeground);
      gc.setBackground(prevBackground);
    }
  }

  public static void drawShadowImage(GC gc, Image image, int x, int y,
      int alpha) {
    Display display = Display.getCurrent();
    Point imageSize = new Point(image.getBounds().width,
        image.getBounds().height);
    //
    ImageData imgData = new ImageData(imageSize.x, imageSize.y, 24,
        new PaletteData(255, 255, 255));
    imgData.alpha = alpha;
    Image img = new Image(display, imgData);
    GC imgGC = new GC(img);
    imgGC.drawImage(image, 0, 0);
    gc.drawImage(img, x, y);
    imgGC.dispose();
    img.dispose();
  }
}

           
       








Related examples in the same category

1.How to order 1000 elements in a swt column table with O(n log(n)) complexity! using Comparator and Array.sort() implemented in a TableColumn Listener FactoryHow to order 1000 elements in a swt column table with O(n log(n)) complexity! using Comparator and Array.sort() implemented in a TableColumn Listener Factory
2.Print KTable (SWT Table)Example Print KTable (SWT Table)Example
3.SWT Table Editor
4.Simple File Browser in SWT TableSimple File Browser in SWT Table
5.Bug Tracker JFaceBug Tracker JFace
6.Bug TrackerBug Tracker
7.File Browser DemoFile Browser Demo
8.TableEditor exampleTableEditor example
9.File Browser SampleFile Browser Sample
10.File Browser JFace
11.Bug ReportBug Report
12.Displays ASCII CodesDisplays ASCII Codes
13.Demonstrates the SWT.VIRTUAL styleDemonstrates the SWT.VIRTUAL style
14.Displays a tableDisplays a table
15.A table of baseball players and allows sortingA table of baseball players and allows sorting
16.Demonstrates TableCursorDemonstrates TableCursor
17.Demonstrates TableTreeDemonstrates TableTree
18.Demonstrates TableEditorDemonstrates TableEditor
19.Shows the extensions on the system and their associated programsShows the extensions on the system and their associated programs
20.Table Example 3Table Example 3
21.Table Example 2Table Example 2
22.Table ExampleTable Example
23.Demonstrates TableViewersDemonstrates TableViewers
24.Demonstrates CheckboxTableViewerDemonstrates CheckboxTableViewer
25.Demonstrates CellEditorsDemonstrates CellEditors
26.SWT Table Simple DemoSWT Table Simple Demo
27.Create fake tooltips for items in a SWT tableCreate fake tooltips for items in a SWT table
28.Place a progress bar in a SWT tablePlace a progress bar in a SWT table
29.edit a cell in a SWT table (in place, fancy)edit a cell in a SWT table (in place, fancy)
30.edit the text of a SWT table item (in place)edit the text of a SWT table item (in place)
31.navigate a SWT table cells with arrow keysnavigate a SWT table cells with arrow keys
32.Update SWT table item textUpdate SWT table item text
33.Sort a SWT table by columnSort a SWT table by column
34.Select an index (select and scroll) in a SWT tableSelect an index (select and scroll) in a SWT table
35.Scroll a SWT table (set the top index)Scroll a SWT table (set the top index)
36.Resize columns as SWT table resizesResize columns as SWT table resizes
37.Remove selected items in a SWT tableRemove selected items in a SWT table
38.Print selected items in a SWT tablePrint selected items in a SWT table
39.Place arbitrary controls in a SWT tablePlace arbitrary controls in a SWT table
40.Reorder columns and reorder columns programmaticallyReorder columns and reorder columns programmatically
41.Insert a SWT table column (at an index)Insert a SWT table column (at an index)
42.Insert a SWT table item (at an index)Insert a SWT table item (at an index)
43.Find a SWT table cell from mouse down (works for any table style)Find a SWT table cell from mouse down (works for any table style)
44.Find a table cell from mouse down (SWT.FULL_SELECTION)Find a table cell from mouse down (SWT.FULL_SELECTION)
45.Detect a selection or check event in a table (SWT.CHECK)Detect a selection or check event in a table (SWT.CHECK)
46.Create a SWT table with 1,000,000 itemsCreate a SWT table with 1,000,000 items
47.Create a SWT table (columns, headers, lines)Create a SWT table (columns, headers, lines)
48.Create a SWT table (no columns, no headers)Create a SWT table (no columns, no headers)
49.Color cells and rows in SWT tableColor cells and rows in SWT table
50.Create a virtual SWT table and add 1000 entries to it every 500 msCreate a virtual SWT table and add 1000 entries to it every 500 ms
51.Dropped data type depends on target item in tableDropped data type depends on target item in table
52.Create a table (lazy)Create a table (lazy)