Java/SWT JFace Eclipse/Table

Материал из Java эксперт
Версия от 18:01, 31 мая 2010; (обсуждение)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Содержание

A table of baseball players and allows sorting

//Send questions, comments, bug reports, etc. to the authors:
//Rob Warner (rwarner@interspatial.ru)
//Robert Harris (rbrt_harris@yahoo.ru)
import java.util.*;
import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.*;
/**
 * This program displays a table of baseball players and allows sorting by first
 * name, last name, or lifetime batting average.
 */
public class PlayerTable {
  private PlayerComparator comparator;
  // Must fully-qualify List to avoid ambiguity with
  // org.eclipse.swt.widgets.List
  private java.util.List players;
  /**
   * Constructs a PlayerTable
   */
  public PlayerTable() {
    // Create the comparator used for sorting
    comparator = new PlayerComparator();
    comparator.setColumn(PlayerComparator.FIRST_NAME);
    comparator.setDirection(PlayerComparator.ASCENDING);
    // Create the players
    players = new ArrayList();
    players.add(new Player("Gil", "Hodges", 0.273f));
    players.add(new Player("Jim", "Gilliam", 0.265f));
    players.add(new Player("Jackie", "Robinson", 0.311f));
    players.add(new Player("Pee Wee", "Reese", 0.269f));
    players.add(new Player("Roy", "Campanella", 0.276f));
    players.add(new Player("Carl", "Furillo", 0.299f));
    players.add(new Player("Sandy", "Amoros", 0.255f));
    players.add(new Player("Duke", "Snider", 0.295f));
  }
  /**
   * Runs the application
   */
  public void run() {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setText("Player Table");
    createContents(shell);
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
    display.dispose();
  }
  /**
   * Create the contents of the main window
   * 
   * @param composite the parent composite
   */
  private void createContents(Composite composite) {
    composite.setLayout(new FillLayout());
    // Create the table
    final Table table = new Table(composite, SWT.NONE);
    table.setHeaderVisible(true);
    table.setLinesVisible(true);
    // Create each of the columns, adding an event
    // listener that will set the appropriate fields
    // into the comparator and then call the fillTable
    // helper method
    TableColumn[] columns = new TableColumn[3];
    columns[0] = new TableColumn(table, SWT.NONE);
    columns[0].setText("First Name");
    columns[0].addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        comparator.setColumn(PlayerComparator.FIRST_NAME);
        comparator.reverseDirection();
        fillTable(table);
      }
    });
    columns[1] = new TableColumn(table, SWT.NONE);
    columns[1].setText("Last Name");
    columns[1].addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        comparator.setColumn(PlayerComparator.LAST_NAME);
        comparator.reverseDirection();
        fillTable(table);
      }
    });
    columns[2] = new TableColumn(table, SWT.RIGHT);
    columns[2].setText("Batting Average");
    columns[2].addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        comparator.setColumn(PlayerComparator.BATTING_AVERAGE);
        comparator.reverseDirection();
        fillTable(table);
      }
    });
    // Do the initial fill of the table
    fillTable(table);
    // Pack each column so inital display is good
    for (int i = 0, n = columns.length; i < n; i++) {
      columns[i].pack();
    }
  }
  private void fillTable(Table table) {
    // Turn off drawing to avoid flicker
    table.setRedraw(false);
    // We remove all the table entries, sort our
    // rows, then add the entries
    table.removeAll();
    Collections.sort(players, comparator);
    for (Iterator itr = players.iterator(); itr.hasNext();) {
      Player player = (Player) itr.next();
      TableItem item = new TableItem(table, SWT.NONE);
      int c = 0;
      item.setText(c++, player.getFirstName());
      item.setText(c++, player.getLastName());
      item.setText(c++, String.valueOf(player.getBattingAverage()));
    }
    // Turn drawing back on
    table.setRedraw(true);
  }
  /**
   * The application"s entry point
   * 
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    new PlayerTable().run();
  }
}
//Send questions, comments, bug reports, etc. to the authors:
//Rob Warner (rwarner@interspatial.ru)
//Robert Harris (rbrt_harris@yahoo.ru)
/**
 * This class represents a player.
 */
 class Player {
  private String firstName;
  private String lastName;
  private float battingAverage;
  /**
   * Constructs a Player
   * 
   * @param firstName the first name
   * @param lastName the last name
   * @param battingAverage the batting average
   */
  public Player(String firstName, String lastName, float battingAverage) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.battingAverage = battingAverage;
  }
  /**
   * Gets the batting average
   * 
   * @return float
   */
  public float getBattingAverage() {
    return battingAverage;
  }
  /**
   * Gets the first name
   * 
   * @return String
   */
  public String getFirstName() {
    return firstName;
  }
  /**
   * Gets the last name
   * 
   * @return String
   */
  public String getLastName() {
    return lastName;
  }
}
//Send questions, comments, bug reports, etc. to the authors:
//Rob Warner (rwarner@interspatial.ru)
//Robert Harris (rbrt_harris@yahoo.ru)

/**
 * This class does the comparisons for sorting Player objects.
 */
class PlayerComparator implements Comparator {
  /** Constant for First Name column */
  public static final int FIRST_NAME = 0;
  /** Constant for Last Name column */
  public static final int LAST_NAME = 1;
  /** Constant for Batting Average column */
  public static final int BATTING_AVERAGE = 2;
  /** Constant for ascending */
  public static final int ASCENDING = 0;
  /** Constant for descending */
  public static final int DESCENDING = 1;
  private int column;
  private int direction;
  /**
   * Compares two Player objects
   * 
   * @param obj1 the first Player
   * @param obj2 the second Player
   * @return int
   * @see java.util.ruparator#compare(java.lang.Object, java.lang.Object)
   */
  public int compare(Object obj1, Object obj2) {
    int rc = 0;
    Player p1 = (Player) obj1;
    Player p2 = (Player) obj2;
    // Determine which field to sort on, then sort
    // on that field
    switch (column) {
    case FIRST_NAME:
      rc = p1.getFirstName().rupareTo(p2.getFirstName());
      break;
    case LAST_NAME:
      rc = p1.getLastName().rupareTo(p2.getLastName());
      break;
    case BATTING_AVERAGE:
      rc = (p1.getBattingAverage() < p2.getBattingAverage()) ? -1 : 1;
      break;
    }
    // Check the direction for sort and flip the sign
    // if appropriate
    if (direction == DESCENDING) {
      rc = -rc;
    }
    return rc;
  }
  /**
   * Sets the column for sorting
   * 
   * @param column the column
   */
  public void setColumn(int column) {
    this.column = column;
  }
  /**
   * Sets the direction for sorting
   * 
   * @param direction the direction
   */
  public void setDirection(int direction) {
    this.direction = direction;
  }
  /**
   * Reverses the direction
   */
  public void reverseDirection() {
    direction = 1 - direction;
  }
}





Bug Report

/******************************************************************************
 * All Right Reserved. 
 * Copyright (c) 1998, 2004 Jackwind Li Guojie
 * 
 * Created on 2004-4-11 0:10:48 by JACK
 * $Id$
 * 
 *****************************************************************************/
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.rubo;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class BugReport {
  Display display = new Display();
  Shell shell = new Shell(display);
  public BugReport() {
    shell.setLayout(new GridLayout(1, true));
    shell.setImage(new Image(display, "jexp.gif"));
    shell.setText("Bug report page");
    
    Group groupBug = new Group(shell, SWT.NULL);
    groupBug.setText("Bug details");
    groupBug.setLayout(new GridLayout(2, false));
    groupBug.setLayoutData(new GridData(GridData.FILL_BOTH));
    
    new Label(groupBug, SWT.NULL).setText("Priority");
    Combo combo = new Combo(groupBug, SWT.BORDER);
    combo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    
    new Label(groupBug, SWT.NULL).setText("Details");
    Text text = new Text(groupBug, SWT.BORDER | SWT.MULTI);
    text.setLayoutData(new GridData(GridData.FILL_BOTH));
    
    Group groupProxy = new Group(shell, SWT.NULL);
    groupProxy.setText("Connection setting");
    groupProxy.setLayout(new GridLayout(2, false));
    groupProxy.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    
    new Label(groupProxy, SWT.NULL).setText("Proxy host");
    Text textHost = new Text(groupProxy, SWT.SINGLE | SWT.BORDER);
    textHost.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    new Label(groupProxy, SWT.NULL).setText("Proxy port");
    Text textPort = new Text(groupProxy, SWT.SINGLE | SWT.BORDER);
    textPort.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    
    Button button = new Button(shell, SWT.PUSH);
    button.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
    //button.setAlignment(SWT.CENTER);
    button.setText("Submit bug report");
    shell.pack();
    shell.open();
    //textUser.forceFocus();
    // Set up the event loop.
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        // If no more entries in event queue
        display.sleep();
      }
    }
    display.dispose();
  }
  private void init() {
  }
  public static void main(String[] args) {
    new BugReport();
  }
}





Bug Tracker

/*******************************************************************************
 * All Right Reserved. Copyright (c) 1998, 2004 Jackwind Li Guojie
 * 
 * Created on Mar 3, 2004 7:53:44 PM by JACK $Id$
 *  
 ******************************************************************************/
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.ruparator;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
public class BugTracker {
  Display display = new Display();
  Shell shell = new Shell(display);
  Table table;
  Image bugIcon = new Image(shell.getDisplay(), "jexp.gif");
  public BugTracker() {
    GridLayout gridLayout = new GridLayout();
    shell.setLayout(gridLayout);
    shell.setText("Bug Tracking System");
    // Action.
    Action actionAddNew = new Action("New bug") {
      public void run() {
          // Append.
  TableItem item = new TableItem(table, SWT.NULL);
        item.setImage(bugIcon);
        table.select(table.getItemCount() - 1);
      }
    };
    Action actionDelete = new Action("Delete selected") {
      public void run() {
        int index = table.getSelectionIndex();
        if (index < 0) {
          System.out.println("Please select an item first. ");
          return;
        }
        MessageBox messageBox = new MessageBox(shell, SWT.YES | SWT.NO);
        messageBox.setText("Confirmation");
        messageBox.setMessage(
          "Are you sure to remove the bug with id #"
            + table.getItem(index).getText(0));
        if (messageBox.open() == SWT.YES) {
          table.remove(index);
        }
      }
    };
    Action actionSave = new Action("Save") {
      public void run() {
        saveBugs();
      }
    };
    ToolBar toolBar = new ToolBar(shell, SWT.RIGHT | SWT.FLAT);
    ToolBarManager manager = new ToolBarManager(toolBar);
    manager.add(actionAddNew);
    manager.add(actionDelete);
    manager.add(new Separator());
    manager.add(actionSave);
    manager.update(true);
    table = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
    table.setLayoutData(new GridData(GridData.FILL_BOTH));
    table.setLinesVisible(true);
    table.setHeaderVisible(true);
    TableColumn tcID = new TableColumn(table, SWT.LEFT);
    tcID.setText("ID");
    TableColumn tcSummary = new TableColumn(table, SWT.NULL);
    tcSummary.setText("Summary");
    TableColumn tcAssignedTo = new TableColumn(table, SWT.NULL);
    tcAssignedTo.setText("Assigned to");
    TableColumn tcSolved = new TableColumn(table, SWT.NULL);
    tcSolved.setText("Solved");
    tcID.setWidth(60);
    tcSummary.setWidth(200);
    tcAssignedTo.setWidth(80);
    tcSolved.setWidth(50);
    table.pack();
    // Table editor.
    final TableEditor editor = new TableEditor(table);
    table.addListener(SWT.MouseDown, new Listener() {
      public void handleEvent(Event event) {
        // Locate the cell position.
        Point point = new Point(event.x, event.y);
        final TableItem item = table.getItem(point);
        if (item == null)
          return;
        int column = -1;
        for (int i = 0; i < table.getColumnCount(); i++) {
          Rectangle rect = item.getBounds(i);
          if (rect.contains(point))
            column = i;
        }
        if (column != 3)
          return;
        // Cell position located, now open the table editor.
        final Button button = new Button(table, SWT.CHECK);
        button.setSelection(
          item.getText(column).equalsIgnoreCase("YES"));
        editor.horizontalAlignment = SWT.LEFT;
        editor.grabHorizontal = true;
        editor.setEditor(button, item, column);
        final int selectedColumn = column;
        Listener buttonListener = new Listener() {
          public void handleEvent(final Event e) {
            switch (e.type) {
              case SWT.FocusOut :
                item.setText(
                  selectedColumn,
                  button.getSelection() ? "YES" : "NO");
                button.dispose();
                break;
              case SWT.Traverse :
                switch (e.detail) {
                  case SWT.TRAVERSE_RETURN :
                    item.setText(
                      selectedColumn,
                      button.getSelection()
                        ? "YES"
                        : "NO");
                    //FALL THROUGH
                  case SWT.TRAVERSE_ESCAPE :
                    button.dispose();
                    e.doit = false;
                }
                break;
            }
          }
        };
        button.addListener(SWT.FocusOut, buttonListener);
        button.addListener(SWT.Traverse, buttonListener);
        button.setFocus();
      }
    });
    table.addListener(SWT.MouseDown, new Listener() {
      public void handleEvent(Event event) {
        // Locate the cell position.
        Point point = new Point(event.x, event.y);
        final TableItem item = table.getItem(point);
        if (item == null)
          return;
        int column = -1;
        for (int i = 0; i < table.getColumnCount(); i++) {
          Rectangle rect = item.getBounds(i);
          if (rect.contains(point))
            column = i;
        }
        if (column < 0 || column >= 3)
          return;
        // Cell position located, now open the table editor.
        final Text text = new Text(table, SWT.NONE);
        text.setText(item.getText(column));
        editor.horizontalAlignment = SWT.LEFT;
        editor.grabHorizontal = true;
        editor.setEditor(text, item, column);
        final int selectedColumn = column;
        Listener textListener = new Listener() {
          public void handleEvent(final Event e) {
            switch (e.type) {
              case SWT.FocusOut :
                item.setText(selectedColumn, text.getText());
                text.dispose();
                break;
              case SWT.Traverse :
                switch (e.detail) {
                  case SWT.TRAVERSE_RETURN :
                    item.setText(
                      selectedColumn,
                      text.getText());
                    //FALL THROUGH
                  case SWT.TRAVERSE_ESCAPE :
                    text.dispose();
                    e.doit = false;
                }
                break;
            }
          }
        };
        text.addListener(SWT.FocusOut, textListener);
        text.addListener(SWT.Traverse, textListener);
        text.setFocus();
      }
    });
    loadBugs();
    table.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        System.out.println("Selected: " + table.getSelection()[0]);
      }
    });
    
    Listener sortListener = new Listener() {
      public void handleEvent(Event event) {
        if(! (event.widget instanceof TableColumn))
          return;
        TableColumn tc = (TableColumn)event.widget;
        sortTable(table, table.indexOf(tc));
        System.out.println("The table is sorted by column #" + table.indexOf(tc));
      }
    };
    
    for(int i=0; i<table.getColumnCount(); i++)
      ((TableColumn)table.getColumn(i)).addListener(SWT.Selection, sortListener);
    shell.pack();
    shell.open();
    //textUser.forceFocus();
    // Set up the event loop.
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        // If no more entries in event queue
        display.sleep();
      }
    }
    display.dispose();
  }
  
  /**
   * Sorts the given table by the specified column.
   * @param columnIndex
   */
  public static void sortTable(Table table, int columnIndex) {
    if(table == null || table.getColumnCount() <= 1)
      return;
    if(columnIndex < 0 || columnIndex >= table.getColumnCount())
      throw new IllegalArgumentException("The specified column does not exist. ");
    
    final int colIndex = columnIndex;
    Comparator comparator = new Comparator() {
      public int compare(Object o1, Object o2) {
        return ((TableItem)o1).getText(colIndex).rupareTo(((TableItem)o2).getText(colIndex));
      }
      public boolean equals(Object obj) {
        return false;
      }
    };
    
    TableItem[] tableItems = table.getItems();
    Arrays.sort(tableItems, comparator);
    
    for(int i=0; i<tableItems.length; i++) {
      TableItem item = new TableItem(table, SWT.NULL);
      for(int j=0; j<table.getColumnCount(); j++) {
        item.setText(j, tableItems[i].getText(j));
        item.setImage(j, tableItems[i].getImage(j));
      }
      tableItems[i].dispose();
    }
  }
  private void saveBugs() {
    // Save bugs to a file.
    DataOutputStream out = null;
    try {
      File file = new File("bugs.dat");
      out = new DataOutputStream(new FileOutputStream(file));
      for (int i = 0; i < table.getItemCount(); i++) {
        TableItem item = table.getItem(i);
        out.writeUTF(item.getText(0));
        out.writeUTF(item.getText(1));
        out.writeUTF(item.getText(2));
        out.writeBoolean(item.getText(3).equalsIgnoreCase("YES"));
      }
    } catch (IOException ioe) {
      // Ignore.
    } finally {
      try {
        if (out != null)
          out.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  private void loadBugs() {
    // Load bugs from a file.
    DataInputStream in = null;
    try {
      File file = new File("bugs.dat");
      if (!file.exists())
        return;
      in = new DataInputStream(new FileInputStream(file));
      while (true) {
        String id = in.readUTF();
        String summary = in.readUTF();
        String assignedTo = in.readUTF();
        boolean solved = in.readBoolean();
        TableItem item = new TableItem(table, SWT.NULL);
        item.setImage(bugIcon);
        item.setText(
          new String[] {
            id,
            summary,
            assignedTo,
            solved ? "Yes" : "No" });
      }
    } catch (IOException ioe) {
      // Ignore.
    } finally {
      try {
        if (in != null)
          in.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  public static void main(String[] args) {
    new BugTracker();
  }
}





Bug Tracker JFace

/*******************************************************************************
 * All Right Reserved. Copyright (c) 1998, 2004 Jackwind Li Guojie
 * 
 * Created on Mar 5, 2004 7:38:59 PM by JACK $Id$
 *  
 ******************************************************************************/

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Vector;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxCellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.ToolBar;
public class BugTrackerJFace {
  
  /**
   * Represents a bug report. 
   *
   */
  public static class Bug {
    // For the sake of simplicity, all variables are public.
    public String id;
    public String summary;
    public String assignedTo;
    public boolean isSolved;
    
    public Bug(String id, String summary, String assignedTo, boolean isSolved) {
      this.id = id;
      this.summary = summary;
      this.assignedTo = assignedTo;
      this.isSolved = isSolved;
    }
    public static Vector loadBugs(File file) {
      Vector v = new Vector();
      // Load bugs from a file.
      DataInputStream in = null;
      try {
        if (!file.exists())
          return v;
        in = new DataInputStream(new FileInputStream(file));
        while (true) {
          String id = in.readUTF();
          String summary = in.readUTF();
          String assignedTo = in.readUTF();
          boolean solved = in.readBoolean();
          v.add(new Bug(id, summary, assignedTo, solved));
        }
        
      } catch (IOException ioe) {
        // Ignore.
      } finally {
        try {
          if (in != null)
            in.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      
      return v;
    }
  }
  
  Display display = new Display();
  Shell shell = new Shell(display);
  
  Table table;
  TableViewer tableViewer;
  
  Vector bugs;
  
  Image bugIcon = new Image(shell.getDisplay(), "jexp.gif");
  
  String[] colNames = new String[]{"ID", "Summary", "Assigned to", "Solved"};
  // Sorter. 
  class BugSorter extends ViewerSorter {
    private String property;
    private int propertyIndex;
    
    public BugSorter(String sortByProperty) {
      for(int i=0; i<colNames.length; i++) {
        if(colNames[i].equals(sortByProperty)) {
          this.property = sortByProperty;
          this.propertyIndex = i;
          return;
        }
      }
      
      throw new IllegalArgumentException("Unrecognized property: " + sortByProperty);
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.ViewerSorter#compare(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
     */
    public int compare(Viewer viewer, Object e1, Object e2) {
      Bug bug1 = (Bug)e1;
      Bug bug2 = (Bug)e2;
      
      switch(propertyIndex) {
        case 0:
          return bug1.id.rupareTo(bug2.id);
        case 1:
          return bug1.summary.rupareTo(bug2.summary);
        case 2:
          return bug1.assignedTo.rupareTo(bug2.assignedTo);
        case 3:
          if(bug1.isSolved == bug2.isSolved)
            return 0;
          
          if(bug1.isSolved)
            return 1;
          else
            return -1;
        default:
          return 0;
      }
      
    }
  }  
  
  
  public BugTrackerJFace() {
    // Action.
    Action actionAddNew = new Action("New bug") {
      public void run() {
          // Append.
        Bug bug = new Bug("", "", "", false);
        bugs.add(bug);
        tableViewer.refresh(false);
      }
    };
    Action actionDelete = new Action("Delete selected") {
      public void run() {
        IStructuredSelection selection = (IStructuredSelection)tableViewer.getSelection();
        Bug bug = (Bug)selection.getFirstElement();
        if (bug == null) {
          System.out.println("Please select an item first. ");
          return;
        }
        MessageBox messageBox = new MessageBox(shell, SWT.YES | SWT.NO);
        messageBox.setText("Confirmation");
        messageBox.setMessage(
          "Are you sure to remove the bug with id #"
            + bug.id);
        if (messageBox.open() == SWT.YES) {
          bugs.remove(bug);
          tableViewer.refresh(false);
        }
      }
    };
    Action actionSave = new Action("Save") {
      public void run() {
        saveBugs(bugs);
      }
    };
    
    final ViewerFilter filter = new ViewerFilter() {
      public boolean select(
        Viewer viewer,
        Object parentElement,
        Object element) {
        if(! ((Bug)element).isSolved)
          return true;
        return false;
      }
    };
    
    Action actionShowUnsolvedOnly = new Action("Show unsolved only") {
      public void run() {
        if(! isChecked())
          tableViewer.removeFilter(filter);
        else
          tableViewer.addFilter(filter);
      }
    };
    actionShowUnsolvedOnly.setChecked(false);
    ToolBar toolBar = new ToolBar(shell, SWT.RIGHT | SWT.FLAT);
    ToolBarManager manager = new ToolBarManager(toolBar);
    manager.add(actionAddNew);
    manager.add(actionDelete);
    manager.add(new Separator());
    manager.add(actionSave);
    manager.add(new Separator());
    manager.add(actionShowUnsolvedOnly);
    
    manager.update(true);
    
    
    shell.setLayout(new GridLayout());
    
    table = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
    TableColumn tcID = new TableColumn(table, SWT.LEFT);
    tcID.setText(colNames[0]);
    TableColumn tcSummary = new TableColumn(table, SWT.NULL);
    tcSummary.setText(colNames[1]);
    TableColumn tcAssignedTo = new TableColumn(table, SWT.NULL);
    tcAssignedTo.setText(colNames[2]);
    TableColumn tcSolved = new TableColumn(table, SWT.NULL);
    tcSolved.setText(colNames[3]);
    tcID.setWidth(60);
    tcSummary.setWidth(200);
    tcAssignedTo.setWidth(80);
    tcSolved.setWidth(50);
    
    
    tableViewer = new TableViewer(table);
    
    tableViewer.getTable().setLinesVisible(true);
    tableViewer.getTable().setHeaderVisible(true);
    tableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));
    
    // Sets the content provider. 
    tableViewer.setContentProvider(new IStructuredContentProvider() {
      public Object[] getElements(Object inputElement) {
        Vector v = (Vector)inputElement;
        return v.toArray();
      }
      public void dispose() {
        System.out.println("Disposing ...");
      }
      public void inputChanged(
        Viewer viewer,
        Object oldInput,
        Object newInput) {
          System.out.println("Input changed: old=" + 
            oldInput + ", new=" + newInput);
      }
    });
    
    // Sets the label provider. 
    tableViewer.setLabelProvider(new ITableLabelProvider() {
      public Image getColumnImage(Object element, int columnIndex) {
        if(columnIndex == 0)
          return bugIcon;
        return null;
      }
      public String getColumnText(Object element, int columnIndex) {
        Bug bug = (Bug)element;
        switch(columnIndex) {
          case 0:
            return bug.id;
          case 1:
            return bug.summary;
          case 2:
            return bug.assignedTo;
          case 3:
            return bug.isSolved ? "YES" : "NO";
        }
        return null;
      }
      public void addListener(ILabelProviderListener listener) {
      }
      public void dispose() {
      }
      public boolean isLabelProperty(Object element, String property) {
        return false;
      }
      public void removeListener(ILabelProviderListener listener) {
      }
    });
    
    
    // Sets cell editors. 
    tableViewer.setColumnProperties(colNames);
    
    CellEditor[] cellEditors = new CellEditor[4];
    
    cellEditors[0] = new TextCellEditor(table);
    cellEditors[1] = cellEditors[0];
    cellEditors[2] = cellEditors[0];
    cellEditors[3] = new CheckboxCellEditor(table);
    
    tableViewer.setCellEditors(cellEditors);
    
    tableViewer.setCellModifier(new ICellModifier() {
      public boolean canModify(Object element, String property) {
        return true;
      }
      public Object getValue(Object element, String property) {
        // Get the index first. 
        int index = -1;
        for(int i=0; i<colNames.length; i++) {
          if(colNames[i].equals(property)) {
            index = i;
            break;
          }
        }
        Bug bug = (Bug)element;
        
        switch(index) {
          case 0:
            return bug.id;
          case 1:
            return bug.summary;
          case 2:
            return bug.assignedTo;
          case 3:
            return new Boolean(bug.isSolved);
        }
        
        return null;
      }
      public void modify(Object element, String property, Object value) {
        System.out.println("Modify: " + element + ", " + property + ", " + value);
        // Get the index first. 
        int index = -1;
        for(int i=0; i<colNames.length; i++) {
          if(colNames[i].equals(property)) {
            index = i;
            break;
          }
        }
        
        Bug bug = null;
        if(element instanceof Item) {
          TableItem item = (TableItem)element;
          bug = (Bug)item.getData();
        }else{
          bug = (Bug)element;
        }
        
        switch(index) {
          case 0:
            bug.id = (String)value;
            break;
          case 1:
            bug.summary = (String)value;
            break;
          case 2:
            bug.assignedTo = (String)value;
            break;
          case 3:
            bug.isSolved = ((Boolean)value).booleanValue();
            break;
        }
        
        tableViewer.update(bug, null);
      }
    });
    
    // Setting sorters. 
    tcID.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        tableViewer.setSorter(new BugSorter(colNames[0]));
      }
    });
    
    tcSummary.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        tableViewer.setSorter(new BugSorter(colNames[1]));
      }
    });
    
    tcAssignedTo.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        tableViewer.setSorter(new BugSorter(colNames[2]));
      }
    });    
    
    tcSolved.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        tableViewer.setSorter(new BugSorter(colNames[3]));
      }
    });
    
    bugs = Bug.loadBugs(new File("bugs.dat"));
    
    tableViewer.setInput(bugs);
    shell.pack();
    shell.open();
    //textUser.forceFocus();
    // Set up the event loop.
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        // If no more entries in event queue
        display.sleep();
      }
    }
    display.dispose();
  }
  
  
  private void saveBugs(Vector v) {
    // Save bugs to a file.
    DataOutputStream out = null;
    try {
      File file = new File("bugs.dat");
      out = new DataOutputStream(new FileOutputStream(file));
      for (int i = 0; i < v.size(); i++) {
        Bug bug = (Bug)v.elementAt(i);
        out.writeUTF(bug.id);
        out.writeUTF(bug.summary);
        out.writeUTF(bug.assignedTo);
        out.writeBoolean(bug.isSolved);
      }
    } catch (IOException ioe) {
      // Ignore.
    } finally {
      try {
        if (out != null)
          out.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  public static void main(String[] args) {
    new BugTrackerJFace();
  }
}





Color cells and rows in SWT table

/*
 * Table example snippet: color cells and rows in table
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class Snippet129 {
  public static void main(String[] args) {
    Display display = new Display();
    Color red = display.getSystemColor(SWT.COLOR_RED);
    Color blue = display.getSystemColor(SWT.COLOR_BLUE);
    Color white = display.getSystemColor(SWT.COLOR_WHITE);
    Color gray = display.getSystemColor(SWT.COLOR_GRAY);
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    Table table = new Table(shell, SWT.BORDER);
    table.setBackground(gray);
    TableColumn column1 = new TableColumn(table, SWT.NONE);
    TableColumn column2 = new TableColumn(table, SWT.NONE);
    TableColumn column3 = new TableColumn(table, SWT.NONE);
    TableItem item = new TableItem(table, SWT.NONE);
    item.setText(new String[] { "entire", "row", "red foreground" });
    item.setForeground(red);
    item = new TableItem(table, SWT.NONE);
    item.setText(new String[] { "entire", "row", "red background" });
    item.setBackground(red);
    item = new TableItem(table, SWT.NONE);
    item.setText(new String[] { "entire", "row", "white fore/red back" });
    item.setForeground(white);
    item.setBackground(red);
    item = new TableItem(table, SWT.NONE);
    item.setText(new String[] { "normal", "blue foreground",
        "red foreground" });
    item.setForeground(1, blue);
    item.setForeground(2, red);
    item = new TableItem(table, SWT.NONE);
    item.setText(new String[] { "normal", "blue background",
        "red background" });
    item.setBackground(1, blue);
    item.setBackground(2, red);
    item = new TableItem(table, SWT.NONE);
    item.setText(new String[] { "white fore/blue back", "normal",
        "white fore/red back" });
    item.setForeground(0, white);
    item.setBackground(0, blue);
    item.setForeground(2, white);
    item.setBackground(2, red);
    column1.pack();
    column2.pack();
    column3.pack();
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Create a SWT table (columns, headers, lines)

/*
 * Table example snippet: create a table (columns, headers, lines)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class Snippet38 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    Table table = new Table(shell, SWT.MULTI | SWT.BORDER
        | SWT.FULL_SELECTION);
    table.setLinesVisible(true);
    table.setHeaderVisible(true);
    String[] titles = { " ", "C", "!", "Description", "Resource",
        "In Folder", "Location" };
    for (int i = 0; i < titles.length; i++) {
      TableColumn column = new TableColumn(table, SWT.NONE);
      column.setText(titles[i]);
    }
    int count = 128;
    for (int i = 0; i < count; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText(0, "x");
      item.setText(1, "y");
      item.setText(2, "!");
      item.setText(3, "this stuff behaves the way I expect");
      item.setText(4, "almost everywhere");
      item.setText(5, "some.folder");
      item.setText(6, "line " + i + " in nowhere");
    }
    for (int i = 0; i < titles.length; i++) {
      table.getColumn(i).pack();
    }
    table.setSize(table.ruputeSize(SWT.DEFAULT, 200));
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Create a SWT table (no columns, no headers)

 
/*
 * Table example snippet: create a table (no columns, no headers)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class Snippet35 {
public static void main (String [] args) {
  Display display = new Display ();
  Shell shell = new Shell (display);
  Table table = new Table (shell, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
  for (int i=0; i<12; i++) {
    TableItem item = new TableItem (table, 0);
    item.setText ("Item " + i);
  }
  table.setSize (100, 100);
  shell.setSize (200, 200);
  shell.open ();
  while (!shell.isDisposed()) {
    if (!display.readAndDispatch ()) display.sleep ();
  }
  display.dispose ();
}
}





Create a SWT table with 1,000,000 items

/*
 * Virtual Table example snippet: create a table with 1,000,000 items
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class Snippet144 {
  static final int COUNT = 1000000;
  public static void main(String[] args) {
    Display display = new Display();
    final Shell shell = new Shell(display);
    shell.setLayout(new RowLayout(SWT.VERTICAL));
    final Table table = new Table(shell, SWT.VIRTUAL | SWT.BORDER);
    table.addListener(SWT.SetData, new Listener() {
      public void handleEvent(Event event) {
        TableItem item = (TableItem) event.item;
        int index = table.indexOf(item);
        item.setText("Item " + index);
        System.out.println(item.getText());
      }
    });
    table.setLayoutData(new RowData(200, 200));
    Button button = new Button(shell, SWT.PUSH);
    button.setText("Add Items");
    final Label label = new Label(shell, SWT.NONE);
    button.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        long t1 = System.currentTimeMillis();
        table.setItemCount(COUNT);
        long t2 = System.currentTimeMillis();
        label.setText("Items: " + COUNT + ", Time: " + (t2 - t1)
            + " (ms)");
        shell.layout();
      }
    });
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Create a table (lazy)

/*
 * example snippet: create a table (lazy)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class Snippet7 {
  
public static void main (String [] args) {
  final Display display = new Display ();
  final Image image = new Image (display, 16, 16);
  GC gc = new GC (image);
  gc.setBackground (display.getSystemColor (SWT.COLOR_RED));
  gc.fillRectangle (image.getBounds ());
  gc.dispose ();
  final Shell shell = new Shell (display);
  shell.setText ("Lazy Table");
  shell.setLayout (new FillLayout ());
  final Table table = new Table (shell, SWT.BORDER | SWT.MULTI);
  table.setSize (200, 200);
  Thread thread = new Thread () {
    public void run () {
      for (int i=0; i<20000; i++) {
        if (table.isDisposed ()) return;
        final int [] index = new int [] {i};
        display.syncExec (new Runnable () {
          public void run () {
            if (table.isDisposed ()) return;
            TableItem item = new TableItem (table, SWT.NONE);
            item.setText ("Table Item " + index [0]);
            item.setImage (image);
          }
        });
      }
    }
  };
  thread.start ();
  shell.setSize (200, 200);
  shell.open ();
  while (!shell.isDisposed ()) {
    if (!display.readAndDispatch ()) display.sleep ();
  }
  image.dispose ();
  display.dispose ();
}
}





Create a virtual SWT table and add 1000 entries to it every 500 ms

/*
 * Create a virtual table and add 1000 entries to it every 500 ms.
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import java.util.Arrays;
import java.util.Random;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class Snippet151 {
static int[] data = new int[0];
public static void main (String [] args) {
  final Display display = new Display ();
  Shell shell = new Shell (display);
  shell.setLayout(new FillLayout());
  final Table table = new Table(shell, SWT.BORDER | SWT.VIRTUAL);
  table.addListener(SWT.SetData, new Listener() {
    public void handleEvent(Event e) {
      TableItem item = (TableItem)e.item;
      int index = table.indexOf(item);
      item.setText("Item "+data[index]);
    }
  });
  Thread thread = new Thread() {
    public void run() {
      int count = 0;
      Random random = new Random();
      while (count++ < 500) {
        if (table.isDisposed()) return;
        // add 10 random numbers to array and sort
        int grow = 10;
        int[] newData = new int[data.length + grow];
        System.arraycopy(data, 0, newData, 0, data.length);
        int index = data.length;
        data = newData;
        for (int j = 0; j < grow; j++) {
          data[index++] = random.nextInt();
        }
        Arrays.sort(data);
        display.syncExec(new Runnable() {
          public void run() {
            if (table.isDisposed()) return;
            table.setItemCount(data.length);
            table.clearAll();
          }
        });
        try {Thread.sleep(500);} catch (Throwable t) {}
      }
    }
  };
  thread.start();
  shell.open ();
  while (!shell.isDisposed() || thread.isAlive()) {
    if (!display.readAndDispatch ()) display.sleep ();
  }
  display.dispose ();
}
}





Demonstrates CellEditors

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxCellEditor;
import org.eclipse.jface.viewers.ColorCellEditor;
import org.eclipse.jface.viewers.ruboBoxCellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.ruposite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
/**
 * This class demonstrates CellEditors. It allows you to create and edit Person
 * objects
 */
public class PersonEditor extends ApplicationWindow {
  // Table column names/properties
  public static final String NAME = "Name";
  public static final String MALE = "Male?";
  public static final String AGE = "Age Range";
  public static final String SHIRT_COLOR = "Shirt Color";
  public static final String[] PROPS = { NAME, MALE, AGE, SHIRT_COLOR };
  // The data model
  private java.util.List people;
  /**
   * Constructs a PersonEditor
   */
  public PersonEditor() {
    super(null);
    people = new ArrayList();
  }
  /**
   * Runs the application
   */
  public void run() {
    // Don"t return from open() until window closes
    setBlockOnOpen(true);
    // Open the main window
    open();
    // Dispose the display
    Display.getCurrent().dispose();
  }
  /**
   * Configures the shell
   * 
   * @param shell
   *            the shell
   */
  protected void configureShell(Shell shell) {
    super.configureShell(shell);
    shell.setText("Person Editor");
    shell.setSize(400, 400);
  }
  /**
   * Creates the main window"s contents
   * 
   * @param parent
   *            the main window
   * @return Control
   */
  protected Control createContents(Composite parent) {
    Composite composite = new Composite(parent, SWT.NONE);
    composite.setLayout(new GridLayout(1, false));
    // Add a button to create the new person
    Button newPerson = new Button(composite, SWT.PUSH);
    newPerson.setText("Create New Person");
    // Add the TableViewer
    final TableViewer tv = new TableViewer(composite, SWT.FULL_SELECTION);
    tv.setContentProvider(new PersonContentProvider());
    tv.setLabelProvider(new PersonLabelProvider());
    tv.setInput(people);
    // Set up the table
    Table table = tv.getTable();
    table.setLayoutData(new GridData(GridData.FILL_BOTH));
    new TableColumn(table, SWT.CENTER).setText(NAME);
    new TableColumn(table, SWT.CENTER).setText(MALE);
    new TableColumn(table, SWT.CENTER).setText(AGE);
    new TableColumn(table, SWT.CENTER).setText(SHIRT_COLOR);
    for (int i = 0, n = table.getColumnCount(); i < n; i++) {
      table.getColumn(i).pack();
    }
    table.setHeaderVisible(true);
    table.setLinesVisible(true);
    // Add a new person when the user clicks button
    newPerson.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        Person p = new Person();
        p.setName("Name");
        p.setMale(true);
        p.setAgeRange(Integer.valueOf("0"));
        p.setShirtColor(new RGB(255, 0, 0));
        people.add(p);
        tv.refresh();
      }
    });
    // Create the cell editors
    CellEditor[] editors = new CellEditor[4];
    editors[0] = new TextCellEditor(table);
    editors[1] = new CheckboxCellEditor(table);
    editors[2] = new ComboBoxCellEditor(table, AgeRange.INSTANCES,
        SWT.READ_ONLY);
    editors[3] = new ColorCellEditor(table);
    // Set the editors, cell modifier, and column properties
    tv.setColumnProperties(PROPS);
    tv.setCellModifier(new PersonCellModifier(tv));
    tv.setCellEditors(editors);
    return composite;
  }
  /**
   * The application entry point
   * 
   * @param args
   *            the command line arguments
   */
  public static void main(String[] args) {
    new PersonEditor().run();
  }
}
/**
 * This class provides the content for the person table
 */
class PersonContentProvider implements IStructuredContentProvider {
  /**
   * Returns the Person objects
   */
  public Object[] getElements(Object inputElement) {
    return ((List) inputElement).toArray();
  }
  /**
   * Disposes any created resources
   */
  public void dispose() {
    // Do nothing
  }
  /**
   * Called when the input changes
   */
  public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
    // Ignore
  }
}
/**
 * This class provides the content for the FoodList application
 */
class FoodContentProvider implements IStructuredContentProvider {
  /**
   * Gets the food items for the list
   * 
   * @param arg0
   *            the data model
   * @return Object[]
   */
  public Object[] getElements(Object arg0) {
    return ((GroceryList) arg0).getFoods().toArray();
  }
  /**
   * Disposes any created resources
   */
  public void dispose() {
    // Do nothing
  }
  /**
   * Called when the input changes
   * 
   * @param arg0
   *            the viewer
   * @param arg1
   *            the old input
   * @param arg2
   *            the new input
   */
  public void inputChanged(Viewer arg0, Object arg1, Object arg2) {
    // Do nothing
  }
}
/**
 * This class represents the cell modifier for the PersonEditor program
 */
class PersonCellModifier implements ICellModifier {
  private Viewer viewer;
  public PersonCellModifier(Viewer viewer) {
    this.viewer = viewer;
  }
  /**
   * Returns whether the property can be modified
   * 
   * @param element
   *            the element
   * @param property
   *            the property
   * @return boolean
   */
  public boolean canModify(Object element, String property) {
    // Allow editing of all values
    return true;
  }
  /**
   * Returns the value for the property
   * 
   * @param element
   *            the element
   * @param property
   *            the property
   * @return Object
   */
  public Object getValue(Object element, String property) {
    Person p = (Person) element;
    if (PersonEditor.NAME.equals(property))
      return p.getName();
    else if (PersonEditor.MALE.equals(property))
      return Boolean.valueOf(p.isMale());
    else if (PersonEditor.AGE.equals(property))
      return p.getAgeRange();
    else if (PersonEditor.SHIRT_COLOR.equals(property))
      return p.getShirtColor();
    else
      return null;
  }
  /**
   * Modifies the element
   * 
   * @param element
   *            the element
   * @param property
   *            the property
   * @param value
   *            the value
   */
  public void modify(Object element, String property, Object value) {
    if (element instanceof Item)
      element = ((Item) element).getData();
    Person p = (Person) element;
    if (PersonEditor.NAME.equals(property))
      p.setName((String) value);
    else if (PersonEditor.MALE.equals(property))
      p.setMale(((Boolean) value).booleanValue());
    else if (PersonEditor.AGE.equals(property))
      p.setAgeRange((Integer) value);
    else if (PersonEditor.SHIRT_COLOR.equals(property))
      p.setShirtColor((RGB) value);
    // Force the viewer to refresh
    viewer.refresh();
  }
}
/**
 * This class represents a person
 */
class Person {
  private String name;
  private boolean male;
  private Integer ageRange;
  private RGB shirtColor;
  /**
   * @return Returns the ageRange.
   */
  public Integer getAgeRange() {
    return ageRange;
  }
  /**
   * @param ageRange
   *            The ageRange to set.
   */
  public void setAgeRange(Integer ageRange) {
    this.ageRange = ageRange;
  }
  /**
   * @return Returns the male.
   */
  public boolean isMale() {
    return male;
  }
  /**
   * @param male
   *            The male to set.
   */
  public void setMale(boolean male) {
    this.male = male;
  }
  /**
   * @return Returns the name.
   */
  public String getName() {
    return name;
  }
  /**
   * @param name
   *            The name to set.
   */
  public void setName(String name) {
    this.name = name;
  }
  /**
   * @return Returns the shirtColor.
   */
  public RGB getShirtColor() {
    return shirtColor;
  }
  /**
   * @param shirtColor
   *            The shirtColor to set.
   */
  public void setShirtColor(RGB shirtColor) {
    this.shirtColor = shirtColor;
  }
}
/**
 * This class contains all the foods on the "grocery list"
 */
class GroceryList {
  // Holds the foods
  private List foods;
  /**
   * Constructs a grocery list
   */
  public GroceryList() {
    foods = new ArrayList();
    // Add some foods
    foods.add(new Food("Broccoli", true));
    foods.add(new Food("Bundt Cake", false));
    foods.add(new Food("Cabbage", true));
    foods.add(new Food("Candy Canes", false));
    foods.add(new Food("Eggs", true));
    foods.add(new Food("Potato Chips", false));
    foods.add(new Food("Milk", true));
    foods.add(new Food("Soda", false));
    foods.add(new Food("Chicken", true));
    foods.add(new Food("Cinnamon Rolls", false));
  }
  /**
   * Returns the foods in this grocery list
   * 
   * @return List
   */
  public List getFoods() {
    return Collections.unmodifiableList(foods);
  }
}
/**
 * This class represents a type of food
 */
class Food {
  // The name of the food
  private String name;
  // Is it healthy?
  private boolean healthy;
  /**
   * Food constructor
   * 
   * @param name
   *            the name
   * @param healthy
   *            whether or not it"s healthy
   */
  public Food(String name, boolean healthy) {
    this.name = name;
    this.healthy = healthy;
  }
  /**
   * Gets whether this is healthy
   * 
   * @return boolean
   */
  public boolean isHealthy() {
    return healthy;
  }
  /**
   * Gets the name
   * 
   * @return String
   */
  public String getName() {
    return name;
  }
}
/**
 * This class provides the labels for the person table
 */
class PersonLabelProvider implements ITableLabelProvider {
  /**
   * Returns the image
   * 
   * @param element
   *            the element
   * @param columnIndex
   *            the column index
   * @return Image
   */
  public Image getColumnImage(Object element, int columnIndex) {
    return null;
  }
  /**
   * Returns the column text
   * 
   * @param element
   *            the element
   * @param columnIndex
   *            the column index
   * @return String
   */
  public String getColumnText(Object element, int columnIndex) {
    Person person = (Person) element;
    switch (columnIndex) {
    case 0:
      return person.getName();
    case 1:
      return Boolean.toString(person.isMale());
    case 2:
      return AgeRange.INSTANCES[person.getAgeRange().intValue()];
    case 3:
      return person.getShirtColor().toString();
    }
    return null;
  }
  /**
   * Adds a listener
   * 
   * @param listener
   *            the listener
   */
  public void addListener(ILabelProviderListener listener) {
    // Ignore it
  }
  /**
   * Disposes any created resources
   */
  public void dispose() {
    // Nothing to dispose
  }
  /**
   * Returns whether altering this property on this element will affect the
   * label
   * 
   * @param element
   *            the element
   * @param property
   *            the property
   * @return boolean
   */
  public boolean isLabelProperty(Object element, String property) {
    return false;
  }
  /**
   * Removes a listener
   * 
   * @param listener
   *            the listener
   */
  public void removeListener(ILabelProviderListener listener) {
    // Ignore
  }
}

/**
 * This class encapsulates age ranges
 */
class AgeRange {
  public static final String NONE = "";
  public static final String BABY = "0 - 3";
  public static final String TODDLER = "4 - 7";
  public static final String CHILD = "8 - 12";
  public static final String TEENAGER = "13 - 19";
  public static final String ADULT = "20 - ?";
  public static final String[] INSTANCES = { NONE, BABY, TODDLER, CHILD,
      TEENAGER, ADULT };
}





Demonstrates CheckboxTableViewer

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.ruposite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
/**
 * This class demonstrates CheckboxTableViewer. It allows you to check files to
 * copy, and copy them to a backup directory.
 */
public class BackupFiles extends ApplicationWindow {
  // Used to show status
  private Label status;
  /**
   * BackupFiles constructor
   */
  public BackupFiles() {
    super(null);
  }
  /**
   * Runs the application
   */
  public void run() {
    // Don"t return from open() until window closes
    setBlockOnOpen(true);
    // Open the main window
    open();
    // Dispose the display
    Display.getCurrent().dispose();
  }
  /**
   * Configures the shell
   * 
   * @param shell
   *            the shell
   */
  protected void configureShell(Shell shell) {
    super.configureShell(shell);
    // Set the title bar text and the size
    shell.setText("Backup Files");
    shell.setSize(400, 400);
  }
  /**
   * Creates the main window"s contents
   * 
   * @param parent
   *            the main window
   * @return Control
   */
  protected Control createContents(Composite parent) {
    Composite composite = new Composite(parent, SWT.NONE);
    composite.setLayout(new GridLayout(1, false));
    // Create the source directory panel and its controls
    final Text sourceDir = createFilePanelHelper(composite, "Source Dir:");
    // Create the CheckboxTableViewer to display the files in the source dir
    final CheckboxTableViewer ctv = CheckboxTableViewer.newCheckList(
        composite, SWT.BORDER);
    ctv.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));
    ctv.setContentProvider(new BackupFilesContentProvider());
    ctv.setLabelProvider(new BackupFilesLabelProvider());
    // Create the destination directory panel and its controls
    final Text destDir = createFilePanelHelper(composite, "Dest Dir:");
    // Create the Copy button
    Button copy = new Button(composite, SWT.PUSH);
    copy.setText("Copy");
    // Create the status field
    status = new Label(composite, SWT.NONE);
    status.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    // When the source directory changes, change the input for the viewer
    sourceDir.addModifyListener(new ModifyListener() {
      public void modifyText(ModifyEvent event) {
        ctv.setInput(((Text) event.widget).getText());
      }
    });
    // When copy is pressed, copy the files
    copy.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        // Get the checked elements
        Object[] files = ctv.getCheckedElements();
        if (files.length > 0) {
          // Some files are checked; make sure we have a valid
          // destination
          File dest = new File(destDir.getText());
          if (dest.isDirectory()) {
            // Go through each file
            for (int i = 0, n = files.length; i < n; i++) {
              copyFile((File) files[i], dest);
            }
          } else
            showMessage("You must select a valid destination directory");
        } else
          showMessage("You must select some files to copy");
      }
    });
    return composite;
  }
  /**
   * Helper method to create the label/text/button for a directory
   * 
   * @param composite
   *            the parent composite
   * @param label
   *            the text for the label
   * @return Text
   */
  private Text createFilePanelHelper(Composite composite, String label) {
    // Create the composite to hold the controls
    Composite panel = new Composite(composite, SWT.BORDER);
    panel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    panel.setLayout(new GridLayout(3, false));
    // Create the controls
    new Label(panel, SWT.LEFT).setText(label);
    Text text = new Text(panel, SWT.BORDER);
    text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    Button browse = new Button(panel, SWT.PUSH);
    // Add browsing
    browse.setText("...");
    browse.addSelectionListener(new DirectoryBrowser(text));
    // Return the Text that holds the directory
    return text;
  }
  /**
   * Copies a file
   * 
   * @param file
   *            the file to copy
   * @param targetDir
   *            the directory to copy to
   */
  private void copyFile(File file, File targetDir) {
    BufferedInputStream in = null;
    BufferedOutputStream out = null;
    File destFile = new File(targetDir.getAbsolutePath() + File.separator
        + file.getName());
    try {
      showMessage("Copying " + file.getName());
      in = new BufferedInputStream(new FileInputStream(file));
      out = new BufferedOutputStream(new FileOutputStream(destFile));
      int n;
      while ((n = in.read()) != -1) {
        out.write(n);
      }
      showMessage("Copied " + file.getName());
    } catch (Exception e) {
      showMessage("Cannot copy file " + file.getAbsolutePath());
    } finally {
      if (in != null)
        try {
          in.close();
        } catch (Exception e) {
        }
      if (out != null)
        try {
          out.close();
        } catch (Exception e) {
        }
    }
  }
  /**
   * Shows a message
   * 
   * @param message
   *            the message
   */
  private void showMessage(String message) {
    status.setText(message);
  }
  /**
   * The application entry point
   * 
   * @param args
   *            the command line arguments
   */
  public static void main(String[] args) {
    new BackupFiles().run();
  }
}
/**
 * This class returns the files in the specified directory. If the specified
 * directory doesn"t exist, it returns an empty array.
 */
class BackupFilesContentProvider implements IStructuredContentProvider {
  private static final Object[] EMPTY = new Object[] {};
  /**
   * Gets the files in the specified directory
   * 
   * @param arg0
   *            a String containing the directory
   */
  public Object[] getElements(Object arg0) {
    File file = new File((String) arg0);
    if (file.isDirectory()) {
      return file.listFiles(new FileFilter() {
        public boolean accept(File pathName) {
          // Ignore directories; return only files
          return pathName.isFile();
        }
      });
    }
    return EMPTY;
  }
  /**
   * Disposes any created resources
   */
  public void dispose() {
    // Nothing to dispose
  }
  /**
   * Called when the input changes
   */
  public void inputChanged(Viewer arg0, Object arg1, Object arg2) {
    // Nothing to do
  }
}
/**
 * This class provides the labels for files
 */
class BackupFilesLabelProvider implements ILabelProvider {
  /**
   * Returns the image
   * 
   * @param arg0
   *            the file
   * @return Image
   */
  public Image getImage(Object arg0) {
    return null;
  }
  /**
   * Returns the name of the file
   * 
   * @param arg0
   *            the name of the file
   * @return String
   */
  public String getText(Object arg0) {
    return ((File) arg0).getName();
  }
  /**
   * Adds a listener
   * 
   * @param arg0
   *            the listener
   */
  public void addListener(ILabelProviderListener arg0) {
    // Throw it away
  }
  /**
   * Disposes any created resources
   */
  public void dispose() {
    // Nothing to dispose
  }
  /**
   * Returns whether changing this property for this element affects the label
   * 
   * @param arg0
   *            the element
   * @param arg1
   *            the property
   */
  public boolean isLabelProperty(Object arg0, String arg1) {
    return false;
  }
  /**
   * Removes a listener
   * 
   * @param arg0
   *            the listener
   */
  public void removeListener(ILabelProviderListener arg0) {
    // Ignore
  }
}
/**
 * This class allows users to browse for a directory
 */
class DirectoryBrowser extends SelectionAdapter {
  // The Text this browser is tied to
  private Text text;
  /**
   * DirectoryBrowser constructor
   * 
   * @param text
   */
  public DirectoryBrowser(Text text) {
    this.text = text;
  }
  /**
   * Called when the browse button is pushed
   * 
   * @param event
   *            the generated event
   */
  public void widgetSelected(SelectionEvent event) {
    DirectoryDialog dlg = new DirectoryDialog(Display.getCurrent()
        .getActiveShell());
    dlg.setFilterPath(text.getText());
    String dir = dlg.open();
    if (dir != null) {
      text.setText(dir);
    }
  }
}





Demonstrates TableCursor

//Send questions, comments, bug reports, etc. to the authors:
//Rob Warner (rwarner@interspatial.ru)
//Robert Harris (rbrt_harris@yahoo.ru)
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
/**
 * This class demonstrates TableCursor
 */
public class TableCursorTest {
  // The number of rows and columns
  private static final int NUM = 5;
  /**
   * Runs the program
   */
  public void run() {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setText("Table Cursor Test");
    createContents(shell);
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
    display.dispose();
  }
  /**
   * Creates the main window"s contents
   * 
   * @param shell the main window
   */
  private void createContents(Shell shell) {
    shell.setLayout(new FillLayout());
    // Create the table
    final Table table = new Table(shell, SWT.SINGLE | SWT.FULL_SELECTION);
    table.setHeaderVisible(true);
    table.setLinesVisible(true);
    // Create the columns
    for (int i = 0; i < NUM; i++) {
      TableColumn column = new TableColumn(table, SWT.CENTER);
      column.setText("Column " + (i + 1));
      column.pack();
    }
    // Create the rows
    for (int i = 0; i < NUM; i++) {
      new TableItem(table, SWT.NONE);
    }
    // Create the TableCursor
    final TableCursor cursor = new TableCursor(table, SWT.NONE);
    // Create the editor
    // Use a ControlEditor, not a TableEditor, because the cursor is the parent
    final ControlEditor editor = new ControlEditor(cursor);
    editor.grabHorizontal = true;
    editor.grabVertical = true;
    // Add the event handling
    cursor.addSelectionListener(new SelectionAdapter() {
      // This is called as the user navigates around the table
      public void widgetSelected(SelectionEvent event) {
        // Select the row in the table where the TableCursor is
        table.setSelection(new TableItem[] { cursor.getRow()});
      }
      // This is called when the user hits Enter
      public void widgetDefaultSelected(SelectionEvent event) {
        // Begin an editing session
        // Notice that the parent of the Text is the TableCursor, not the Table
        final Text text = new Text(cursor, SWT.NONE);
        text.setFocus();
        // Copy the text from the cell to the Text
        text.setText(cursor.getRow().getText(cursor.getColumn()));
        text.setFocus();
        // Add a handler to detect key presses
        text.addKeyListener(new KeyAdapter() {
          public void keyPressed(KeyEvent event) {
            // End the editing and save the text if the user presses Enter
            // End the editing and throw away the text if the user presses Esc
            switch (event.keyCode) {
            case SWT.CR:
              cursor.getRow().setText(cursor.getColumn(), text.getText());
            case SWT.ESC:
              text.dispose();
              break;
            }
          }
        });
        editor.setEditor(text);
      }
    });
  }
  /**
   * The application entry point
   * 
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    new TableCursorTest().run();
  }
}





Demonstrates TableEditor

//Send questions, comments, bug reports, etc. to the authors:
//Rob Warner (rwarner@interspatial.ru)
//Robert Harris (rbrt_harris@yahoo.ru)
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
/**
 * This class demonstrates TableEditor.
 */
public class TextTableEditor {
  // Number of rows and columns
  private static final int NUM = 5;
  // Colors for each row
  private Color[] colors = new Color[NUM];
  // Options for each dropdown
  private String[] options = { "Option 1", "Option 2", "Option 3"};
  /**
   * Runs the application
   */
  public void run() {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setText("Text Table Editor");
    createContents(shell);
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
    // Dispose any created colors
    for (int i = 0; i < NUM; i++) {
      if (colors[i] != null) colors[i].dispose();
    }
    display.dispose();
  }
  /**
   * Creates the main window"s contents
   * 
   * @param shell the main window
   */
  private void createContents(final Shell shell) {
    shell.setLayout(new FillLayout());
    // Create the table
    final Table table = new Table(shell, SWT.SINGLE | SWT.FULL_SELECTION
        | SWT.HIDE_SELECTION);
    table.setHeaderVisible(true);
    table.setLinesVisible(true);
    // Create five columns
    for (int i = 0; i < NUM; i++) {
      TableColumn column = new TableColumn(table, SWT.CENTER);
      column.setText("Column " + (i + 1));
      column.pack();
    }
    // Create five table editors for color
    TableEditor[] colorEditors = new TableEditor[NUM];
    // Create five buttons for changing color
    Button[] colorButtons = new Button[NUM];
    // Create five rows and the editors for those rows. The first column has the
    // color change buttons. The second column has dropdowns. The final three
    // have text fields.
    for (int i = 0; i < NUM; i++) {
      // Create the row
      final TableItem item = new TableItem(table, SWT.NONE);
      // Create the editor and button
      colorEditors[i] = new TableEditor(table);
      colorButtons[i] = new Button(table, SWT.PUSH);
      // Set attributes of the button
      colorButtons[i].setText("Color...");
      colorButtons[i].ruputeSize(SWT.DEFAULT, table.getItemHeight());
      // Set attributes of the editor
      colorEditors[i].grabHorizontal = true;
      colorEditors[i].minimumHeight = colorButtons[i].getSize().y;
      colorEditors[i].minimumWidth = colorButtons[i].getSize().x;
      // Set the editor for the first column in the row
      colorEditors[i].setEditor(colorButtons[i], item, 0);
      // Create a handler for the button
      final int index = i;
      colorButtons[i].addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent event) {
          ColorDialog dialog = new ColorDialog(shell);
          if (colors[index] != null) dialog.setRGB(colors[index].getRGB());
          RGB rgb = dialog.open();
          if (rgb != null) {
            if (colors[index] != null) colors[index].dispose();
            colors[index] = new Color(shell.getDisplay(), rgb);
            item.setForeground(colors[index]);
          }
        }
      });
    }
    // Create an editor object to use for text editing
    final TableEditor editor = new TableEditor(table);
    editor.horizontalAlignment = SWT.LEFT;
    editor.grabHorizontal = true;
    // Use a mouse listener, not a selection listener, since we"re interested
    // in the selected column as well as row
    table.addMouseListener(new MouseAdapter() {
      public void mouseDown(MouseEvent event) {
        // Dispose any existing editor
        Control old = editor.getEditor();
        if (old != null) old.dispose();
        // Determine where the mouse was clicked
        Point pt = new Point(event.x, event.y);
        // Determine which row was selected
        final TableItem item = table.getItem(pt);
        if (item != null) {
          // Determine which column was selected
          int column = -1;
          for (int i = 0, n = table.getColumnCount(); i < n; i++) {
            Rectangle rect = item.getBounds(i);
            if (rect.contains(pt)) {
              // This is the selected column
              column = i;
              break;
            }
          }
          // Column 2 holds dropdowns
          if (column == 1) {
            // Create the dropdown and add data to it
            final CCombo combo = new CCombo(table, SWT.READ_ONLY);
            for (int i = 0, n = options.length; i < n; i++) {
              combo.add(options[i]);
            }
            // Select the previously selected item from the cell
            combo.select(combo.indexOf(item.getText(column)));
            // Compute the width for the editor
            // Also, compute the column width, so that the dropdown fits
            editor.minimumWidth = combo.ruputeSize(SWT.DEFAULT, SWT.DEFAULT).x;
            table.getColumn(column).setWidth(editor.minimumWidth);
            // Set the focus on the dropdown and set into the editor
            combo.setFocus();
            editor.setEditor(combo, item, column);
            // Add a listener to set the selected item back into the cell
            final int col = column;
            combo.addSelectionListener(new SelectionAdapter() {
              public void widgetSelected(SelectionEvent event) {
                item.setText(col, combo.getText());
                // They selected an item; end the editing session
                combo.dispose();
              }
            });
          } else if (column > 1) {
            // Create the Text object for our editor
            final Text text = new Text(table, SWT.NONE);
            text.setForeground(item.getForeground());
            // Transfer any text from the cell to the Text control,
            // set the color to match this row, select the text,
            // and set focus to the control
            text.setText(item.getText(column));
            text.setForeground(item.getForeground());
            text.selectAll();
            text.setFocus();
            // Recalculate the minimum width for the editor
            editor.minimumWidth = text.getBounds().width;
            // Set the control into the editor
            editor.setEditor(text, item, column);
            // Add a handler to transfer the text back to the cell
            // any time it"s modified
            final int col = column;
            text.addModifyListener(new ModifyListener() {
              public void modifyText(ModifyEvent event) {
                // Set the text of the editor"s control back into the cell
                item.setText(col, text.getText());
              }
            });
          }
        }
      }
    });
  }
  /**
   * The application entry point
   * 
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    new TextTableEditor().run();
  }
}





Demonstrates TableViewers

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.rubo;
import org.eclipse.swt.widgets.ruposite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
/**
 * This class demonstrates TableViewers
 */
public class PlayerTable extends ApplicationWindow {
  // The data model
  private PlayerTableModel model;
  // The table viewer
  private TableViewer tv;
  /**
   * Constructs a PlayerTable
   */
  public PlayerTable() {
    super(null);
    model = new PlayerTableModel();
  }
  /**
   * Runs the application
   */
  public void run() {
    // Don"t return from open() until window closes
    setBlockOnOpen(true);
    // Open the main window
    open();
    // Dispose the display
    Display.getCurrent().dispose();
  }
  /**
   * Configures the shell
   * 
   * @param shell
   *            the shell
   */
  protected void configureShell(Shell shell) {
    super.configureShell(shell);
    shell.setSize(400, 400);
  }
  /**
   * Creates the main window"s contents
   * 
   * @param parent
   *            the main window
   * @return Control
   */
  protected Control createContents(Composite parent) {
    // Create the composite to hold the controls
    Composite composite = new Composite(parent, SWT.NONE);
    composite.setLayout(new GridLayout(1, false));
    // Create the combo to hold the team names
    Combo combo = new Combo(composite, SWT.READ_ONLY);
    combo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    // Create the table viewer to display the players
    tv = new TableViewer(composite);
    // Set the content and label providers
    tv.setContentProvider(new PlayerContentProvider());
    tv.setLabelProvider(new PlayerLabelProvider());
    tv.setSorter(new PlayerViewerSorter());
    // Set up the table
    Table table = tv.getTable();
    table.setLayoutData(new GridData(GridData.FILL_BOTH));
    // Add the first name column
    TableColumn tc = new TableColumn(table, SWT.LEFT);
    tc.setText("First Name");
    tc.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        ((PlayerViewerSorter) tv.getSorter())
            .doSort(PlayerConst.COLUMN_FIRST_NAME);
        tv.refresh();
      }
    });
    // Add the last name column
    tc = new TableColumn(table, SWT.LEFT);
    tc.setText("Last Name");
    tc.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        ((PlayerViewerSorter) tv.getSorter())
            .doSort(PlayerConst.COLUMN_LAST_NAME);
        tv.refresh();
      }
    });
    // Add the points column
    tc = new TableColumn(table, SWT.RIGHT);
    tc.setText("Points");
    tc.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        ((PlayerViewerSorter) tv.getSorter())
            .doSort(PlayerConst.COLUMN_POINTS);
        tv.refresh();
      }
    });
    // Add the rebounds column
    tc = new TableColumn(table, SWT.RIGHT);
    tc.setText("Rebounds");
    tc.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        ((PlayerViewerSorter) tv.getSorter())
            .doSort(PlayerConst.COLUMN_REBOUNDS);
        tv.refresh();
      }
    });
    // Add the assists column
    tc = new TableColumn(table, SWT.RIGHT);
    tc.setText("Assists");
    tc.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        ((PlayerViewerSorter) tv.getSorter())
            .doSort(PlayerConst.COLUMN_ASSISTS);
        tv.refresh();
      }
    });
    // Add the team names to the combo
    for (int i = 0, n = model.teams.length; i < n; i++) {
      combo.add(model.teams[i].getName());
    }
    // Add a listener to change the tableviewer"s input
    combo.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        update(model.teams[((Combo) event.widget).getSelectionIndex()]);
      }
    });
    // Select the first item
    combo.select(0);
    update(model.teams[0]);
    // Pack the columns
    for (int i = 0, n = table.getColumnCount(); i < n; i++) {
      table.getColumn(i).pack();
    }
    // Turn on the header and the lines
    table.setHeaderVisible(true);
    table.setLinesVisible(true);
    return composite;
  }
  /**
   * Updates the application with the selected team
   * 
   * @param team
   *            the team
   */
  private void update(Team team) {
    // Update the window"s title bar with the new team
    getShell().setText(team.getYear() + " " + team.getName());
    // Set the table viewer"s input to the team
    tv.setInput(team);
  }
  /**
   * The application entry point
   * 
   * @param args
   *            the command line arguments
   */
  public static void main(String[] args) {
    new PlayerTable().run();
  }
}
/**
 * This class contains the data model for the PlayerTable
 */
class PlayerTableModel {
  public Team[] teams;
  /**
   * Constructs a PlayerTableModel Fills the model with data
   */
  public PlayerTableModel() {
    teams = new Team[3];
    teams[0] = new Team("Celtics", "1985-86");
    teams[0].add(new Player("Larry", "Bird", 25.8f, 9.8f, 6.8f));
    teams[0].add(new Player("Kevin", "McHale", 21.3f, 8.1f, 2.7f));
    teams[0].add(new Player("Robert", "Parish", 16.1f, 9.5f, 1.8f));
    teams[0].add(new Player("Dennis", "Johnson", 15.6f, 3.4f, 5.8f));
    teams[0].add(new Player("Danny", "Ainge", 10.7f, 2.9f, 5.1f));
    teams[0].add(new Player("Scott", "Wedman", 8.0f, 2.4f, 1.1f));
    teams[0].add(new Player("Bill", "Walton", 7.6f, 6.8f, 2.1f));
    teams[0].add(new Player("Jerry", "Sichting", 6.5f, 1.3f, 2.3f));
    teams[0].add(new Player("David", "Thirdkill", 3.3f, 1.4f, 0.3f));
    teams[0].add(new Player("Sam", "Vincent", 3.2f, 0.8f, 1.2f));
    teams[0].add(new Player("Sly", "Williams", 2.8f, 2.5f, 0.3f));
    teams[0].add(new Player("Rick", "Carlisle", 2.6f, 1.0f, 1.4f));
    teams[0].add(new Player("Greg", "Kite", 1.3f, 2.0f, 1.3f));
    teams[1] = new Team("Bulls", "1995-96");
    teams[1].add(new Player("Michael", "Jordan", 30.4f, 6.6f, 4.3f));
    teams[1].add(new Player("Scottie", "Pippen", 19.4f, 6.4f, 5.9f));
    teams[1].add(new Player("Toni", "Kukoc", 13.1f, 4.0f, 3.5f));
    teams[1].add(new Player("Luc", "Longley", 9.1f, 5.1f, 1.9f));
    teams[1].add(new Player("Steve", "Kerr", 8.4f, 1.3f, 2.3f));
    teams[1].add(new Player("Ron", "Harper", 7.4f, 2.7f, 2.6f));
    teams[1].add(new Player("Dennis", "Rodman", 5.5f, 14.9f, 2.5f));
    teams[1].add(new Player("Bill", "Wennington", 5.3f, 2.5f, 0.6f));
    teams[1].add(new Player("Jack", "Haley", 5.0f, 2.0f, 0.0f));
    teams[1].add(new Player("John", "Salley", 4.4f, 3.3f, 1.3f));
    teams[1].add(new Player("Jud", "Buechler", 3.8f, 1.5f, 0.8f));
    teams[1].add(new Player("Dickey", "Simpkins", 3.6f, 2.6f, 0.6f));
    teams[1].add(new Player("James", "Edwards", 3.5f, 1.4f, 0.4f));
    teams[1].add(new Player("Jason", "Caffey", 3.2f, 1.9f, 0.4f));
    teams[1].add(new Player("Randy", "Brown", 2.7f, 1.0f, 1.1f));
    teams[2] = new Team("Lakers", "1987-1988");
    teams[2].add(new Player("Magic", "Johnson", 23.9f, 6.3f, 12.2f));
    teams[2].add(new Player("James", "Worthy", 19.4f, 5.7f, 2.8f));
    teams[2].add(new Player("Kareem", "Abdul-Jabbar", 17.5f, 6.7f, 2.6f));
    teams[2].add(new Player("Byron", "Scott", 17.0f, 3.5f, 3.4f));
    teams[2].add(new Player("A.C.", "Green", 10.8f, 7.8f, 1.1f));
    teams[2].add(new Player("Michael", "Cooper", 10.5f, 3.1f, 4.5f));
    teams[2].add(new Player("Mychal", "Thompson", 10.1f, 4.1f, 0.8f));
    teams[2].add(new Player("Kurt", "Rambis", 5.7f, 5.8f, 0.8f));
    teams[2].add(new Player("Billy", "Thompson", 5.6f, 2.9f, 1.0f));
    teams[2].add(new Player("Adrian", "Branch", 4.3f, 1.7f, 0.5f));
    teams[2].add(new Player("Wes", "Matthews", 4.2f, 0.9f, 2.0f));
    teams[2].add(new Player("Frank", "Brickowski", 4.0f, 2.6f, 0.3f));
    teams[2].add(new Player("Mike", "Smrek", 2.2f, 1.1f, 0.1f));
  }
}
/**
 * This class represents a player
 */
class Player {
  private Team team;
  private String lastName;
  private String firstName;
  private float points;
  private float rebounds;
  private float assists;
  /**
   * Constructs an empty Player
   */
  public Player() {
    this(null, null, 0.0f, 0.0f, 0.0f);
  }
  /**
   * Constructs a Player
   * 
   * @param firstName
   *            the first name
   * @param lastName
   *            the last name
   * @param points
   *            the points
   * @param rebounds
   *            the rebounds
   * @param assists
   *            the assists
   */
  public Player(String firstName, String lastName, float points,
      float rebounds, float assists) {
    setFirstName(firstName);
    setLastName(lastName);
    setPoints(points);
    setRebounds(rebounds);
    setAssists(assists);
  }
  /**
   * Sets the team for theo player
   * 
   * @param team
   *            the team
   */
  public void setTeam(Team team) {
    this.team = team;
  }
  /**
   * Gets the assists
   * 
   * @return float
   */
  public float getAssists() {
    return assists;
  }
  /**
   * Sets the assists
   * 
   * @param assists
   *            The assists to set.
   */
  public void setAssists(float assists) {
    this.assists = assists;
  }
  /**
   * Gets the first name
   * 
   * @return String
   */
  public String getFirstName() {
    return firstName;
  }
  /**
   * Sets the first name
   * 
   * @param firstName
   *            The firstName to set.
   */
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  /**
   * Gets the last name
   * 
   * @return String
   */
  public String getLastName() {
    return lastName;
  }
  /**
   * Sets the last name
   * 
   * @param lastName
   *            The lastName to set.
   */
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  /**
   * Gets the points
   * 
   * @return float
   */
  public float getPoints() {
    return points;
  }
  /**
   * Sets the points
   * 
   * @param points
   *            The points to set.
   */
  public void setPoints(float points) {
    this.points = points;
  }
  /**
   * Gets the rebounds
   * 
   * @return float
   */
  public float getRebounds() {
    return rebounds;
  }
  /**
   * Sets the rebounds
   * 
   * @param rebounds
   *            The rebounds to set.
   */
  public void setRebounds(float rebounds) {
    this.rebounds = rebounds;
  }
  /**
   * Gets the team
   * 
   * @return Team
   */
  public Team getTeam() {
    return team;
  }
  /**
   * Returns whether this player led the team in the specified category
   * 
   * @param column
   *            the column (category)
   * @return boolean
   */
  public boolean ledTeam(int column) {
    return team.led(this, column);
  }
}
/**
 * This class represents a team
 */
class Team {
  private String name;
  private String year;
  private List players;
  /**
   * Constructs a Team
   * 
   * @param name
   *            the name
   * @param year
   *            the year
   */
  public Team(String name, String year) {
    this.name = name;
    this.year = year;
    players = new LinkedList();
  }
  /**
   * Gets the name
   * 
   * @return String
   */
  public String getName() {
    return name;
  }
  /**
   * Gets the year
   * 
   * @return String
   */
  public String getYear() {
    return year;
  }
  /**
   * Adds a player
   * 
   * @param player
   *            the player to add
   * @return boolean
   */
  public boolean add(Player player) {
    boolean added = players.add(player);
    if (added)
      player.setTeam(this);
    return added;
  }
  /**
   * Gets the players
   * 
   * @return List
   */
  public List getPlayers() {
    return Collections.unmodifiableList(players);
  }
  /**
   * Returns whether the specified player led his team in the specified
   * category
   * 
   * @param player
   *            the player
   * @param column
   *            the category
   * @return boolean
   */
  public boolean led(Player player, int column) {
    boolean led = true;
    // Go through all the players on the team, comparing the specified
    // player"s
    // stats with each other player.
    for (int i = 0, n = players.size(); i < n && led; i++) {
      Player test = (Player) players.get(i);
      if (player == test)
        continue;
      switch (column) {
      case PlayerConst.COLUMN_POINTS:
        if (player.getPoints() < test.getPoints())
          led = false;
        break;
      case PlayerConst.COLUMN_REBOUNDS:
        if (player.getRebounds() < test.getRebounds())
          led = false;
        break;
      case PlayerConst.COLUMN_ASSISTS:
        if (player.getAssists() < test.getAssists())
          led = false;
        break;
      }
    }
    return led;
  }
}
/**
 * This class implements the sorting for the Player Table
 */
class PlayerViewerSorter extends ViewerSorter {
  private static final int ASCENDING = 0;
  private static final int DESCENDING = 1;
  private int column;
  private int direction;
  /**
   * Does the sort. If it"s a different column from the previous sort, do an
   * ascending sort. If it"s the same column as the last sort, toggle the sort
   * direction.
   * 
   * @param column
   */
  public void doSort(int column) {
    if (column == this.column) {
      // Same column as last sort; toggle the direction
      direction = 1 - direction;
    } else {
      // New column; do an ascending sort
      this.column = column;
      direction = ASCENDING;
    }
  }
  /**
   * Compares the object for sorting
   */
  public int compare(Viewer viewer, Object e1, Object e2) {
    int rc = 0;
    Player p1 = (Player) e1;
    Player p2 = (Player) e2;
    // Determine which column and do the appropriate sort
    switch (column) {
    case PlayerConst.COLUMN_FIRST_NAME:
      rc = collator.rupare(p1.getFirstName(), p2.getFirstName());
      break;
    case PlayerConst.COLUMN_LAST_NAME:
      rc = collator.rupare(p1.getLastName(), p2.getLastName());
      break;
    case PlayerConst.COLUMN_POINTS:
      rc = p1.getPoints() > p2.getPoints() ? 1 : -1;
      break;
    case PlayerConst.COLUMN_REBOUNDS:
      rc = p1.getRebounds() > p2.getRebounds() ? 1 : -1;
      break;
    case PlayerConst.COLUMN_ASSISTS:
      rc = p1.getAssists() > p2.getAssists() ? 1 : -1;
      break;
    }
    // If descending order, flip the direction
    if (direction == DESCENDING)
      rc = -rc;
    return rc;
  }
}
/**
 * This class contains constants for the PlayerTable application
 */
class PlayerConst {
  // Column constants
  public static final int COLUMN_FIRST_NAME = 0;
  public static final int COLUMN_LAST_NAME = 1;
  public static final int COLUMN_POINTS = 2;
  public static final int COLUMN_REBOUNDS = 3;
  public static final int COLUMN_ASSISTS = 4;
}
/**
 * This class provides the labels for the person table
 */
class PersonLabelProvider implements ITableLabelProvider {
  /**
   * Returns the image
   * 
   * @param element
   *            the element
   * @param columnIndex
   *            the column index
   * @return Image
   */
  public Image getColumnImage(Object element, int columnIndex) {
    return null;
  }
  /**
   * Returns the column text
   * 
   * @param element
   *            the element
   * @param columnIndex
   *            the column index
   * @return String
   */
  public String getColumnText(Object element, int columnIndex) {
    Person person = (Person) element;
    switch (columnIndex) {
    case 0:
      return person.getName();
    case 1:
      return Boolean.toString(person.isMale());
    case 2:
      return AgeRange.INSTANCES[person.getAgeRange().intValue()];
    case 3:
      return person.getShirtColor().toString();
    }
    return null;
  }
  /**
   * Adds a listener
   * 
   * @param listener
   *            the listener
   */
  public void addListener(ILabelProviderListener listener) {
    // Ignore it
  }
  /**
   * Disposes any created resources
   */
  public void dispose() {
    // Nothing to dispose
  }
  /**
   * Returns whether altering this property on this element will affect the
   * label
   * 
   * @param element
   *            the element
   * @param property
   *            the property
   * @return boolean
   */
  public boolean isLabelProperty(Object element, String property) {
    return false;
  }
  /**
   * Removes a listener
   * 
   * @param listener
   *            the listener
   */
  public void removeListener(ILabelProviderListener listener) {
    // Ignore
  }
}
/**
 * This class represents a person
 */
class Person {
  private String name;
  private boolean male;
  private Integer ageRange;
  private RGB shirtColor;
  /**
   * @return Returns the ageRange.
   */
  public Integer getAgeRange() {
    return ageRange;
  }
  /**
   * @param ageRange
   *            The ageRange to set.
   */
  public void setAgeRange(Integer ageRange) {
    this.ageRange = ageRange;
  }
  /**
   * @return Returns the male.
   */
  public boolean isMale() {
    return male;
  }
  /**
   * @param male
   *            The male to set.
   */
  public void setMale(boolean male) {
    this.male = male;
  }
  /**
   * @return Returns the name.
   */
  public String getName() {
    return name;
  }
  /**
   * @param name
   *            The name to set.
   */
  public void setName(String name) {
    this.name = name;
  }
  /**
   * @return Returns the shirtColor.
   */
  public RGB getShirtColor() {
    return shirtColor;
  }
  /**
   * @param shirtColor
   *            The shirtColor to set.
   */
  public void setShirtColor(RGB shirtColor) {
    this.shirtColor = shirtColor;
  }
}
/**
 * This class encapsulates age ranges
 */
class AgeRange {
  public static final String NONE = "";
  public static final String BABY = "0 - 3";
  public static final String TODDLER = "4 - 7";
  public static final String CHILD = "8 - 12";
  public static final String TEENAGER = "13 - 19";
  public static final String ADULT = "20 - ?";
  public static final String[] INSTANCES = { NONE, BABY, TODDLER, CHILD,
      TEENAGER, ADULT };
}
/**
 * This class provides the labels for PlayerTable
 */
class PlayerLabelProvider implements ITableLabelProvider {
  // Image to display if the player led his team
  private Image ball;
  // Constructs a PlayerLabelProvider
  public PlayerLabelProvider() {
    // Create the image
    try {
      ball = new Image(null, new FileInputStream("images/ball.png"));
    } catch (FileNotFoundException e) {
      // Swallow it
    }
  }
  /**
   * Gets the image for the specified column
   * 
   * @param arg0
   *            the player
   * @param arg1
   *            the column
   * @return Image
   */
  public Image getColumnImage(Object arg0, int arg1) {
    Player player = (Player) arg0;
    Image image = null;
    switch (arg1) {
    // A player can"t lead team in first name or last name
    case PlayerConst.COLUMN_POINTS:
    case PlayerConst.COLUMN_REBOUNDS:
    case PlayerConst.COLUMN_ASSISTS:
      if (player.ledTeam(arg1))
        // Set the image
        image = ball;
      break;
    }
    return image;
  }
  /**
   * Gets the text for the specified column
   * 
   * @param arg0
   *            the player
   * @param arg1
   *            the column
   * @return String
   */
  public String getColumnText(Object arg0, int arg1) {
    Player player = (Player) arg0;
    String text = "";
    switch (arg1) {
    case PlayerConst.COLUMN_FIRST_NAME:
      text = player.getFirstName();
      break;
    case PlayerConst.COLUMN_LAST_NAME:
      text = player.getLastName();
      break;
    case PlayerConst.COLUMN_POINTS:
      text = String.valueOf(player.getPoints());
      break;
    case PlayerConst.COLUMN_REBOUNDS:
      text = String.valueOf(player.getRebounds());
      break;
    case PlayerConst.COLUMN_ASSISTS:
      text = String.valueOf(player.getAssists());
      break;
    }
    return text;
  }
  /**
   * Adds a listener
   * 
   * @param arg0
   *            the listener
   */
  public void addListener(ILabelProviderListener arg0) {
    // Throw it away
  }
  /**
   * Dispose any created resources
   */
  public void dispose() {
    // Dispose the image
    if (ball != null)
      ball.dispose();
  }
  /**
   * Returns whether the specified property, if changed, would affect the
   * label
   * 
   * @param arg0
   *            the player
   * @param arg1
   *            the property
   * @return boolean
   */
  public boolean isLabelProperty(Object arg0, String arg1) {
    return false;
  }
  /**
   * Removes the specified listener
   * 
   * @param arg0
   *            the listener
   */
  public void removeListener(ILabelProviderListener arg0) {
    // Do nothing
  }
}
/**
 * This class provides the content for the table
 */
class PlayerContentProvider implements IStructuredContentProvider {
  /**
   * Gets the elements for the table
   * 
   * @param arg0
   *            the model
   * @return Object[]
   */
  public Object[] getElements(Object arg0) {
    // Returns all the players in the specified team
    return ((Team) arg0).getPlayers().toArray();
  }
  /**
   * Disposes any resources
   */
  public void dispose() {
    // We don"t create any resources, so we don"t dispose any
  }
  /**
   * Called when the input changes
   * 
   * @param arg0
   *            the parent viewer
   * @param arg1
   *            the old input
   * @param arg2
   *            the new input
   */
  public void inputChanged(Viewer arg0, Object arg1, Object arg2) {
    // Nothing to do
  }
}





Demonstrates the SWT.VIRTUAL style

//Send questions, comments, bug reports, etc. to the authors:
//Rob Warner (rwarner@interspatial.ru)
//Robert Harris (rbrt_harris@yahoo.ru)
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
/**
 * This class demonstrates the SWT.VIRTUAL style
 */
public class VirtualTable {
  private String[] items;
  /**
   * Runs the application
   */
  public void run() {
    // Create the data for the table
    items = new String[5000];
    for (int i = 0, n = items.length; i < n; i++) {
      items[i] = "I am item number " + i;
    }
    
    // Normal SWT stuff
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setText("Virtual Table");
    createContents(shell);
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
    display.dispose();
  }
  
  /**
   * Creates the shell"s contents
   * @param shell the shell
   */
  private void createContents(Shell shell) {
    shell.setLayout(new FillLayout());
    
    // Create a table and column
    final Table table = new Table(shell, SWT.VIRTUAL);
    table.setLinesVisible(true);
    table.setHeaderVisible(true);
    TableColumn tc = new TableColumn(table, SWT.NONE);
    tc.setText("Virtual Value");
    tc.setWidth(400);
    // Tell the table how many items it has
    table.setItemCount(items.length);
    
    // Provide the callback handler--this handler
    // is invoked when the table needs new rows
    table.addListener(SWT.SetData, new Listener() {
      public void handleEvent(Event event) {
        TableItem item = (TableItem) event.item;
        item.setText(items[table.indexOf(item)]);
      }
    });
  }
  /**
   * The application entry point
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    new VirtualTable().run();
  }
}





Detect a selection or check event in a table (SWT.CHECK)

/*
 * Table example snippet: detect a selection or check event in a table (SWT.CHECK)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class Snippet113 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    Table table = new Table(shell, SWT.CHECK | SWT.BORDER | SWT.V_SCROLL
        | SWT.H_SCROLL);
    for (int i = 0; i < 12; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText("Item " + i);
    }
    table.setSize(100, 100);
    table.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        String string = event.detail == SWT.CHECK ? "Checked"
            : "Selected";
        System.out.println(event.item + " " + string);
      }
    });
    shell.setSize(200, 200);
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Displays ASCII Codes

//Send questions, comments, bug reports, etc. to the authors:
//Rob Warner (rwarner@interspatial.ru)
//Robert Harris (rbrt_harris@yahoo.ru)
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
/**
 * Displays ASCII Codes
 */
public class AsciiTable {
  // The number of characters to show.
  private static final int MAX_CHARS = 128;
  // Names for each of the columns
  private static final String[] COLUMN_NAMES = { "Char", "Dec", "Hex", "Oct",
      "Bin", "Name"};
  // The names of the first 32 characters
  private static final String[] CHAR_NAMES = { "NUL", "SOH", "STX", "ETX", "EOT",
      "ENQ", "ACK", "BEL", "BS", "TAB", "LF", "VT", "FF", "CR", "SO", "SI",
      "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB",
      "ESC", "FS", "GS", "RS", "US", "Space"};
  // The font to use for displaying characters
  private Font font;
  // The background colors to use for the rows
  private Color[] colors = new Color[MAX_CHARS];
  /**
   * Runs the application
   */
  public void run() {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setText("ASCII Codes");
    createContents(shell);
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
    // Call dispose to dispose any resources created
    // we have created
    dispose();
    display.dispose();
  }
  /**
   * Disposes the resources created
   */
  private void dispose() {
    // We created this font; we must dispose it
    if (font != null) {
      font.dispose();
    }
    // We created the colors; we must dispose them
    for (int i = 0, n = colors.length; i < n; i++) {
      if (colors[i] != null) {
        colors[i].dispose();
      }
    }
  }
  /**
   * Creates the font
   */
  private void createFont() {
    // Create a font that will display the range
    // of characters. "Terminal" works well in
    // Windows
    font = new Font(Display.getCurrent(), "Terminal", 10, SWT.NORMAL);
  }
  /**
   * Creates the columns for the table
   * 
   * @param table the table
   * @return TableColumn[]
   */
  private TableColumn[] createColumns(Table table) {
    TableColumn[] columns = new TableColumn[COLUMN_NAMES.length];
    for (int i = 0, n = columns.length; i < n; i++) {
      // Create the TableColumn with right alignment
      columns[i] = new TableColumn(table, SWT.RIGHT);
      // This text will appear in the column header
      columns[i].setText(COLUMN_NAMES[i]);
    }
    return columns;
  }
  /**
   * Creates the window"s contents (the table)
   * 
   * @param composite the parent composite
   */
  private void createContents(Composite composite) {
    composite.setLayout(new FillLayout());
    // The system font will not display the lower 32
    // characters, so create one that will
    createFont();
    // Create a table with visible headers
    // and lines, and set the font that we
    // created
    Table table = new Table(composite, SWT.SINGLE | SWT.FULL_SELECTION);
    table.setHeaderVisible(true);
    table.setLinesVisible(true);
    table.setRedraw(false);
    table.setFont(font);
    // Create the columns
    TableColumn[] columns = createColumns(table);
    for (int i = 0; i < MAX_CHARS; i++) {
      // Create a background color for this row
      colors[i] = new Color(table.getDisplay(), 255 - i, 127 + i, i);
      // Create the row in the table by creating
      // a TableItem and setting text for each
      // column
      int c = 0;
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText(c++, String.valueOf((char) i));
      item.setText(c++, String.valueOf(i));
      item.setText(c++, Integer.toHexString(i).toUpperCase());
      item.setText(c++, Integer.toOctalString(i));
      item.setText(c++, Integer.toBinaryString(i));
      item.setText(c++, i < CHAR_NAMES.length ? CHAR_NAMES[i] : "");
      item.setBackground(colors[i]);
    }
    // Now that we"ve set the text into the columns,
    // we call pack() on each one to size it to the
    // contents.
    for (int i = 0, n = columns.length; i < n; i++) {
      columns[i].pack();
    }
    // Set redraw back to true so that the table
    // will paint appropriately
    table.setRedraw(true);
  }
  /**
   * The application entry point
   * 
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    new AsciiTable().run();
  }
}





Displays a table

//Send questions, comments, bug reports, etc. to the authors:
//Rob Warner (rwarner@interspatial.ru)
//Robert Harris (rbrt_harris@yahoo.ru)
import org.eclipse.swt.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
/**
 * Displays a table
 */
public class TableTest {
  public static void main(String[] args) {
    new TableTest().run();
  }
  public void run() {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    Table table = new Table(shell, SWT.MULTI | SWT.FULL_SELECTION);
    for (int i = 0; i < 5; i++) {
      TableColumn column = new TableColumn(table, SWT.NONE);
    }
    for (int i = 0; i < 10; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      for (int j = 0; j < 5; j++) {
        item.setText(j, "Row " + i + ", Column " + j);
      }
    }
    for (int i = 0, n = table.getColumnCount(); i < n; i++) {
      table.getColumn(i).pack();
    }
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
    display.dispose();
  }
}





Dropped data type depends on target item in table

/*
 * Dropped data type depends on target item in table
 * 
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import java.io.File;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class Snippet185 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    Label label1 = new Label(shell, SWT.BORDER);
    label1.setText("Drag Source");
    final Table table = new Table(shell, SWT.BORDER);
    for (int i = 0; i < 4; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      if (i % 2 == 0)
        item.setText("Drop a file");
      if (i % 2 == 1)
        item.setText("Drop text");
    }
    DragSource dragSource = new DragSource(label1, DND.DROP_COPY);
    dragSource.setTransfer(new Transfer[] { TextTransfer.getInstance(),
        FileTransfer.getInstance() });
    dragSource.addDragListener(new DragSourceAdapter() {
      public void dragSetData(DragSourceEvent event) {
        if (FileTransfer.getInstance().isSupportedType(event.dataType)) {
          File file = new File("temp");
          event.data = new String[] { file.getAbsolutePath() };
        }
        if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
          event.data = "once upon a time";
        }
      }
    });
    DropTarget dropTarget = new DropTarget(table, DND.DROP_COPY
        | DND.DROP_DEFAULT);
    dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance(),
        FileTransfer.getInstance() });
    dropTarget.addDropListener(new DropTargetAdapter() {
      FileTransfer fileTransfer = FileTransfer.getInstance();
      TextTransfer textTransfer = TextTransfer.getInstance();
      public void dragEnter(DropTargetEvent event) {
        if (event.detail == DND.DROP_DEFAULT)
          event.detail = DND.DROP_COPY;
      }
      public void dragOperationChanged(DropTargetEvent event) {
        if (event.detail == DND.DROP_DEFAULT)
          event.detail = DND.DROP_COPY;
      }
      public void dragOver(DropTargetEvent event) {
        event.detail = DND.DROP_NONE;
        TableItem item = (TableItem) event.item;
        if (item == null)
          return;
        int itemIndex = table.indexOf(item);
        if (itemIndex % 2 == 0) {
          int index = 0;
          while (index < event.dataTypes.length) {
            if (fileTransfer
                .isSupportedType(event.dataTypes[index]))
              break;
            index++;
          }
          if (index < event.dataTypes.length) {
            event.currentDataType = event.dataTypes[index];
            event.detail = DND.DROP_COPY;
            return;
          }
        } else {
          int index = 0;
          while (index < event.dataTypes.length) {
            if (textTransfer
                .isSupportedType(event.dataTypes[index]))
              break;
            index++;
          }
          if (index < event.dataTypes.length) {
            event.currentDataType = event.dataTypes[index];
            event.detail = DND.DROP_COPY;
            return;
          }
        }
      }
      public void drop(DropTargetEvent event) {
        TableItem item = (TableItem) event.item;
        if (item == null) {
          event.detail = DND.DROP_NONE;
          return;
        }
        if (fileTransfer.isSupportedType(event.currentDataType)) {
          String[] files = (String[]) event.data;
          if (files != null && files.length > 0) {
            item.setText(files[0]);
          }
        }
        if (textTransfer.isSupportedType(event.currentDataType)) {
          String text = (String) event.data;
          if (text != null) {
            item.setText(text);
          }
        }
      }
    });
    shell.setSize(300, 150);
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





edit a cell in a SWT table (in place, fancy)

/*
 * TableEditor example snippet: edit a cell in a table (in place, fancy)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
public class Snippet124 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    final Table table = new Table(shell, SWT.BORDER | SWT.MULTI);
    table.setLinesVisible(true);
    for (int i = 0; i < 3; i++) {
      TableColumn column = new TableColumn(table, SWT.NONE);
      column.setWidth(100);
    }
    for (int i = 0; i < 3; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText(new String[] { "" + i, "" + i, "" + i });
    }
    final TableEditor editor = new TableEditor(table);
    editor.horizontalAlignment = SWT.LEFT;
    editor.grabHorizontal = true;
    table.addListener(SWT.MouseDown, new Listener() {
      public void handleEvent(Event event) {
        Rectangle clientArea = table.getClientArea();
        Point pt = new Point(event.x, event.y);
        int index = table.getTopIndex();
        while (index < table.getItemCount()) {
          boolean visible = false;
          final TableItem item = table.getItem(index);
          for (int i = 0; i < table.getColumnCount(); i++) {
            Rectangle rect = item.getBounds(i);
            if (rect.contains(pt)) {
              final int column = i;
              final Text text = new Text(table, SWT.NONE);
              Listener textListener = new Listener() {
                public void handleEvent(final Event e) {
                  switch (e.type) {
                  case SWT.FocusOut:
                    item.setText(column, text.getText());
                    text.dispose();
                    break;
                  case SWT.Traverse:
                    switch (e.detail) {
                    case SWT.TRAVERSE_RETURN:
                      item
                          .setText(column, text
                              .getText());
                    // FALL THROUGH
                    case SWT.TRAVERSE_ESCAPE:
                      text.dispose();
                      e.doit = false;
                    }
                    break;
                  }
                }
              };
              text.addListener(SWT.FocusOut, textListener);
              text.addListener(SWT.Traverse, textListener);
              editor.setEditor(text, item, i);
              text.setText(item.getText(i));
              text.selectAll();
              text.setFocus();
              return;
            }
            if (!visible && rect.intersects(clientArea)) {
              visible = true;
            }
          }
          if (!visible)
            return;
          index++;
        }
      }
    });
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





edit the text of a SWT table item (in place)

/*
 * TableEditor example snippet: edit the text of a table item (in place)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
public class Snippet88 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    final Table table = new Table(shell, SWT.FULL_SELECTION
        | SWT.HIDE_SELECTION);
    TableColumn column1 = new TableColumn(table, SWT.NONE);
    TableColumn column2 = new TableColumn(table, SWT.NONE);
    for (int i = 0; i < 10; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText(new String[] { "item " + i, "edit this value" });
    }
    column1.pack();
    column2.pack();
    final TableEditor editor = new TableEditor(table);
    // The editor must have the same size as the cell and must
    // not be any smaller than 50 pixels.
    editor.horizontalAlignment = SWT.LEFT;
    editor.grabHorizontal = true;
    editor.minimumWidth = 50;
    // editing the second column
    final int EDITABLECOLUMN = 1;
    table.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        // Clean up any previous editor control
        Control oldEditor = editor.getEditor();
        if (oldEditor != null)
          oldEditor.dispose();
        // Identify the selected row
        TableItem item = (TableItem) e.item;
        if (item == null)
          return;
        // The control that will be the editor must be a child of the
        // Table
        Text newEditor = new Text(table, SWT.NONE);
        newEditor.setText(item.getText(EDITABLECOLUMN));
        newEditor.addModifyListener(new ModifyListener() {
          public void modifyText(ModifyEvent me) {
            Text text = (Text) editor.getEditor();
            editor.getItem()
                .setText(EDITABLECOLUMN, text.getText());
          }
        });
        newEditor.selectAll();
        newEditor.setFocus();
        editor.setEditor(newEditor, item, EDITABLECOLUMN);
      }
    });
    shell.setSize(300, 300);
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





File Browser Demo

/******************************************************************************
 * All Right Reserved. 
 * Copyright (c) 1998, 2004 Jackwind Li Guojie
 * 
 * Created on Mar 3, 2004 2:09:15 PM by JACK
 * $Id$
 * 
 *****************************************************************************/

import java.io.File;
import java.util.Date;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class FileBrowserDemo {
  Display display = new Display();
  Shell shell = new Shell(display);
  Table table;
  
  File rootDir;
  
  Image iconFolder = new Image(shell.getDisplay(), "jexp.gif");
  Image iconFile = new Image(shell.getDisplay(), "jexp.gif");
  
  public FileBrowserDemo() {
    GridLayout gridLayout = new GridLayout();
    shell.setLayout(gridLayout);
    
    // Tool bar. 
    
    // Table. 
    table = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
    //table.setLinesVisible(true);
    table.setHeaderVisible(true);
    
    TableColumn tcFileName = new TableColumn(table, SWT.LEFT);
    tcFileName.setText("File name");
    //tcFileName.setImage(new Image(shell.getDisplay(), "jexp.gif"));
    
    TableColumn tcFileSize = new TableColumn(table, SWT.RIGHT);
    tcFileSize.setText("Size");
    
    TableColumn tcDateModified = new TableColumn(table, SWT.RIGHT);
    tcDateModified.setText("Date Modified");
    
    tcFileName.setWidth(200);
    tcFileSize.setWidth(80);
    tcDateModified.setWidth(180);
    
    TableItem item = new TableItem(table, SWT.NULL);
    item.setText(new String[]{"Name", "Size"});
    
    table.setLayoutData(new GridData(GridData.FILL_BOTH));
    table.pack();
    
    shell.pack();
    shell.open();
    
    setRootDirectory(new File("."));
    //textUser.forceFocus();
    // Set up the event loop.
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        // If no more entries in event queue
        display.sleep();
      }
    }
    display.dispose();
  }
  
  private void setRootDirectory(File dir) {
    this.rootDir = dir;
    if(! (dir.exists() && dir.isDirectory()))
      throw new IllegalArgumentException("Invalid directory. ");
    
    // Remove all existing items. 
    table.removeAll();
    
    File[] files = dir.listFiles();
    for(int i=0; files != null && i < files.length; i++) {
      File file = files[i];
      TableItem item = new TableItem(table, SWT.NULL);
      
      item.setBackground(i % 2 == 0 ? shell.getDisplay().getSystemColor(SWT.COLOR_WHITE) :
                      shell.getDisplay().getSystemColor(SWT.COLOR_GRAY));
      
      item.setText(0, file.getName());
      item.setText(2, new Date(file.lastModified()).toString());
      
      
      if(file.isDirectory()) {
        item.setImage(0, iconFolder);
      }else{
        int lastDot = file.getName().lastIndexOf(".");
        if(lastDot >= 0 && lastDot < file.getName().length()) {
          item.setImage(0, getIcon(file.getName().substring(lastDot+1)));
        }
        long kbytes = file.length() / 1024;
        if(kbytes == 0)
          kbytes = 1;
        item.setText(1, kbytes + " KB");
      }
    }
    
  }
  
  private ImageRegistry imageRegistry;
  
  /**
   * Returns the icon for the file type with the specified extension. 
   * @param extension
   * @return
   */
  public Image getIcon(String extension) {
    if(imageRegistry == null)
      imageRegistry = new ImageRegistry();
    Image image = imageRegistry.get(extension);
    if(image != null)
      return image;
    
    Program program = Program.findProgram(extension);
    if(program != null) {
      image = new Image(shell.getDisplay(), program.getImageData());
      imageRegistry.put(extension, image);
    }else{
      image = iconFile;
    }
    
    return image;
  }
  public static void main(String[] args) {
    new FileBrowserDemo();
  }
}





File Browser JFace

/******************************************************************************
 * All Right Reserved. 
 * Copyright (c) 1998, 2004 Jackwind Li Guojie
 * 
 * Created on Mar 12, 2004 11:51:42 PM by JACK
 * $Id$
 * 
 *****************************************************************************/

import java.io.File;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
public class FileBrowserJFace {
  Display display = new Display();
  Shell shell = new Shell(display);
  
  File rootDir;
  
  TreeViewer treeViewer;
  public FileBrowserJFace() {
    Action actionSetRootDir = new Action("Set Root Dir") {
      public void run() {
        DirectoryDialog dialog = new DirectoryDialog(shell);
        String path = dialog.open();
        if (path != null) {
          treeViewer.setInput(new File(path));
        }
      }
    };
    
    final ViewerFilter directoryFilter = new ViewerFilter() {
      public boolean select(
        Viewer viewer,
        Object parentElement,
        Object element) {
        return ((File)element).isDirectory();
      }
    };
    
    Action actionShowDirectoriesOnly = new Action("Show directories only") {
      public void run() {
        if(! isChecked())
          treeViewer.removeFilter(directoryFilter);
        else
          treeViewer.addFilter(directoryFilter);
      }
    };
    actionShowDirectoriesOnly.setChecked(false);
    Action actionDeleteFile = new Action("Delete the selected file") {
      public void run() {
        IStructuredSelection selection = (IStructuredSelection)treeViewer.getSelection();
        File file = (File)selection.getFirstElement();
        if(file == null) {
          System.out.println("Please select a file first.");
          return;
        }
        
        MessageBox messageBox = new MessageBox(shell, SWT.YES | SWT.NO);
        messageBox.setMessage("Are you sure to delete file: " + file.getName() + "?");
        if(messageBox.open() == SWT.YES) {
          File parentFile = file.getParentFile();
          if(file.delete()) {
            System.out.println("File has been deleted. ");
            // Notifies the viewer for update. 
            treeViewer.refresh(parentFile, false);
          }else{
            System.out.println("Unable to delete file.");
          }
        }
          
      }
    };
    ToolBar toolBar = new ToolBar(shell, SWT.FLAT);
    ToolBarManager manager = new ToolBarManager(toolBar);
    manager.add(actionSetRootDir);
    manager.add(actionShowDirectoriesOnly);
    manager.add(actionDeleteFile);
    manager.update(true);
    
  
    shell.setLayout(new GridLayout());
    treeViewer = new TreeViewer(shell, SWT.BORDER);
    treeViewer.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
    // Sets the content provider.
    treeViewer.setContentProvider(new ITreeContentProvider() {
      public Object[] getChildren(Object parentElement) {
        File[] files = ((File)parentElement).listFiles();
        if(files == null)
          return new Object[0];
        return files;
      }
      public Object getParent(Object element) {
        return ((File)element).getParentFile();
      }
      public boolean hasChildren(Object element) {
        File file = (File)element;
        File[] files = file.listFiles();
        if(files == null || files.length == 0)
          return false;
        return true;
      }
      public Object[] getElements(Object inputElement) {
        File[] files = ((File)inputElement).listFiles();
        if(files == null)
          return new Object[0];
        return files;
      }
      public void dispose() {
      }
      public void inputChanged(
        Viewer viewer,
        Object oldInput,
        Object newInput) {
        shell.setText("Now browsing: " + newInput);
      }
    });
    
    // Sets the label provider. 
    treeViewer.setLabelProvider(new LabelProvider() {
      public Image getImage(Object element) {
        return getIcon((File)element);
      }
      public String getText(Object element) {
        return ((File)element).getName();
      }
    });
    
    // Sorts the tree. 
    treeViewer.setSorter(new ViewerSorter() {
      public int category(Object element) {
        File file = (File)element;
        if(file.isDirectory())
          return 0;
        else
          return 1;
      }
    });
    
    
    treeViewer.setInput(new File("C:/"));
    
    shell.setSize(400, 260);
    shell.open();
    //textUser.forceFocus();
    // Set up the event loop.
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        // If no more entries in event queue
        display.sleep();
      }
    }
    display.dispose();
  }
  /**
   * Renames a file.
   * 
   * @param file
   * @param newName
   * @return the after after being renamed or <code>null</code> if renaming
   *         fails.
   */
  private File renameFile(File file, String newName) {
    File dest = new File(file.getParentFile(), newName);
    if (file.renameTo(dest)) {
      return dest;
    } else {
      return null;
    }
  }

  private ImageRegistry imageRegistry;
  Image iconFolder = new Image(shell.getDisplay(), "jexp.gif");
  Image iconFile = new Image(shell.getDisplay(), "jexp.gif");
  /**
   * Returns an icon representing the specified file.
   * 
   * @param file
   * @return
   */
  private Image getIcon(File file) {
    if (file.isDirectory())
      return iconFolder;
    int lastDotPos = file.getName().indexOf(".");
    if (lastDotPos == -1)
      return iconFile;
    Image image = getIcon(file.getName().substring(lastDotPos + 1));
    return image == null ? iconFile : image;
  }
  /**
   * Returns the icon for the file type with the specified extension.
   * 
   * @param extension
   * @return
   */
  private Image getIcon(String extension) {
    if (imageRegistry == null)
      imageRegistry = new ImageRegistry();
    Image image = imageRegistry.get(extension);
    if (image != null)
      return image;
    Program program = Program.findProgram(extension);
    ImageData imageData = (program == null ? null : program.getImageData());
    if (imageData != null) {
      image = new Image(shell.getDisplay(), imageData);
      imageRegistry.put(extension, image);
    } else {
      image = iconFile;
    }
    return image;
  }
  
  
  
  public static void main(String[] args) {
    new FileBrowserJFace();
  }
}





File Browser Sample

/*******************************************************************************
 * All Right Reserved. Copyright (c) 1998, 2004 Jackwind Li Guojie
 * 
 * Created on Mar 9, 2004 7:07:16 PM by JACK $Id$
 *  
 ******************************************************************************/
import java.io.File;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TreeEditor;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TreeEvent;
import org.eclipse.swt.events.TreeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
public class FileBrowserSample {
  Display display = new Display();
  Shell shell = new Shell(display);
  Tree tree;
  File rootDir;
  public FileBrowserSample() {
    Action actionSetRootDir = new Action("Set Root Dir") {
      public void run() {
        DirectoryDialog dialog = new DirectoryDialog(shell);
        String path = dialog.open();
        if (path != null) {
          setRootDir(new File(path));
        }
      }
    };

    ToolBar toolBar = new ToolBar(shell, SWT.FLAT);
    ToolBarManager manager = new ToolBarManager(toolBar);
    manager.add(actionSetRootDir);
    manager.update(true);
    shell.setLayout(new GridLayout());
    tree = new Tree(shell, SWT.BORDER);
    tree.setLayoutData(new GridData(GridData.FILL_BOTH));
    setRootDir(new File("C:/"));
    tree.addTreeListener(new TreeListener() {
      public void treeCollapsed(TreeEvent e) {
      }
      public void treeExpanded(TreeEvent e) {
        TreeItem item = (TreeItem) e.item;
        TreeItem[] children = item.getItems();
        for (int i = 0; i < children.length; i++)
          if (children[i].getData() == null)
            children[i].dispose();
          else // Child files already added to the tree.
            return;
        File[] files = ((File) item.getData()).listFiles();
        for (int i = 0; files != null && i < files.length; i++)
          addFileToTree(item, files[i]);
      }
    });
    tree.addSelectionListener(new SelectionListener() {
      public void widgetSelected(SelectionEvent e) {
      }
      // Gets called when a tree item is double-clicked.
      public void widgetDefaultSelected(SelectionEvent e) {
        TreeItem item = (TreeItem) e.item;
        File file = (File) item.getData();
        if (Program.launch(file.getAbsolutePath())) {
          System.out.println("File has been launched: " + file);
        } else {
          System.out.println("Unable to launch file: " + file);
        }
      }
    });
    final TreeEditor editor = new TreeEditor(tree);
    tree.addListener(SWT.MouseDown, new Listener() {
      public void handleEvent(Event event) {
        // Locate the cell position.
        Point point = new Point(event.x, event.y);
        final TreeItem item = tree.getItem(point);
        if (item == null)
          return;
        
        final Text text = new Text(tree, SWT.NONE);
        text.setText(item.getText());
        text.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_YELLOW));
        editor.horizontalAlignment = SWT.LEFT;
        editor.grabHorizontal = true;
        editor.setEditor(text, item);
        Listener textListener = new Listener() {
          public void handleEvent(final Event e) {
            switch (e.type) {
              case SWT.FocusOut :
                File renamed =
                  renameFile(
                    (File) item.getData(),
                    text.getText());
                if (renamed != null) {
                  item.setText(text.getText());
                  item.setData(renamed);
                }
                text.dispose();
                break;
              case SWT.Traverse :
                switch (e.detail) {
                  case SWT.TRAVERSE_RETURN :
                    renamed =
                      renameFile(
                        (File) item.getData(),
                        text.getText());
                    if (renamed != null) {
                      item.setText(text.getText());
                      item.setData(renamed);
                    }
                    //FALL THROUGH
                  case SWT.TRAVERSE_ESCAPE :
                    text.dispose();
                    e.doit = false;
                }
                break;
            }
          }
        };
        text.addListener(SWT.FocusOut, textListener);
        text.addListener(SWT.Traverse, textListener);
        text.setFocus();
      }
    });
    shell.setSize(400, 260);
    shell.open();
    //textUser.forceFocus();
    // Set up the event loop.
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        // If no more entries in event queue
        display.sleep();
      }
    }
    display.dispose();
  }
  /**
   * Renames a file.
   * 
   * @param file
   * @param newName
   * @return the after after being renamed or <code>null</code> if renaming
   *         fails.
   */
  private File renameFile(File file, String newName) {
    File dest = new File(file.getParentFile(), newName);
    if (file.renameTo(dest)) {
      return dest;
    } else {
      return null;
    }
  }
  /**
   * Sets the root directory to browse from.
   * 
   * @param root
   */
  private void setRootDir(File root) {
    // validates the root first. 
    if( (!root.isDirectory()) || (!root.exists()))
      throw new IllegalArgumentException("Invalid root: " + root);
    
    this.rootDir = root;
    shell.setText("Now browsing: " + root.getAbsolutePath());
    // Remove all the items in the tree.
    if (tree.getItemCount() > 0) {
      TreeItem[] items = tree.getItems();
      for (int i = 0; i < items.length; i++) {
        items[i].dispose();
        // Dispose itself and all of its descendants.
      }
    }
    // Adds files under the root to the tree. 
    File[] files = root.listFiles();
    for(int i=0; files != null && i < files.length; i++)
      addFileToTree(tree, files[i]);
  }
  /**
   * Adds the given file to the tree.
   * 
   * @param parent
   * @param file
   */
  private void addFileToTree(Object parent, File file) {
    TreeItem item = null;
    if (parent instanceof Tree)
      item = new TreeItem((Tree) parent, SWT.NULL);
    else if (parent instanceof TreeItem)
      item = new TreeItem((TreeItem) parent, SWT.NULL);
    else
      throw new IllegalArgumentException(
        "parent should be a tree or a tree item: " + parent);
    item.setText(file.getName());
    item.setImage(getIcon(file));
    item.setData(file);
    if (file.isDirectory()) {
      //      // recursively adds all the children of this file.
      //      File[] files = file.listFiles();
      //      for(int i=0; i<files.length; i++)
      //        buildTree(item, files[i]);
      if (file.list() != null && file.list().length > 0)
        new TreeItem(item, SWT.NULL);
    }
  }
  private ImageRegistry imageRegistry;
  Image iconFolder = new Image(shell.getDisplay(), "jexp.gif");
  Image iconFile = new Image(shell.getDisplay(), "jexp.gif");
  /**
   * Returns an icon representing the specified file.
   * 
   * @param file
   * @return
   */
  private Image getIcon(File file) {
    if (file.isDirectory())
      return iconFolder;
    int lastDotPos = file.getName().indexOf(".");
    if (lastDotPos == -1)
      return iconFile;
    Image image = getIcon(file.getName().substring(lastDotPos + 1));
    return image == null ? iconFile : image;
  }
  /**
   * Returns the icon for the file type with the specified extension.
   * 
   * @param extension
   * @return
   */
  private Image getIcon(String extension) {
    if (imageRegistry == null)
      imageRegistry = new ImageRegistry();
    Image image = imageRegistry.get(extension);
    if (image != null)
      return image;
    Program program = Program.findProgram(extension);
    ImageData imageData = (program == null ? null : program.getImageData());
    if (imageData != null) {
      image = new Image(shell.getDisplay(), imageData);
      imageRegistry.put(extension, image);
    } else {
      image = iconFile;
    }
    return image;
  }
  public static void main(String[] args) {
    new FileBrowserSample();
  }
}





Find a SWT table cell from mouse down (works for any table style)

/*
 * Table example snippet: find a table cell from mouse down (works for any table style)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class Snippet110 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    final Table table = new Table(shell, SWT.BORDER | SWT.V_SCROLL);
    table.setHeaderVisible(true);
    table.setLinesVisible(true);
    final int rowCount = 64, columnCount = 4;
    for (int i = 0; i < columnCount; i++) {
      TableColumn column = new TableColumn(table, SWT.NONE);
      column.setText("Column " + i);
    }
    for (int i = 0; i < rowCount; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      for (int j = 0; j < columnCount; j++) {
        item.setText(j, "Item " + i + "-" + j);
      }
    }
    for (int i = 0; i < columnCount; i++) {
      table.getColumn(i).pack();
    }
    Point size = table.ruputeSize(SWT.DEFAULT, 200);
    table.setSize(size);
    shell.pack();
    table.addListener(SWT.MouseDown, new Listener() {
      public void handleEvent(Event event) {
        Rectangle clientArea = table.getClientArea();
        Point pt = new Point(event.x, event.y);
        int index = table.getTopIndex();
        while (index < table.getItemCount()) {
          boolean visible = false;
          TableItem item = table.getItem(index);
          for (int i = 0; i < columnCount; i++) {
            Rectangle rect = item.getBounds(i);
            if (rect.contains(pt)) {
              System.out.println("Item " + index + "-" + i);
            }
            if (!visible && rect.intersects(clientArea)) {
              visible = true;
            }
          }
          if (!visible)
            return;
          index++;
        }
      }
    });
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Find a table cell from mouse down (SWT.FULL_SELECTION)

/*
 * Table example snippet: find a table cell from mouse down (SWT.FULL_SELECTION)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class Snippet3 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    final Table table = new Table(shell, SWT.BORDER | SWT.V_SCROLL
        | SWT.FULL_SELECTION);
    table.setHeaderVisible(true);
    table.setLinesVisible(true);
    final int rowCount = 64, columnCount = 4;
    for (int i = 0; i < columnCount; i++) {
      TableColumn column = new TableColumn(table, SWT.NONE);
      column.setText("Column " + i);
    }
    for (int i = 0; i < rowCount; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      for (int j = 0; j < columnCount; j++) {
        item.setText(j, "Item " + i + "-" + j);
      }
    }
    for (int i = 0; i < columnCount; i++) {
      table.getColumn(i).pack();
    }
    Point size = table.ruputeSize(SWT.DEFAULT, 200);
    table.setSize(size);
    shell.pack();
    table.addListener(SWT.MouseDown, new Listener() {
      public void handleEvent(Event event) {
        Point pt = new Point(event.x, event.y);
        TableItem item = table.getItem(pt);
        if (item == null)
          return;
        for (int i = 0; i < columnCount; i++) {
          Rectangle rect = item.getBounds(i);
          if (rect.contains(pt)) {
            int index = table.indexOf(item);
            System.out.println("Item " + index + "-" + i);
          }
        }
      }
    });
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





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 Factory

/*
 *  This snippet show 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 Factory
 *  
 *  Comparator implemented: INT_COMPARATOR, STRING_COMPARATOR, DATE_COMPARATOR, DOUBLE_COMPARATOR, HOUR_COMPARATOR  
 *  Example: column.addListener(SWT.Selection, SortListenerFactory.getListener(SortListenerFactory.STRING_COMPARATOR));
 *  
 *  Gianluigi Davassi 
 *  Feel free to contact me: davassi (at) yahoo.it
 *  
 * */
/*  Copyright (C) 2004 by Gianluigi Davassi www.omega-dream.ru
 
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.
 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.
 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 Author: Gianluigi Davassi
 davassi (at) yahoo.it
 www.omega-dream.ru
 
 */

package org.omegadream;
import java.text.Collator;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.ruparator;
import java.util.Date;
import java.util.Locale;
import java.util.Random;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class TableSortListenerFactory {
    private static final int MAX_ELEMENTS = 1000;
    private Display display;
    private Shell shell;
    
    private Table table;
    private TableColumn intColumn,stringColumn,dateColumn,doubleColumn,hourColumn;  
    
    private Random ran = new Random();
    
    public TableSortListenerFactory() {
        display = new Display();
        shell = new Shell(display);
        shell.setSize(640, 480);
        
        shell.setText("A Table Sorter Example. Click on column header to order it!");
        shell.setLayout(new FillLayout());
        table = new Table(shell, SWT.HIDE_SELECTION|SWT.SINGLE|SWT.FULL_SELECTION|SWT.BORDER);
        table.setHeaderVisible(true);
        table.setLinesVisible(true);
        intColumn = new TableColumn(table, SWT.CENTER);
        intColumn.setText("Number Column");
        intColumn.setWidth(120);
        intColumn.addListener(SWT.Selection, SortListenerFactory.getListener(SortListenerFactory.INT_COMPARATOR));
        
        stringColumn = new TableColumn(table, SWT.CENTER);
        stringColumn.setText("String Column");
        stringColumn.setWidth(120);
        stringColumn.addListener(SWT.Selection, SortListenerFactory.getListener(SortListenerFactory.STRING_COMPARATOR));
        
        dateColumn = new TableColumn(table, SWT.CENTER);
        dateColumn.setText("Date Column");
        dateColumn.setWidth(120);
        dateColumn.addListener(SWT.Selection, SortListenerFactory.getListener(SortListenerFactory.DATE_COMPARATOR));
        
        doubleColumn = new TableColumn(table, SWT.CENTER);
        doubleColumn.setText("Double Column");
        doubleColumn.setWidth(120);
        doubleColumn.addListener(SWT.Selection, SortListenerFactory.getListener(SortListenerFactory.DOUBLE_COMPARATOR));
        
        hourColumn = new TableColumn(table, SWT.CENTER);
        hourColumn.setText("Hour Column");
        hourColumn.setWidth(120);
        hourColumn.addListener(SWT.Selection, SortListenerFactory.getListener(SortListenerFactory.HOUR_COMPARATOR));
     
        // let"s populate the table with random data!
        for (int i = 0; i< MAX_ELEMENTS ; i++)
        {
            String int_value = String.valueOf(ran.nextInt(1000000));
            
            String string_value = randomstring(4,16);
            
            String date_value = "" + ran.nextInt(31) + "/" + ran.nextInt(12) + "/" + ran.nextInt(2000); // dd-mm-aaaa
            
            String double_value = String.valueOf(ran.nextDouble());
            
            String hour_value = "" + ran.nextInt(24) + ":" + ran.nextInt(60) + ":" + ran.nextInt(60); // hh:mm:SS
            
            // ok now store it in the table
            TableItem item = new TableItem(table, SWT.NONE);
            item.setText(new String[] { int_value, string_value, date_value, double_value, hour_value });
        }
      
        shell.open();
        while (!shell.isDisposed()) {
          if (!display.readAndDispatch())
            display.sleep();
        }
        display.dispose();
    }
    
    
    public static void main(String[] args)
    {
        new TableSortListenerFactory();
    }
    
    private int rand(int lo, int hi)
    {
            int n = hi - lo + 1;
            int i = ran.nextInt() % n;
            if (i < 0)
                    i = -i;
            return lo + i;
    }
    private String randomstring(int lo, int hi)
    {
            int n = rand(lo, hi);
            byte b[] = new byte[n];
            for (int i = 0; i < n; i++)
                    b[i] = (byte)rand("a", "z");
            return new String(b, 0);
    }
    
}
// this is the ListenerFactory implementation
class SortListenerFactory implements Listener
{
    private Comparator currentComparator = null;
    
    private Collator col = Collator.getInstance(Locale.getDefault());
    
    public static final int INT_COMPARATOR    = 0;
    public static final int STRING_COMPARATOR = 1;
    public static final int DATE_COMPARATOR   = 2;
    public static final int DOUBLE_COMPARATOR = 3;
    public static final int HOUR_COMPARATOR   = 4;
    
    private SortListenerFactory(int _comp)
    {
        switch (_comp) 
        {
        case INT_COMPARATOR:
            currentComparator = intComparator;
            break;
        case STRING_COMPARATOR:
            currentComparator = strComparator;
            break;
        case DATE_COMPARATOR:
            currentComparator = dateComparator;
            break;
            
        case DOUBLE_COMPARATOR:
            currentComparator = doubleComparator;
            break;
            
        case HOUR_COMPARATOR:
            currentComparator = hourComparator;
            break;
        default:
            currentComparator = strComparator;
        }
    }
    
    public static Listener getListener(int _comp)
    {
        return new SortListenerFactory(_comp);
    }
    
    private int colIndex = 0;
    private int updown   = 1;
          
    // Integer Comparator
    private Comparator intComparator = new Comparator()
    {
        public int compare(Object arg0, Object arg1) {
            TableItem t1 = (TableItem)arg0;
            TableItem t2 = (TableItem)arg1;
            int v1 = Integer.parseInt(t1.getText(colIndex));
            int v2 = Integer.parseInt(t2.getText(colIndex));
            if (v1<v2) return 1*updown;
            if (v1>v2) return -1*updown;
            return 0;
        }    
    };
         
    // String Comparator
    private Comparator strComparator = new Comparator()
    {
        public int compare(Object arg0, Object arg1) {
            TableItem t1 = (TableItem)arg0;
            TableItem t2 = (TableItem)arg1;
            String v1 = (t1.getText(colIndex));
            String v2 = (t2.getText(colIndex));
            return (col.rupare(v1,v2))*updown;
        }    
    };
    
    // Double Comparator
    private Comparator doubleComparator = new Comparator()
    {
        public int compare(Object arg0, Object arg1) {
            
            TableItem t1 = (TableItem)arg0;
            TableItem t2 = (TableItem)arg1;
            
            double v1 = Double.parseDouble(t1.getText(colIndex));
            double v2 = Double.parseDouble(t2.getText(colIndex));
            
            if (v1<v2) return 1*updown;
            if (v1>v2) return -1*updown;
            
            return 0;
        }    
    };
    
    // Hour Comparator (hh:mm:ss)
    private Comparator hourComparator = new Comparator()
    {
        public int compare(Object arg0, Object arg1) {
            
            TableItem t1 = (TableItem)arg0;
            TableItem t2 = (TableItem)arg1;
            
            String v1 = (t1.getText(colIndex)).trim();
            String v2 = (t2.getText(colIndex)).trim();
            
            DateFormat df = new SimpleDateFormat("hh:mm:ss");
           
            Date d1 = null; Date d2 = null;
            
            try {                
                d1 = df.parse(v1);
            } catch (ParseException e) 
            { 
                System.out.println("[WARNING] v1 " + v1);
                try { d1 = df.parse("01:01:01"); } catch (ParseException e1) {}
            }
            
            try {               
                d2 = df.parse(v2);
            } catch (ParseException e) 
            { 
                System.out.println("[WARNING] v2 " + v2);
                try { d2 = df.parse("01:01:01"); } catch (ParseException e1) {}
            }
            if (d1.equals(d2))
                return 0;
            return updown*(d1.before(d2) ? 1 : -1);
        }    
    };
    
    private Comparator dateComparator = new Comparator()
    {
        public int compare(Object arg0, Object arg1) 
        {    
            TableItem t1 = (TableItem)arg0;
            TableItem t2 = (TableItem)arg1;
            
            String v1 = (t1.getText(colIndex)).trim();
            String v2 = (t2.getText(colIndex)).trim();
            v1.replaceAll("-", "/");
            v2.replaceAll("-", "/");
            
            DateFormat df_europe = new SimpleDateFormat("dd/MM/yyyy");
            DateFormat df_usa = new SimpleDateFormat("yyyy/MM/dd");
            DateFormat df = df_europe;
            
            Date d1 = null; Date d2 = null;
            
            try {
                d1 = df.parse(v1);
            } catch (ParseException e) 
            { 
               //System.out.println("[WARNING] v1 " + v1);
                d1 = new Date("01/01/1900");
            }
            
            try {               
                d2 = df.parse(v2);
            } catch (ParseException e) 
            { 
                d2 = new Date("01/01/1900");
            }
            if (d1.equals(d2))
                return 0;
            return updown*(d1.before(d2) ? 1 : -1);
        }    
    };
        
    public void handleEvent(Event e) {
        
        updown = (updown == 1 ? -1 : 1);
        
        TableColumn currentColumn = (TableColumn)e.widget;
        Table table = currentColumn.getParent();
    
        colIndex = searchColumnIndex(currentColumn);
        
        table.setRedraw(false);
        
        TableItem[] items = table.getItems();
       
        Arrays.sort(items,currentComparator);
        
        table.setItemCount(items.length);
        
        for (int i = 0;i<items.length;i++)
        {   
            TableItem item = new TableItem(table,SWT.NONE,i);
            item.setText(getData(items[i]));
            items[i].dispose();
        }
        
        table.setRedraw(true);     
    }
    
    private String[] getData(TableItem t)
    {
        Table table = t.getParent();
        
        int colCount = table.getColumnCount();
        String [] s = new String[colCount];
        
        for (int i = 0;i<colCount;i++)
            s[i] = t.getText(i);
                
        return s;
        
    }
    
    private int searchColumnIndex(TableColumn currentColumn)
    {
        Table table = currentColumn.getParent();
        
        int in = 0;
        
        for (int i = 0;i<table.getColumnCount();i++)
            if (table.getColumn(i) == currentColumn)
                in = i;
        
        return in;
    }
}





Insert a SWT table column (at an index)

/*
 * Table example snippet: insert a table column (at an index)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class Snippet106 {
public static void main (String [] args) {
  Display display = new Display ();
  Shell shell = new Shell (display);
  shell.setLayout (new RowLayout (SWT.VERTICAL));
  final Table table = new Table (shell, SWT.BORDER | SWT.MULTI);
  table.setHeaderVisible (true);
  for (int i=0; i<4; i++) {
    TableColumn column = new TableColumn (table, SWT.NONE);
    column.setText ("Column " + i);
  }
  final TableColumn [] columns = table.getColumns ();
  for (int i=0; i<12; i++) {
    TableItem item = new TableItem (table, SWT.NONE);
    for (int j=0; j<columns.length; j++) {
      item.setText (j, "Item " + i);
    }
  }
  for (int i=0; i<columns.length; i++) columns [i].pack ();
  Button button = new Button (shell, SWT.PUSH);
  final int index = 1;
  button.setText ("Insert Column " + index + "a");
  button.addListener (SWT.Selection, new Listener () {
    public void handleEvent (Event e) {
      TableColumn column = new TableColumn (table, SWT.NONE, index);
      column.setText ("Column " + index + "a");
      TableItem [] items = table.getItems ();
      for (int i=0; i<items.length; i++) {
        items [i].setText (index, "Item " + i + "a");
      }
      column.pack ();
    }
  });
  shell.pack ();
  shell.open ();
  while (!shell.isDisposed ()) {
    if (!display.readAndDispatch ()) display.sleep ();
  }
  display.dispose ();
}
}





Insert a SWT table item (at an index)

/*
 * Table example snippet: insert a table item (at an index)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class Snippet101 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    Table table = new Table(shell, SWT.BORDER | SWT.MULTI);
    table.setSize(200, 200);
    for (int i = 0; i < 12; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText("Item " + i);
    }
    TableItem item = new TableItem(table, SWT.NONE, 1);
    item.setText("*** New Item " + table.indexOf(item) + " ***");
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





navigate a SWT table cells with arrow keys

/*
 * TableCursor example snippet: navigate a table cells with arrow keys. 
 * Edit when user hits Return key.  Exit edit mode by hitting Escape (cancels edit)
 * or Return (applies edit to table).
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ControlEditor;
import org.eclipse.swt.custom.TableCursor;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
public class Snippet96 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new GridLayout());
    // create a a table with 3 columns and fill with data
    final Table table = new Table(shell, SWT.BORDER | SWT.MULTI
        | SWT.FULL_SELECTION);
    table.setLayoutData(new GridData(GridData.FILL_BOTH));
    TableColumn column1 = new TableColumn(table, SWT.NONE);
    TableColumn column2 = new TableColumn(table, SWT.NONE);
    TableColumn column3 = new TableColumn(table, SWT.NONE);
    for (int i = 0; i < 100; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText(new String[] { "cell " + i + " 0", "cell " + i + " 1",
          "cell " + i + " 2" });
    }
    column1.pack();
    column2.pack();
    column3.pack();
    // create a TableCursor to navigate around the table
    final TableCursor cursor = new TableCursor(table, SWT.NONE);
    // create an editor to edit the cell when the user hits "ENTER"
    // while over a cell in the table
    final ControlEditor editor = new ControlEditor(cursor);
    editor.grabHorizontal = true;
    editor.grabVertical = true;
    cursor.addSelectionListener(new SelectionAdapter() {
      // when the TableEditor is over a cell, select the corresponding row
      // in
      // the table
      public void widgetSelected(SelectionEvent e) {
        table.setSelection(new TableItem[] { cursor.getRow() });
      }
      // when the user hits "ENTER" in the TableCursor, pop up a text
      // editor so that
      // they can change the text of the cell
      public void widgetDefaultSelected(SelectionEvent e) {
        final Text text = new Text(cursor, SWT.NONE);
        TableItem row = cursor.getRow();
        int column = cursor.getColumn();
        text.setText(row.getText(column));
        text.addKeyListener(new KeyAdapter() {
          public void keyPressed(KeyEvent e) {
            // close the text editor and copy the data over
            // when the user hits "ENTER"
            if (e.character == SWT.CR) {
              TableItem row = cursor.getRow();
              int column = cursor.getColumn();
              row.setText(column, text.getText());
              text.dispose();
            }
            // close the text editor when the user hits "ESC"
            if (e.character == SWT.ESC) {
              text.dispose();
            }
          }
        });
        editor.setEditor(text);
        text.setFocus();
      }
    });
    // Hide the TableCursor when the user hits the "CTRL" or "SHIFT" key.
    // This alows the user to select multiple items in the table.
    cursor.addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        if (e.keyCode == SWT.CTRL || e.keyCode == SWT.SHIFT
            || (e.stateMask & SWT.CONTROL) != 0
            || (e.stateMask & SWT.SHIFT) != 0) {
          cursor.setVisible(false);
        }
      }
    });
    // Show the TableCursor when the user releases the "SHIFT" or "CTRL"
    // key.
    // This signals the end of the multiple selection task.
    table.addKeyListener(new KeyAdapter() {
      public void keyReleased(KeyEvent e) {
        if (e.keyCode == SWT.CONTROL && (e.stateMask & SWT.SHIFT) != 0)
          return;
        if (e.keyCode == SWT.SHIFT && (e.stateMask & SWT.CONTROL) != 0)
          return;
        if (e.keyCode != SWT.CONTROL
            && (e.stateMask & SWT.CONTROL) != 0)
          return;
        if (e.keyCode != SWT.SHIFT && (e.stateMask & SWT.SHIFT) != 0)
          return;
        TableItem[] selection = table.getSelection();
        TableItem row = (selection.length == 0) ? table.getItem(table
            .getTopIndex()) : selection[0];
        table.showItem(row);
        cursor.setSelection(row, 0);
        cursor.setVisible(true);
        cursor.setFocus();
      }
    });
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Place a progress bar in a SWT table

/*
 * TableEditor example snippet: place a progress bar in a table
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class Snippet149 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    Table table = new Table(shell, SWT.BORDER);
    table.setHeaderVisible(true);
    table.setLinesVisible(true);
    for (int i = 0; i < 2; i++) {
      new TableColumn(table, SWT.NONE);
    }
    table.getColumn(0).setText("Task");
    table.getColumn(1).setText("Progress");
    for (int i = 0; i < 40; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText("Task " + i);
      if (i % 5 == 0) {
        ProgressBar bar = new ProgressBar(table, SWT.NONE);
        bar.setSelection(i);
        TableEditor editor = new TableEditor(table);
        editor.grabHorizontal = editor.grabVertical = true;
        editor.setEditor(bar, item, 1);
      }
    }
    table.getColumn(0).pack();
    table.getColumn(1).setWidth(128);
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
  }
}





Place arbitrary controls in a SWT table

/*
 * Table example snippet: place arbitrary controls in a table
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
public class Snippet126 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    Table table = new Table(shell, SWT.BORDER | SWT.MULTI);
    table.setLinesVisible(true);
    for (int i = 0; i < 3; i++) {
      TableColumn column = new TableColumn(table, SWT.NONE);
      column.setWidth(100);
    }
    for (int i = 0; i < 12; i++) {
      new TableItem(table, SWT.NONE);
    }
    TableItem[] items = table.getItems();
    for (int i = 0; i < items.length; i++) {
      TableEditor editor = new TableEditor(table);
      CCombo combo = new CCombo(table, SWT.NONE);
      editor.grabHorizontal = true;
      editor.setEditor(combo, items[i], 0);
      editor = new TableEditor(table);
      Text text = new Text(table, SWT.NONE);
      editor.grabHorizontal = true;
      editor.setEditor(text, items[i], 1);
      editor = new TableEditor(table);
      Button button = new Button(table, SWT.CHECK);
      button.pack();
      editor.minimumWidth = button.getSize().x;
      editor.horizontalAlignment = SWT.LEFT;
      editor.setEditor(button, items[i], 2);
    }
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Print KTable (SWT Table)Example

/*
de.kupzog.ktools.kprint*  Version 1.1
_______________________________________________________________________
This is the source of a print layout package for Java SWT applications.
The features in short terms:
- creating well layouted printed documents by putting image and text 
  boxes on a document
  
- printing swt tables and ktables (see de.kupzog.ktable) within this framework 
- a page setup dialog (sorry, only in german)
- a print preview dialog (sorry, also only in german)
  
  
For a detailed function description refer to the api documentation that 
is included in the sourcefiles. For examples how to use KPrint, see the 
de.kupzog.ktools.kprint.example package.

Known problems:
_______________________________________________________________________
- Oversized images and tables will be printed over the margins
  (but not over the page border)
  
- No bold/italic words within other words in a text box available
  (only the complete box can be bold)
  
- The Print Preview can differ from the printed document (slightly
  different page breakes). This is because the space occupied by text
  changes with the font resolution. You can observe this phenomenon 
  also in some cases by changing the preview size.

The author welcomes any feedback:  fkmk@kupzog.de


*/
/*  Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.
 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.
 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 Author: Friederich Kupzog  
 fkmk@kupzog.de
 www.kupzog.de/fkmk
 */
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.ScrolledComposite;
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.SelectionListener;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
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.Device;
import org.eclipse.swt.graphics.Font;
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.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.printing.PrintDialog;
import org.eclipse.swt.printing.Printer;
import org.eclipse.swt.printing.PrinterData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.rubo;
import org.eclipse.swt.widgets.ruposite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
/**
 * This example shows how to print data from a KTableModel. More information
 * about this can be found in the text that is produced by KPrintExample.java.
 * 
 * @author Friederich Kupzog
 * 
 */
public class PrintKTableExample {
  private Display d;
  public PrintKTableExample() {
    d = new Display();
    // create a document with default settings from PageSetup
    PDocument doc = new PDocument("KTable printing example");
    // put some header text on it
    PTextBox t;
    t = new PTextBox(doc);
    t.setText("KTABLE PRINTING EXAMPLE");
    new PVSpace(doc, 0.1);
    new PHLine(doc, 0.02, SWT.COLOR_BLACK);
    new PVSpace(doc, 0.5);
    // create the table
    PTable table = new PTable(doc);
    table.setModel(new ExampleTableModel());
    table.setBoxProvider(new PTableBoxProvider());
    PrintPreview pr = new PrintPreview(null, "Test", IconSource
        .getImage("print"), doc);
    pr.open();
    d.dispose();
  }
  /**
   * This function would print the document witout the print preview.
   * 
   * @param doc
   */
  public void print(PDocument doc) {
    PrintDialog dialog = new PrintDialog(null, SWT.BORDER);
    PrinterData data = dialog.open();
    if (data == null)
      return;
    if (data.printToFile) {
      data.fileName = "print.out"; // you probably want to ask the user
      // for a filename
    }
    Printer printer = new Printer(data);
    GC gc = new GC(printer);
    PBox.setParameters(gc, printer, printer.getDPI(), 100);
    if (printer.startJob("DoSys Druckauftrag")) {
      printer.startPage();
      doc.layout();
      doc.draw(1);
      printer.endJob();
    }
    gc.dispose();
  }
  public static void main(String[] args) {
    new PrintKTableExample();
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/*
 * This feature was contributed by Onsel Armagan, Istanbul, Turkey Thanks a lot!
 */
class SWTPTable {
  protected Table table;
  protected PTableBoxProvider boxProvider;
  protected PContainer parent;
  public SWTPTable(PContainer parent) {
    this.parent = parent;
  }
  protected void fillDocument() {
    boolean abgeschnitten = false;
    calculatePageLengths();
    // Zeilen
    /**
     * TODO Print Table Header if (j == 0) style = PBox.POS_BELOW |
     * PBox.ROW_ALIGN;
     */
    double width = parent.getPossibleWidth();
    for (int j = 0; j < table.getColumnCount(); j++) {
      // System.out.println(" Zeile "+j);
      int height = table.getHeaderHeight();
      int style = PBox.POS_RIGHT | PBox.ROW_ALIGN;
      if (j == 0)
        style = PBox.POS_BELOW | PBox.ROW_ALIGN;
      PBox box = boxProvider.createBox(parent, style, j, 0, table
          .getColumn(j).getWidth(), height, true, table.getColumn(j)
          .getText());
      double boxWidth = Math.max(box.minCm, parent.getPossibleWidth()
          * box.hWeight);
      width -= boxWidth;
      if (width < 0) {
        box.dispose();
        abgeschnitten = true;
        break;
      }
    }
    for (int i = 0; i < table.getItemCount(); i++) {
      // System.out.println("Spalte "+i);
      int height = table.getItemHeight();
      width = parent.getPossibleWidth();
      // Spalten
      for (int j = 0; j < table.getColumnCount(); j++) {
        // System.out.println(" Zeile "+j);
        int style = PBox.POS_RIGHT | PBox.ROW_ALIGN;
        if (j == 0)
          style = PBox.POS_BELOW | PBox.ROW_ALIGN;
        PBox box = boxProvider.createBox(parent, style, j, i, table
            .getColumn(j).getWidth(), height, false, table.getItem(
            i).getText(j));
        double boxWidth = Math.max(box.minCm, parent.getPossibleWidth()
            * box.hWeight);
        width -= boxWidth;
        if (width < 0) {
          box.dispose();
          abgeschnitten = true;
          break;
        }
      }
    }
    if (abgeschnitten)
      MsgBox.show("Tabelle ist zu breit fur die Seite\n"
          + "und wird deshalb abgeschnitten.");
  }
  public void calculatePageLengths() {
    if (table != null) {
      PDocument doc = (PDocument) parent;
      double width = parent.getPossibleWidth();
      for (int j = 0; j < table.getColumnCount(); j++) {
        // System.out.println(" Zeile "+j);
        int height = table.getHeaderHeight();
        double boxWidth = Math.max(0,
            table.getColumn(j).getWidth() * 0.03);
        width -= boxWidth;
        if (width < 0) {
          break;
        }
      }
      if (width < 0) {
        doc.setPageHeight(PageSetup.paperWidth);
        doc.setPageWidth(PageSetup.paperHeight);
      }
    }
  }
  /**
   * @return PTableBoxProvider
   */
  public PTableBoxProvider getBoxProvider() {
    return boxProvider;
  }
  /**
   * @return KTableModel
   */
  public Table getTable() {
    return table;
  }
  /**
   * Sets the boxProvider.
   * 
   * @param boxProvider
   *            The boxProvider to set
   */
  public void setBoxProvider(PTableBoxProvider boxProvider) {
    this.boxProvider = boxProvider;
    if (this.boxProvider != null && this.table != null) {
      fillDocument();
    }
  }
  /**
   * Sets the table.
   * 
   * @param table
   *            The table to set
   */
  public void setTable(Table table) {
    this.table = table;
    if (this.boxProvider != null && this.table != null) {
      fillDocument();
    }
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * Vertical whitspace.
 * 
 * @author Friederich Kupzog
 */
class PVSpace extends PBox {
  private double cm;
  /**
   * Creates a new Space
   */
  public PVSpace(PContainer parent, double cm) {
    super(parent);
    this.cm = cm;
    // getBoxStyle().backColor = SWT.COLOR_CYAN;
  }
  /*
   * overridden from superclass
   */
  protected int getWidth() {
    // return 1;
    return 0;
  }
  /*
   * overridden from superclass
   */
  protected int getHeight() {
    if (forcedHeight > 0)
      return forcedHeight;
    return PBox.pixelY(cm);
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * A style for printable objects that that contain text.
 * 
 * @author Friederich Kupzog
 */
class PTextStyle {
  public static final int ALIGN_LEFT = 1;
  public static final int ALIGN_RIGHT = 2;
  public static final int ALIGN_CENTER = 3;
  protected static HashMap fonts = new HashMap();
  public int fontSize;
  public String fontName;
  public int fontStyle;
  public int fontColor;
  public int textAlign;
  protected double marginLeft;
  protected double marginRight;
  protected double marginTop;
  protected double marginBottom;
  public PTextStyle() {
    fontName = "Arial";
    fontStyle = SWT.NORMAL;
    fontSize = 10;
    fontColor = SWT.COLOR_BLACK;
    textAlign = ALIGN_LEFT;
    marginLeft = 0.0;
    marginRight = 0.0;
    marginTop = 0.0;
    marginBottom = 0.0;
  }
  public static void disposeFonts() {
    for (Iterator iter = fonts.values().iterator(); iter.hasNext();) {
      Font element = (Font) iter.next();
      element.dispose();
    }
    fonts.clear();
  }
  public static PTextStyle getDefaultStyle() {
    return new PTextStyle();
  }
  public Font getFont() {
    int height = Math.abs(fontSize * PBox.scalingPercent / 100);
    String key = PBox.device.getDPI().x + "|" + PBox.device.getDPI().y
        + "|" + fontName + "|" + height + "|" + fontStyle;
    Font font = (Font) fonts.get(key);
    if (font != null)
      return font;
    font = new Font(PBox.device, fontName, Math.abs(fontSize
        * PBox.scalingPercent / 100), fontStyle);
    fonts.put(key, font);
    return font;
  }
  public Color getFontColor() {
    return PBox.device.getSystemColor(fontColor);
  }
  /**
   * @return double
   */
  public double getMarginLeft() {
    return marginLeft;
  }
  /**
   * @return double
   */
  public double getMarginRight() {
    return marginRight;
  }
  /**
   * Sets the marginLeft.
   * 
   * @param marginLeft
   *            The marginLeft to set
   */
  public void setMarginLeft(double marginLeft) {
    this.marginLeft = marginLeft;
  }
  /**
   * Sets the marginRight.
   * 
   * @param marginRight
   *            The marginRight to set
   */
  public void setMarginRight(double marginRight) {
    this.marginRight = marginRight;
  }
  /**
   * @return double
   */
  public double getMarginBottom() {
    return marginBottom;
  }
  /**
   * @return double
   */
  public double getMarginTop() {
    return marginTop;
  }
  /**
   * Sets the marginBottom.
   * 
   * @param marginBottom
   *            The marginBottom to set
   */
  public void setMarginBottom(double marginBottom) {
    this.marginBottom = marginBottom;
  }
  /**
   * Sets the marginTop.
   * 
   * @param marginTop
   *            The marginTop to set
   */
  public void setMarginTop(double marginTop) {
    this.marginTop = marginTop;
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * A printable text label that can occupy more than one page. If you are shure
 * that the box will not be bigger than one page, you can use PLittleTextBox to
 * make the layout process quicker.
 * 
 * @author Friederich Kupzog For more details
 * @see PDocument and
 * @see PBox
 */
class PTextBox extends PBox {
  protected String text;
  protected PTextStyle textStyle;
  // multi-page
  protected ArrayList pageList;
  protected ArrayList textLines;
  protected int unplacedLines;
  /**
   * Creates a non-wrapping text box with a fixed size according to its text.
   * 
   * @param parent
   * @param style
   */
  public PTextBox(PContainer parent) {
    super(parent);
    init();
  }
  /**
   * Creates a non-wrapping text box with a fixed size according to its text.
   * 
   * @param parent
   * @param style
   */
  public PTextBox(PContainer parent, int style) {
    super(parent, style);
    init();
  }
  /**
   * Creates a text box with wrapping capabilities if hWeight is > 0.
   * 
   * @param parent
   * @param style
   * @param hWeight
   *            Specify -1 for a non-wrapping text box (If the text has
   *            newlines it will be a multi-line textbox). Spezify a number
   *            between 0 and 1 for a multiline textbox that consumes the
   *            given fraction of the available document width.
   * @param minWidth
   *            This allows you to specify a minimum width for the text. The
   *            text box will consume some space depending to hWeight or its
   *            text if hWeight is -1, but at least the given amount of
   *            centimeters. For a box with a fixed width for example set
   *            hWeigth = 0 and specify a non-zero minWidth.
   */
  public PTextBox(PContainer parent, int style, double hWeight,
      double minWidth) {
    super(parent, style, hWeight, minWidth);
    init();
  }
  private void init() {
    text = "";
    textStyle = PTextStyle.getDefaultStyle();
    pageList = new ArrayList();
    textLines = new ArrayList();
    unplacedLines = 0;
  }
  public void setText(String text) {
    if (text == null)
      text = "";
    this.text = text;
  }
  protected int layoutHowMuchWouldYouOccupyOf(Point spaceLeft, int page) {
    if (textLines.size() == 0)
      splitIntoLines();
    if (unplacedLines == 0)
      return 0;
    gc.setFont(textStyle.getFont());
    int lineHeight = gc.stringExtent("A").y;
    // System.out.println("LineH: "+lineHeight+" Space: "+spaceLeft.y);
    int erg = 0;
    int ctr = 0;
    do {
      erg += lineHeight;
      ctr++;
      if (ctr == unplacedLines)
        break;
    } while (erg + lineHeight <= spaceLeft.y);
    if (erg > spaceLeft.y)
      return -1;
    return erg;
  }
  /*
   * overridden from superclass
   */
  protected boolean layoutWouldYouFinishWithin(Point spaceLeft, int page) {
    gc.setFont(textStyle.getFont());
    int lineHeight = gc.stringExtent("A").y;
    return ((unplacedLines * lineHeight) <= spaceLeft.y);
  }
  /*
   * overridden from superclass
   */
  protected int layoutOccupy(Point origin, Point spaceLeft, int page) {
    if (textLines.size() == 0)
      splitIntoLines();
    if (unplacedLines == 0)
      return 0;
    if (this.origin.page == 0) {
      this.origin.page = page;
      this.origin.x = origin.x;
      this.origin.y = origin.y;
    }
    gc.setFont(textStyle.getFont());
    int lineHeight = gc.stringExtent("A").y;
    int erg = 0;
    int ctr = 0;
    do {
      erg += lineHeight;
      ctr++;
      if (ctr == unplacedLines)
        break;
    } while (erg + lineHeight <= spaceLeft.y);
    if (erg > spaceLeft.y)
      return 0;
    PTextPart part = new PTextPart();
    part.numOfLines = ctr;
    part.origin = new Point(origin.x, origin.y);
    part.startLine = textLines.size() - unplacedLines;
    pageList.add(part);
    unplacedLines -= ctr;
    return erg;
  }
  /*
   * overridden from superclass
   */
  protected boolean layoutIsOnPage(int page) {
    if (page >= origin.page && page < origin.page + pageList.size())
      return true;
    return false;
  }
  /*
   * overridden from superclass
   */
  protected int getWidth() {
    if (grabbing)
      return grabWidth;
    if (hWeight >= 0 && hWeight <= 1 && minCm >= 0) {
      PDocument myDoc = getDocument();
      double maxWidthCm = (myDoc.pageWidth - myDoc.margins[1] - myDoc.margins[3])
          * hWeight;
      return Math.max(pixelX(maxWidthCm), pixelX(minCm));
    }
    gc.setFont(textStyle.getFont());
    if (textLines.size() == 0)
      splitIntoLines();
    int erg = 0;
    for (Iterator iter = textLines.iterator(); iter.hasNext();) {
      String element = (String) iter.next();
      int w = gc.stringExtent(element).x;
      if (w > erg)
        erg = w;
    }
    erg += pixelX(textStyle.getMarginLeft());
    erg += pixelX(textStyle.getMarginRight());
    erg = Math.max(erg, pixelX(minCm));
    return erg;
  }
  protected void splitIntoLines() {
    textLines.clear();
    gc.setFont(textStyle.getFont());
    if ((grabWidth > 0) || (hWeight >= 0 && hWeight <= 1)) {
      PDocument myDoc = getDocument();
      int maxWidth;
      if (grabWidth > 0)
        maxWidth = grabWidth;
      else {
        double maxWidthCm = (myDoc.pageWidth - myDoc.margins[1] - myDoc.margins[3])
            * hWeight;
        maxWidth = Math.max(pixelX(maxWidthCm), pixelX(minCm));
      }
      maxWidth -= pixelX(textStyle.getMarginLeft());
      maxWidth -= pixelX(textStyle.getMarginRight());
      boolean fertig = false;
      int start = 0;
      int pos = 0;
      int lastPossibility = start;
      if (text.length() > 0) {
        while (!fertig) {
          int textLength = 0;
          while (!fertig && textLength < maxWidth) {
            if (text.charAt(pos) == " ")
              lastPossibility = pos;
            if (text.charAt(pos) == "-")
              lastPossibility = pos;
            if (text.charAt(pos) == "\n") {
              textLines.add(text.substring(start, pos).trim());
              start = pos + 1;
              pos = start;
            }
            int testPos = pos + 1;
            if (testPos > text.length())
              testPos = text.length();
            textLength = gc.stringExtent(text.substring(start,
                testPos)).x;
            if (textLength < maxWidth)
              pos++;
            if (pos >= text.length()) {
              fertig = true;
            }
          }
          int umbruchPos = pos;
          if (lastPossibility > start && !fertig)
            umbruchPos = lastPossibility + 1;
          textLines.add(text.substring(start, umbruchPos));
          if (!fertig) {
            start = umbruchPos;
            if (start >= text.length()) {
              fertig = true;
            } else {
              pos = start;
              lastPossibility = start;
            }
          }
        }
      }
    } else {
      textLines.add(text);
    }
    unplacedLines = textLines.size();
  }
  /*
   * overridden from superclass
   */
  protected void layoutResetTuning() {
    super.layoutResetTuning();
    pageList.clear();
    textLines.clear();
  }
  /*
   * overridden from superclass
   */
  protected int getHeight(int page) {
    gc.setFont(textStyle.getFont());
    int lineHeight = gc.stringExtent("A").y;
    PTextPart part = (PTextPart) pageList.get(page - origin.page);
    return part.numOfLines * lineHeight;
  }
  public void draw(int page, Point originOffset) {
    if (layoutIsOnPage(page)) {
      PTextPart part = (PTextPart) pageList.get(page - origin.page);
      this.origin = new PagePoint(part.origin, origin.page);
      super.draw(page, originOffset);
      Font font = textStyle.getFont();
      gc.setFont(font);
      gc.setForeground(textStyle.getFontColor());
      int lineHeight = gc.stringExtent("A").y;
      for (int i = 0; i < part.numOfLines; i++) {
        int alignPixel = 0;
        if (textStyle.textAlign == PTextStyle.ALIGN_CENTER) {
          int textWidth = gc.stringExtent((String) textLines
              .get(part.startLine + i)).x;
          alignPixel = (getWidth()
              - pixelX(textStyle.getMarginLeft())
              - pixelX(textStyle.getMarginRight()) - textWidth) / 2;
        } else if (textStyle.textAlign == PTextStyle.ALIGN_RIGHT) {
          gc.setFont(font);
          int textWidth = gc.stringExtent((String) textLines
              .get(part.startLine + i)).x;
          alignPixel = (getWidth()
              - pixelX(textStyle.getMarginLeft())
              - pixelX(textStyle.getMarginRight()) - textWidth);
          // System.out.println("""+(String)textLines.get(part.startLine
          // + i)+"" I="+i+" width = "+textWidth+ "
          // align="+alignPixel);
        }
        gc
            .drawText((String) textLines.get(part.startLine + i),
                part.origin.x + alignPixel + originOffset.x
                    + pixelX(textStyle.getMarginLeft()),
                part.origin.y + originOffset.y
                    + (i * lineHeight), true);
      }
    }
  }
  /**
   * @return PTextStyle
   */
  public PTextStyle getTextStyle() {
    return textStyle;
  }
  /**
   * Sets the textStyle.
   * 
   * @param textStyle
   *            The textStyle to set
   */
  public void setTextStyle(PTextStyle textStyle) {
    this.textStyle = textStyle;
  }
}
class PTextPart {
  public Point origin;
  public int startLine;
  public int numOfLines;
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * Used by PTable to print KTables. Comparable to KTableCellRenderer. Creates a
 * PBox for a Table cell. It gets width and height information from the model
 * which are pixel values fro screen view. It may use these values as a
 * guideline.
 * 
 * @author Friederich Kupzog
 */
class PTableBoxProvider {
  public PBox createBox(PContainer parent, int style, int col, int row,
      int widthFromModel, int heightFromModel, boolean fixed,
      Object content) {
    // create a text box
    PLittleTextBox box = new PLittleTextBox(parent, style, 0,
        widthFromModel * 0.03);
    // set its border lines
    PStyle boxStyle = PStyle.getDefaultStyle();
    boxStyle.lines = new double[] { 0.005, 0.01, 0.005, 0.0 };
    if (row == 0)
      boxStyle.lines[0] = 0.02;
    if (col == 0)
      boxStyle.lines[3] = 0.01;
    box.setBoxStyle(boxStyle);
    // set the font
    PTextStyle textStyle = PTextStyle.getDefaultStyle();
    if (fixed) // Header row / column
    {
      textStyle.setMarginLeft(0.08);
      textStyle.setMarginRight(0.08);
      textStyle.setMarginTop(0.1);
      textStyle.setMarginBottom(0.1);
      textStyle.fontSize = 9;
      textStyle.fontStyle = SWT.BOLD;
      textStyle.textAlign = PTextStyle.ALIGN_LEFT;
    } else // normal cell
    {
      textStyle.setMarginLeft(0.08);
      textStyle.setMarginRight(0.08);
      textStyle.setMarginTop(0.1);
      textStyle.setMarginBottom(0.1);
      textStyle.fontSize = 9;
      textStyle.textAlign = PTextStyle.ALIGN_LEFT;
    }
    box.setTextStyle(textStyle);
    // set the text
    box.setText(content.toString());
    // ready
    return box;
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * Allows to print KTable objects.
 * 
 * You have to specify a KTableModel and a PTableBoxProvider.
 * 
 * @author Friederich Kupzog
 */
class PTable {
  protected KTableModel model;
  protected PTableBoxProvider boxProvider;
  protected PContainer parent;
  public PTable(PContainer parent) {
    this.parent = parent;
  }
  protected void fillDocument() {
    boolean abgeschnitten = false;
    // Zeilen
    for (int i = 0; i < model.getRowCount(); i++) {
      // System.out.println("Spalte "+i);
      int height = model.getRowHeight();
      if (i == 0)
        height = model.getFirstRowHeight();
      double width = parent.getPossibleWidth();
      // Spalten
      for (int j = 0; j < model.getColumnCount(); j++) {
        // System.out.println(" Zeile "+j);
        int style = PBox.POS_RIGHT | PBox.ROW_ALIGN;
        if (j == 0)
          style = PBox.POS_BELOW | PBox.ROW_ALIGN;
        PBox box = boxProvider.createBox(parent, style, j, i, model
            .getColumnWidth(j), height,
            (model.getFixedColumnCount() > j || model
                .getFixedRowCount() > i), model.getContentAt(j,
                i));
        double boxWidth = Math.max(box.minCm, parent.getPossibleWidth()
            * box.hWeight);
        width -= boxWidth;
        if (width < 0) {
          box.dispose();
          abgeschnitten = true;
          break;
        }
      }
    }
    if (abgeschnitten)
      MsgBox.show("Tabelle ist zu breit fur die Seite\n"
          + "und wird deshalb abgeschnitten.");
  }
  /**
   * @return PTableBoxProvider
   */
  public PTableBoxProvider getBoxProvider() {
    return boxProvider;
  }
  /**
   * @return KTableModel
   */
  public KTableModel getModel() {
    return model;
  }
  /**
   * Sets the boxProvider.
   * 
   * @param boxProvider
   *            The boxProvider to set
   */
  public void setBoxProvider(PTableBoxProvider boxProvider) {
    this.boxProvider = boxProvider;
    if (this.boxProvider != null && this.model != null) {
      fillDocument();
    }
  }
  /**
   * Sets the model.
   * 
   * @param model
   *            The model to set
   */
  public void setModel(KTableModel model) {
    this.model = model;
    if (this.boxProvider != null && this.model != null) {
      fillDocument();
    }
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * A style for printable objects.
 * 
 * @author Friederich Kupzog
 */
class PStyle {
  public double[] lines;
  public int lineColor;
  public int backColor;
  public PStyle() {
    lines = new double[4];
    lines[0] = 0.0;
    lines[1] = 0.0;
    lines[2] = 0.0;
    lines[3] = 0.0;
    lineColor = SWT.COLOR_BLACK;
    backColor = SWT.COLOR_WHITE;
    // setDebugStyle();
  }
  private void setDebugStyle() {
    lines[0] = 0.01;
    lines[1] = 0.01;
    lines[2] = 0.01;
    lines[3] = 0.01;
    lineColor = SWT.COLOR_GRAY;
  }
  public static PStyle getDefaultStyle() {
    return new PStyle();
  }
  public int getLineWidth(int num) {
    int pixel = 0;
    if (num == 0 || num == 2)
      pixel = PBox.pixelY(lines[num]);
    if (num == 1 || num == 3)
      pixel = PBox.pixelX(lines[num]);
    if (pixel < 0)
      return 0;
    if (pixel == 0)
      return 1;
    return pixel;
  }
  public boolean hasLine(int num) {
    return lines[num] > 0;
  }
  public Color getLineColor() {
    return PBox.device.getSystemColor(lineColor);
  }
  public Color getBackColor() {
    return PBox.device.getSystemColor(backColor);
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * @author Friederich Kupzog A PTextStyle that is easy to create.
 */
class PSimpleTextStyle extends PTextStyle {
  public PSimpleTextStyle(String fontname, int size, boolean bold) {
    super();
    this.fontName = fontname;
    this.fontSize = size;
    if (bold)
      this.fontStyle = SWT.BOLD;
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/*
 * This feature was contributed by Onsel Armagan, Istanbul, Turkey Thanks a lot!
 */
/**
 * This example shows how to print data from a KTableModel. More information
 * about this can be found in the text that is produced by KPrintExample.java.
 * 
 * @author Friederich Kupzog
 * 
 */
class PrintSWTTableExample {
  private Display display;
  public PrintSWTTableExample() {
    // create some gui with a SWT table
    display = new Display();
    final Shell shell = new Shell(display);
    final org.eclipse.swt.layout.GridLayout gridLayout = new org.eclipse.swt.layout.GridLayout();
    gridLayout.numColumns = 2;
    shell.setLayout(gridLayout);
    final Color red = display.getSystemColor(SWT.COLOR_RED);
    final Table table_swt = new Table(shell, SWT.BORDER
        | SWT.FULL_SELECTION);
    final GridData gridData = new GridData(GridData.FILL_BOTH);
    gridData.horizontalSpan = 2;
    table_swt.setLayoutData(gridData);
    table_swt.setLinesVisible(true);
    TableColumn column1 = new TableColumn(table_swt, SWT.NONE);
    TableColumn column2 = new TableColumn(table_swt, SWT.NONE);
    TableColumn column3 = new TableColumn(table_swt, SWT.NONE);
    column1.setText("Column1");
    column2.setText("Column2");
    column3.setText("Column3");
    for (int i = 0; i < 100; i++) {
      TableItem item = new TableItem(table_swt, SWT.NONE);
      item.setText(new String[] { "cell " + i + " 0", "cell " + i + " 1",
          "cell " + i + "2" });
    }
    column1.pack();
    column2.pack();
    column3.pack();
    final Button butPrint = new Button(shell, SWT.NONE);
    butPrint.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        // create a document with default settings from PageSetup
        final PDocument doc = new PDocument(
            "SWT Table Printing Example");
        // put some header text on it
        PTextBox t;
        t = new PTextBox(doc);
        t.setText("SWT Table Printing Example");
        new PVSpace(doc, 0.1);
        new PHLine(doc, 0.02, SWT.COLOR_BLACK);
        new PVSpace(doc, 0.5);
        // create the table
        SWTPTable table = new SWTPTable(doc);
        table.setTable(table_swt);
        table.setBoxProvider(new PTableBoxProvider());
        PrintPreview pr = new PrintPreview(null, "Test", IconSource
            .getImage("print"), doc);
        pr.open();
      }
    });
    butPrint.setText("Print Preview");
    final Button butClose = new Button(shell, SWT.NONE);
    butClose.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        shell.dispose();
      }
    });
    butClose.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
    butClose.setText("Close");
    // Show the shell
    shell.setSize(300, 400);
    shell.setText("SWT Table Printing Example");
    shell.setVisible(true);
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
  /**
   * This function would print the document witout the print preview.
   * 
   * @param doc
   */
  public void print(PDocument doc) {
    PrintDialog dialog = new PrintDialog(null, SWT.BORDER);
    PrinterData data = dialog.open();
    if (data == null)
      return;
    if (data.printToFile) {
      data.fileName = "print.out"; // you probably want to ask the user
      // for a filename
    }
    Printer printer = new Printer(data);
    GC gc = new GC(printer);
    PBox.setParameters(gc, printer, printer.getDPI(), 100);
    if (printer.startJob("DoSys Druckauftrag")) {
      printer.startPage();
      doc.layout();
      doc.draw(1);
      printer.endJob();
    }
    gc.dispose();
  }
  public static void main(String[] args) {
    new PrintSWTTableExample();
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * A GUI dialog that layouts and displays a PDocument. It also allows to print
 * the document.
 * 
 * @author Friederich Kupzog
 */
class PrintPreview extends KDialog {
  protected PDocument document;
  protected Label guiImageLabel;
  protected CLabel guiPageLabel;
  protected Combo guiZoom;
  protected ScrolledComposite guiScrollArea;
  protected boolean layoutNeccessary;
  protected int percent;
  protected int page;
  /**
   * @param parent
   * @param title
   * @param icon
   */
  public PrintPreview(Shell parent, String title, Image icon, PDocument doc) {
    super(parent, title, icon);
    createContents();
    document = doc;
    page = 1;
    percent = 100;
    layoutNeccessary = true;
    addToolItem("print", "Drucken ...", IconSource.getImage("print"));
    addToolItem("first", "erste Seite", IconSource.getImage("i2"));
    addToolItem("prev", "vorherige Seite", IconSource.getImage("i3"));
    addToolItem("next", "nachste Seite", IconSource.getImage("i4"));
    addToolItem("last", "letzte Seite", IconSource.getImage("i5"));
    Button close = addButtonRight("&SchlieBen", "");
    // addButtonRight("Seite &einrichten","");
    close.setFocus();
    guiShell.addShellListener(new ShellAdapter() {
      public void shellClosed(ShellEvent arg0) {
        onClose();
      }
    });
    Composite comp = new Composite(guiToolBarArea, SWT.BORDER);
    comp.setLayout(new FillLayout());
    guiPageLabel = new CLabel(comp, SWT.NONE);
    guiPageLabel.setText(guiPageLabel.getText() + "        ");
    guiPageLabel.setBackground(Display.getCurrent().getSystemColor(
        SWT.COLOR_WHITE));
    adjustToToolBar(comp);
    guiZoom = new Combo(guiToolBarArea, SWT.BORDER | SWT.READ_ONLY);
    guiZoom.add("500%");
    guiZoom.add("200%");
    guiZoom.add("100%");
    guiZoom.add("80%");
    guiZoom.add("50%");
    guiZoom.add("20%");
    guiZoom.add("passend");
    adjustToToolBar(guiZoom);
    guiZoom.setToolTipText("VorschaugroBe");
    guiZoom.select(2);
    guiZoom.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent arg0) {
        onCombo(((Combo) arg0.widget).getText());
      }
    });
    guiMainArea.setLayout(new FillLayout());
    guiScrollArea = new ScrolledComposite(guiMainArea, SWT.H_SCROLL
        | SWT.V_SCROLL);
    guiImageLabel = new Label(guiScrollArea, SWT.NONE);
    guiScrollArea.setContent(guiImageLabel);
    if (guiImageLabel.getImage() != null)
      guiImageLabel.getImage().dispose();
    guiImageLabel.setImage(getPageImage(page));
    guiPageLabel.setText(" Seite " + page + " von "
        + document.getNumOfPages() + "       ");
    guiImageLabel.setSize(guiImageLabel.ruputeSize(SWT.DEFAULT,
        SWT.DEFAULT));
  }
  public int getShellStyle() {
    return super.getShellStyle() | SWT.MAX | SWT.MIN;
  }
  protected void doLayout() {
    int x = Display.getCurrent().getBounds().width - 100;
    int y = Display.getCurrent().getBounds().height - 10;
    guiShell.setSize(x, y);
    guiShell.setMaximized(true);
  }
  public Image getPageImage(int page) {
    Point dpi = Display.getCurrent().getDPI();
    try {
      int h = (int) Math.round(document.getPageHeight() / 2.54 * dpi.y
          * percent / 100 + 5);
      int w = (int) Math.round(document.getPageWidth() / 2.54 * dpi.x
          * percent / 100 + 5);
      Image newImage = new Image(Display.getCurrent(), w, h);
      GC gc = new GC(newImage);
      PBox.setParameters(gc, Display.getCurrent(), dpi, percent);
      if (layoutNeccessary)
        document.layout();
      layoutNeccessary = false;
      document.draw(page);
      // Schatten
      gc.setBackground(Display.getCurrent().getSystemColor(
          SWT.COLOR_DARK_GRAY));
      gc.fillRectangle(0, newImage.getBounds().height - 5, newImage
          .getBounds().width, newImage.getBounds().height);
      gc.fillRectangle(newImage.getBounds().width - 5, 0, newImage
          .getBounds().width - 5, newImage.getBounds().height);
      gc.setBackground(Display.getCurrent().getSystemColor(
          SWT.COLOR_WIDGET_BACKGROUND));
      gc.fillRectangle(0, newImage.getBounds().height - 5, 5, newImage
          .getBounds().height);
      gc.fillRectangle(newImage.getBounds().width - 5, 0, newImage
          .getBounds().width, 5);
      gc.dispose();
      return newImage;
    } catch (Exception e) {
      System.out.println(e.getMessage());
      return null;
    }
  }
  protected void onCombo(String text) {
    if (text.startsWith("passend")) {
      long ypixel = Math.round(document.getPageHeight() / 2.54
          * Display.getCurrent().getDPI().y);
      long xpixel = Math.round(document.getPageWidth() / 2.54
          * Display.getCurrent().getDPI().x);
      int yscale = (int) (100 * (guiScrollArea.getBounds().height) / ypixel);
      int xscale = (int) (100 * (guiScrollArea.getBounds().width) / xpixel);
      percent = Math.min(yscale, xscale);
    } else {
      text = text.substring(0, text.length() - 1);
      percent = 100;
      try {
        percent = Integer.parseInt(text);
      } catch (Exception e1) {
        MsgBox.show(""" + text + "" ist keine gultige Zahl.");
        guiZoom.select(3);
      }
    }
    layoutNeccessary = true;
    if (guiImageLabel.getImage() != null)
      guiImageLabel.getImage().dispose();
    guiImageLabel.setImage(getPageImage(page));
    guiImageLabel.setSize(guiImageLabel.ruputeSize(SWT.DEFAULT,
        SWT.DEFAULT));
  }
  protected void onToolItem(ToolItem toolitem, String name) {
    if (name.equals("next")) {
      if (page < document.getNumOfPages()) {
        page++;
        if (guiImageLabel.getImage() != null)
          guiImageLabel.getImage().dispose();
        guiImageLabel.setImage(getPageImage(page));
        guiPageLabel.setText(" Seite " + page + " von "
            + document.getNumOfPages());
      }
    } else if (name.equals("prev")) {
      if (page > 1) {
        page--;
        if (guiImageLabel.getImage() != null)
          guiImageLabel.getImage().dispose();
        guiImageLabel.setImage(getPageImage(page));
        guiPageLabel.setText(" Seite " + page + " von "
            + document.getNumOfPages());
      }
    } else if (name.equals("first")) {
      page = 1;
      if (guiImageLabel.getImage() != null)
        guiImageLabel.getImage().dispose();
      guiImageLabel.setImage(getPageImage(page));
      guiPageLabel.setText(" Seite " + page + " von "
          + document.getNumOfPages());
    } else if (name.equals("last")) {
      page = document.getNumOfPages();
      if (guiImageLabel.getImage() != null)
        guiImageLabel.getImage().dispose();
      guiImageLabel.setImage(getPageImage(page));
      guiPageLabel.setText(" Seite " + page + " von "
          + document.getNumOfPages());
    } else if (name.equals("print")) {
      onPrint();
    }
  }
  protected void onButton(Button button, String buttonText) {
    if (buttonText.startsWith("&Schlie"))
      onClose();
    else if (buttonText.startsWith("Seite"))
      onPageSetup();
  }
  protected void onClose() {
    if (guiImageLabel.getImage() != null)
      guiImageLabel.getImage().dispose();
    PTextStyle.disposeFonts();
    close();
  }
  protected void onPageSetup() {
    /*
     * funktioniert nicht: - Abgeschnittene Tabellen bleiben abgeschnitten -
     * Skalierung geht nicht
     */
    PageSetup ps = new PageSetup(guiShell);
    ps.open();
    document.readMeasuresFromPageSetup();
    layoutNeccessary = true;
    if (guiImageLabel.getImage() != null)
      guiImageLabel.getImage().dispose();
    guiImageLabel.setImage(getPageImage(page));
    guiImageLabel.setSize(guiImageLabel.ruputeSize(SWT.DEFAULT,
        SWT.DEFAULT));
  }
  protected void onPrint() {
    PrintDialog dialog = new PrintDialog(guiShell, SWT.BORDER);
    PrinterData data = dialog.open();
    if (data == null)
      return;
    if (data.printToFile) {
      FileDialog d = new FileDialog(guiShell, SWT.SAVE);
      d.setFilterNames(new String[] { "All Files (*.*)" });
      d.setFilterExtensions(new String[] { "*.*" }); // Windows wild
      // cards
      d.setFilterPath("c:\\"); // Windows path
      d.setFileName("");
      d.open();
      data.fileName = d.getFilterPath() + "\\" + d.getFileName();
    }
    Printer printer = new Printer(data);
    GC gc = new GC(printer);
    PBox.setParameters(gc, printer, printer.getDPI(), (int) (document
        .getScale() * 100));
    document.layout();
    if (printer.startJob(document.getTitle())) {
      if (data.scope == PrinterData.ALL_PAGES) {
        data.startPage = 1;
        data.endPage = document.getNumOfPages();
      } else if (data.scope == PrinterData.SELECTION) {
        data.startPage = page;
        data.endPage = page;
      } else if (data.scope == PrinterData.PAGE_RANGE) {
        if (data.startPage > document.getNumOfPages())
          data.startPage = document.getNumOfPages();
        if (data.endPage > document.getNumOfPages())
          data.endPage = document.getNumOfPages();
      }
      for (int page = data.startPage; page <= data.endPage; page++) {
        printer.startPage();
        document.draw(page);
        printer.endPage();
      }
      printer.endJob();
    }
    gc.dispose();
    printer.dispose();
    layoutNeccessary = true;
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * A text box that shows the current page number.
 * 
 * @author Friederich Kupzog
 */
class PPageNumber extends PTextBox {
  protected static int pageNumber = 0;
  /**
   * @param parent
   * @param style
   */
  public PPageNumber(PContainer parent, int style) {
    super(parent, style, -1, 0);
    setText("    ");
  }
  public void draw(int page, Point originOffset) {
    if (layoutIsOnPage(page)) {
      super.draw(page, originOffset);
      gc.setFont(textStyle.getFont());
      gc.setForeground(textStyle.getFontColor());
      gc.drawText("" + pageNumber, origin.x + originOffset.x
          + pixelX(textStyle.getMarginLeft()), origin.y
          + originOffset.y, true);
    }
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * forces a page break at the current position in the tree of printable elements
 * 
 * @author Friederich Kupzog
 */
class PPageBreak extends PBox {
  public PPageBreak(PContainer parent) {
    super(parent);
  }
  /*
   * overridden from superclass
   */
  protected int getWidth() {
    return 0;
  }
  /*
   * overridden from superclass
   */
  protected int layoutHowMuchWouldYouOccupyOf(Point spaceLeft, int page) {
    return -1;
  }
  /*
   * overridden from superclass
   */
  public void draw(int page, Point originOffset) {
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * A printable text label. If you need page breaks within the text of a box, use
 * PTextBox instead. CAUTION: A PLittleTextBox with too much text for one entire
 * page causes the layout process to hang in an endless loop.
 * 
 * @author Friederich Kupzog For more details
 * @see PDocument and
 * @see PBox
 */
class PLittleTextBox extends PBox {
  protected String text;
  protected PTextStyle textStyle;
  protected ArrayList textLines;
  /**
   * Creates a non-wrapping text box with a fixed size according to its text.
   * 
   * @param parent
   * @param style
   */
  public PLittleTextBox(PContainer parent) {
    super(parent);
    init();
  }
  /**
   * Creates a non-wrapping text box with a fixed size according to its text.
   * 
   * @param parent
   * @param style
   */
  public PLittleTextBox(PContainer parent, int style) {
    super(parent, style);
    init();
  }
  /**
   * Creates a text box with wrapping capabilities if hWeight is > 0.
   * 
   * @param parent
   * @param style
   * @param hWeight
   *            Specify -1 for a non-wrapping text box (If the text has
   *            newlines it will be a multi-line textbox). Spezify a number
   *            between 0 and 1 for a multiline textbox that consumes the
   *            given fraction of the available document width.
   * @param minWidth
   *            This allows you to specify a minimum width for the text. The
   *            text box will consume some space depending to hWeight or its
   *            text if hWeight is -1, but at least the given amount of
   *            centimeters. For a box with a fixed width for example set
   *            hWeigth = 0 and specify a non-zero minWidth.
   */
  public PLittleTextBox(PContainer parent, int style, double hWeight,
      double minWidth) {
    super(parent, style, hWeight, minWidth);
    init();
  }
  private void init() {
    text = "";
    textStyle = PTextStyle.getDefaultStyle();
    textLines = new ArrayList();
  }
  public void setText(String text) {
    if (text == null)
      text = "";
    this.text = text;
  }
  /*
   * overridden from superclass
   */
  protected int getWidth() {
    if (grabbing)
      return grabWidth;
    if (hWeight >= 0 && hWeight <= 1 && minCm >= 0) {
      PDocument myDoc = getDocument();
      double maxWidthCm = (myDoc.pageWidth - myDoc.margins[1] - myDoc.margins[3])
          * hWeight;
      return Math.max(pixelX(maxWidthCm), pixelX(minCm));
    }
    gc.setFont(textStyle.getFont());
    if (textLines.size() == 0)
      splitIntoLines();
    int erg = 0;
    for (Iterator iter = textLines.iterator(); iter.hasNext();) {
      String element = (String) iter.next();
      int w = gc.stringExtent(element).x;
      if (w > erg)
        erg = w;
    }
    erg += pixelX(textStyle.getMarginLeft());
    erg += pixelX(textStyle.getMarginRight());
    erg = Math.max(erg, pixelX(minCm));
    return erg;
  }
  protected void splitIntoLines() {
    textLines.clear();
    gc.setFont(textStyle.getFont());
    if ((grabWidth > 0) || (hWeight >= 0 && hWeight <= 1)) {
      PDocument myDoc = getDocument();
      int maxWidth;
      if (grabWidth > 0)
        maxWidth = grabWidth;
      else {
        double maxWidthCm = (myDoc.pageWidth - myDoc.margins[1] - myDoc.margins[3])
            * hWeight;
        maxWidth = Math.max(pixelX(maxWidthCm), pixelX(minCm));
      }
      maxWidth -= pixelX(textStyle.getMarginLeft());
      maxWidth -= pixelX(textStyle.getMarginRight());
      boolean fertig = false;
      int start = 0;
      int pos = 0;
      int lastPossibility = start;
      if (text.length() > 0) {
        while (!fertig) {
          int textLength = 0;
          while (!fertig && textLength < maxWidth) {
            if (text.charAt(pos) == " ")
              lastPossibility = pos;
            if (text.charAt(pos) == "-")
              lastPossibility = pos;
            if (text.charAt(pos) == "\n") {
              textLines.add(text.substring(start, pos));
              start = pos + 1;
              pos = start;
            }
            int testPos = pos + 1;
            if (testPos > text.length())
              testPos = text.length();
            textLength = gc.stringExtent(text.substring(start,
                testPos)).x;
            if (textLength < maxWidth)
              pos++;
            if (pos >= text.length()) {
              fertig = true;
            }
          }
          int umbruchPos = pos;
          if (lastPossibility > start && !fertig)
            umbruchPos = lastPossibility + 1;
          textLines.add(text.substring(start, umbruchPos));
          if (!fertig) {
            start = umbruchPos;
            if (start >= text.length()) {
              fertig = true;
            } else {
              pos = start;
              lastPossibility = start;
            }
          }
        }
      }
    } else {
      textLines.add(text);
    }
  }
  /*
   * overridden from superclass
   */
  protected void layoutResetTuning() {
    super.layoutResetTuning();
    textLines.clear();
  }
  /*
   * overridden from superclass
   */
  protected int getHeight() {
    if (forcedHeight > 0)
      return forcedHeight;
    if (textLines.size() == 0)
      splitIntoLines();
    gc.setFont(textStyle.getFont());
    int lineHeight = gc.stringExtent("A").y;
    return (textLines.size() * lineHeight)
        + pixelY(textStyle.getMarginTop() + textStyle.getMarginBottom());
  }
  public void draw(int page, Point originOffset) {
    if (layoutIsOnPage(page)) {
      super.draw(page, originOffset);
      Font font = textStyle.getFont();
      gc.setFont(font);
      gc.setForeground(textStyle.getFontColor());
      int lineHeight = gc.stringExtent("A").y;
      for (int i = 0; i < textLines.size(); i++) {
        int alignPixel = 0;
        if (textStyle.textAlign == PTextStyle.ALIGN_CENTER) {
          int textWidth = gc.stringExtent((String) textLines.get(i)).x;
          alignPixel = (getWidth()
              - pixelX(textStyle.getMarginLeft())
              - pixelX(textStyle.getMarginRight()) - textWidth) / 2;
        } else if (textStyle.textAlign == PTextStyle.ALIGN_RIGHT) {
          int textWidth = gc.stringExtent((String) textLines.get(i)).x;
          alignPixel = (getWidth()
              - pixelX(textStyle.getMarginLeft())
              - pixelX(textStyle.getMarginRight()) - textWidth);
        }
        gc.drawText((String) textLines.get(i), origin.x + alignPixel
            + originOffset.x + pixelX(textStyle.getMarginLeft()),
            origin.y + originOffset.y
                + pixelY(textStyle.getMarginTop())
                + (i * lineHeight), true);
      }
    }
  }
  /**
   * @return PTextStyle
   */
  public PTextStyle getTextStyle() {
    return textStyle;
  }
  /**
   * Sets the textStyle.
   * 
   * @param textStyle
   *            The textStyle to set
   */
  public void setTextStyle(PTextStyle textStyle) {
    this.textStyle = textStyle;
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * A printable Image label.
 * 
 * @author Friederich Kupzog For more details
 * @see PDocument
 */
class PImageBox extends PBox {
  protected String imgName;
  protected int imgDPI;
  protected Image image;
  protected Point imgOriginalSize;
  protected Point imgTargetSize;
  /**
   * @param parent
   * @param style
   */
  public PImageBox(PContainer parent, int style) {
    super(parent, style);
  }
  /**
   * Sets the Image. The size of the image will be calculated by using the dpi
   * parameter, in which you can specify which resolution is the "native"
   * image resulotion. If you e.g. specify 600 dpi and print on a 600 dpi
   * printer, the image will not be resized. If you print it on an 300 dpi
   * printer, it will be resized.
   * 
   * @param name
   * @param dpi
   */
  public void setImage(String name, int dpi) {
    this.imgName = name;
    this.imgDPI = dpi;
    image = null;
    imgOriginalSize = null;
    imgTargetSize = null;
  }
  /*
   * overridden from superclass
   */
  protected void layoutResetTuning() {
    super.layoutResetTuning();
    image = null;
    imgOriginalSize = null;
    imgTargetSize = null;
  }
  protected Point calcSize() {
    try {
      Class clazz = new Object().getClass();
      InputStream is = clazz.getResourceAsStream(imgName);
      image = new Image(device, is);
      imgOriginalSize = new Point(0, 0);
      imgOriginalSize.x = image.getImageData().width;
      imgOriginalSize.y = image.getImageData().height;
      imgTargetSize = new Point(0, 0);
      imgTargetSize.x = (int) (imgOriginalSize.x * scalingPercent / 100 * (pixelPerInch.x / (double) imgDPI));
      imgTargetSize.y = (int) (imgOriginalSize.y * scalingPercent / 100 * (pixelPerInch.y / (double) imgDPI));
      sizeCalculatedfor = scalingPercent;
      image.getImageData().transparentPixel = -1;
      image.getImageData().maskData = null;
      return imgTargetSize;
    } catch (Exception e1) {
      System.out.println("could not open ressource " + imgName);
      imgOriginalSize = new Point(10, 10);
      imgTargetSize = new Point(10, 10);
      return imgTargetSize;
    }
  }
  /*
   * overridden from superclass
   */
  protected int layoutHowMuchWouldYouOccupyOf(Point spaceLeft, int page) {
    if (layoutAlreadyFinished())
      return 0;
    if (sizeCalculatedfor != scalingPercent || image == null) {
      calcSize();
    }
    // System.out.println("Size: "+imgTargetSize.y+" Space: "+spaceLeft.y);
    if (imgTargetSize.y > spaceLeft.y)
      return -1;
    return imgTargetSize.y;
  }
  /*
   * overridden from superclass
   */
  protected int getWidth() {
    if (sizeCalculatedfor != scalingPercent || image == null) {
      calcSize();
    }
    return imgTargetSize.x;
  }
  /*
   * overridden from superclass
   */
  protected int getHeight() {
    if (rowAlign)
      return forcedHeight;
    if (sizeCalculatedfor != scalingPercent || image == null) {
      calcSize();
    }
    return imgTargetSize.y;
  }
  /*
   * overridden from superclass
   */
  protected int layoutOccupy(Point origin, Point spaceLeft, int page) {
    if (layoutAlreadyFinished())
      return 0;
    if (sizeCalculatedfor != scalingPercent || image == null) {
      calcSize();
    }
    this.origin = new PagePoint(origin, page);
    return imgTargetSize.y;
  }
  public void draw(int page, Point originOffset) {
    if (layoutIsOnPage(page)) {
      super.draw(page, originOffset);
      if (image != null) {
        gc.drawImage(image, 0, 0, imgOriginalSize.x, imgOriginalSize.y,
            origin.x + originOffset.x, origin.y + originOffset.y,
            imgTargetSize.x, imgTargetSize.y);
      }
    }
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * Horizontal white space
 * 
 * @author Friederich Kupzog
 */
class PHSpace extends PBox {
  private double cm;
  /**
   * Creates a new Space
   */
  public PHSpace(PContainer parent, int style, double cm) {
    super(parent, style);
    this.cm = cm;
    // getBoxStyle().backColor = SWT.COLOR_GREEN;
  }
  /*
   * overridden from superclass
   */
  protected int getWidth() {
    if (grabbing)
      return grabWidth;
    return PBox.pixelX(cm);
  }
  protected int getHeight() {
    if (forcedHeight > 0)
      return forcedHeight;
    // return 2;
    return 0;
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * A horzontal line
 * 
 * @author Friederich Kupzog
 */
class PHLine extends PBox {
  protected double thickness;
  protected int color;
  /**
   * Creates a horizontal line with the given thickness and color.
   */
  public PHLine(PContainer parent, double thickness, int color) {
    super(parent, POS_BELOW, 1.0, 0.0);
    this.thickness = thickness;
    boxStyle.lines = new double[] { 0.0, 0.0, 0.0, 0.0 };
    boxStyle.backColor = color;
  }
  /**
   * Creates a black thin horizontal line.
   */
  public PHLine(PContainer parent) {
    super(parent, POS_BELOW, 1.0, 0.0);
    this.thickness = 0.01;
    boxStyle.lines = new double[] { 0.0, 0.0, 0.0, 0.0 };
    boxStyle.backColor = SWT.COLOR_BLACK;
  }
  protected int getHeight() {
    if (forcedHeight > 0)
      return forcedHeight;
    int erg = PBox.pixelY(thickness);
    if (erg == 0)
      return 1;
    return erg;
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * Class that represents a document to print.
 * 
 * To print a document an a GC, the folowing steps are neccessary:
 * 
 * (1) create the document"s content by creating a PDocument object and adding
 * children.
 * 
 * (2) setting the GC and its resulution by using the static method
 * PDocument.setParameters
 * 
 * (3) layoutouting the children by a call to PDocument.layout()
 * 
 * (4) drawing the documents pages on a GC by calling PDocument.draw(int page)
 * 
 * (5) disposing the GC and all Font objects by calling PTextStyle.disposeAll.
 * 
 * Note that all this (except (1)) is done by the PrintPreview class.
 * 
 * Example code: <code>
 *     Image newImage = new Image(
 Display.getCurrent(),
 9*40,13*40);
 GC gc = new GC(newImage);
 PBox.setParameters(gc, Display.getCurrent(), d.getDPI());
 PDocument c = new PDocument(9,13);
 
 PTextBox t = new PTextBox(c, PBox.BEGINNING);
 t.setText("This is text.");
 
 c.layout();    
 c.draw(1);
 
 gc.dispose();
 
 PTextStyle.disposeAll();
 
 * </code>
 * 
 * @author Friederich Kupzog
 */
class PDocument extends PContainer {
  protected double pageHeight;
  protected double pageWidth;
  protected PContainer firstHeader;
  protected PContainer firstFooter;
  protected PContainer header;
  protected PContainer footer;
  protected double[] margins;
  protected int numOfPages;
  protected Point originOnFirstPage;
  protected Point originOnOtherPages;
  protected Point originOfPage;
  protected Point originFirstFooter;
  protected Point originOtherFooters;
  protected String documentTitle;
  protected double scale;
  /**
   * 
   * @param pageWidth
   *            absolute paper width in cm
   * @param pageHeight
   *            absolute paper height in cm
   * @param top
   * @param right
   * @param bottom
   * @param left
   * @param scale
   *            Scale factor: 1.0 = normal. If you e.g. specify A4 paper size
   *            and scale factor 0.712, then the document will be printed like
   *            on A3 but scaled on an A4 sheet.
   */
  public PDocument(double pageWidth, double pageHeight, double top,
      double right, double bottom, double left, double scale,
      String docTitle) {
    super(null);
    this.doc = this;
    this.scale = scale;
    this.pageHeight = pageHeight * 1 / scale;
    this.pageWidth = pageWidth * 1 / scale;
    this.documentTitle = docTitle;
    numOfPages = -1;
    margins = new double[4];
    margins[0] = top;
    margins[1] = right;
    margins[2] = bottom;
    margins[3] = left;
    firstFooter = new PContainer(this);
    footer = new PContainer(this);
    firstHeader = new PContainer(this);
    header = new PContainer(this);
  }
  /**
   * Fills parameters with values from PageSetup.
   * 
   * @param pageWidth
   * @param pageHeight
   */
  public PDocument(String docname) {
    this(PageSetup.paperWidth, PageSetup.paperHeight, 0, 0, 0, 0,
        (double) PageSetup.scaling / 100, docname);
    double margin = 2.5;
    if (PageSetup.marginStyle == PageSetup.MARGIN_HUGE)
      margin = 4;
    if (PageSetup.marginStyle == PageSetup.MARGIN_SMALL)
      margin = 1;
    margins[0] = margin;
    margins[1] = margin;
    margins[2] = margin;
    margins[3] = margin;
  }
  public void readMeasuresFromPageSetup() {
    pageWidth = PageSetup.paperWidth;
    pageHeight = PageSetup.paperHeight;
    scale = (double) PageSetup.scaling / 100;
    double margin = 2.5;
    if (PageSetup.marginStyle == PageSetup.MARGIN_HUGE)
      margin = 4;
    if (PageSetup.marginStyle == PageSetup.MARGIN_SMALL)
      margin = 1;
    margins[0] = margin;
    margins[1] = margin;
    margins[2] = margin;
    margins[3] = margin;
  }
  /**
   * returns the size of the page area in pixels given the current dpi setting
   * set by PBox.setParameters. The page borders are not included.
   */
  protected Point getPageSize(int page) {
    Point erg = new Point(PBox.pixelX(pageWidth - margins[1] - margins[3]),
        PBox.pixelY(pageHeight - margins[0] - margins[2]));
    if (getFooter(page) != null) {
      erg.y -= getFooter(page).getHeight();
    }
    if (getHeader(page) != null) {
      erg.y -= getHeader(page).getHeight();
    }
    return erg;
  }
  public String getTitle() {
    return documentTitle;
  }
  /**
   * use this method to make all tuning variables of this document and all its
   * children unvalid and so force a recalculation of these variables.
   */
  protected void layoutResetTuning() {
    super.layoutResetTuning();
    firstHeader.layoutResetTuning();
    firstFooter.layoutResetTuning();
    header.layoutResetTuning();
    footer.layoutResetTuning();
  }
  /**
   * Determines all positions of elements and calculates page break positions
   */
  public void layout() {
    layoutResetTuning();
    int offsetX = 0, offsetY = 0;
    Rectangle clientArea = PBox.device.getClientArea();
    if (PBox.device instanceof Printer) {
      /*
       * Rectangle trim = ((Printer) PBox.device).ruputeTrim(0, 0,
       * PBox.pixelX(pageWidth), PBox.pixelY(pageHeight)); offsetX =
       * trim.x; offsetY = trim.y; System.out.println(" Trim: "+trim);
       * 
       * System.out.println("Vorher Page: " + pageHeight + " x " +
       * pageWidth + " cm"); System.out.println("ClientArea: " +
       * clientArea); pageHeight =
       * (double)(clientArea.height/PBox.device.getDPI().y)*2.54;
       * pageWidth =
       * (double)(clientArea.width/PBox.device.getDPI().x)*2.54;
       * System.out.println("Nachher Page: " + pageHeight + " x " +
       * pageWidth + " cm");
       * 
       */
      /*
       * Rectangle trim = ((Printer) PBox.device).ruputeTrim(0, 0, 0, 0);
       * System.out.println(" Trim: "+trim); System.out.println(" DPI:
       * "+PBox.device.getDPI()); double[] unprintableMargin = new
       * double[4]; unprintableMargin[0] = -trim.y; unprintableMargin[1] =
       * trim.width + trim.x; unprintableMargin[2] = trim.height + trim.y;
       * unprintableMargin[3] = -trim.x;
       * 
       * unprintableMargin[0] =
       * (double)(unprintableMargin[0]/PBox.device.getDPI().y)*2.54;
       * unprintableMargin[1] =
       * (double)(unprintableMargin[1]/PBox.device.getDPI().x)*2.54;
       * unprintableMargin[2] =
       * (double)(unprintableMargin[2]/PBox.device.getDPI().y)*2.54;
       * unprintableMargin[3] =
       * (double)(unprintableMargin[3]/PBox.device.getDPI().x)*2.54;
       * 
       * for (int i = 0; i < unprintableMargin.length; i++) {
       * System.out.print("Rand " + i + " Vorher: "+margins[i]);
       * margins[i] -= unprintableMargin[i]; if (margins[i] < 0)
       * margins[i] = 0; System.out.println(" nachher: "+margins[i]); }
       */
    }
    int maxHeightForFirstPage = PBox.pixelY(getPageHeight() - margins[0]
        - margins[2]);
    int maxHeightForOtherPages = PBox.pixelY(getPageHeight() - margins[0]
        - margins[2]);
    // Annahme hier: Header passen auf jeden Fall auf die Seite
    firstHeader.layout(maxHeightForFirstPage, maxHeightForOtherPages);
    firstFooter.layout(maxHeightForFirstPage, maxHeightForOtherPages);
    maxHeightForFirstPage -= firstHeader.getHeight();
    maxHeightForFirstPage -= firstFooter.getHeight();
    header.layout(maxHeightForOtherPages, maxHeightForOtherPages);
    footer.layout(maxHeightForOtherPages, maxHeightForOtherPages);
    maxHeightForOtherPages -= header.getHeight();
    maxHeightForOtherPages -= footer.getHeight();
    originOfPage = new Point(PBox.pixelX(margins[3]) + offsetX, PBox
        .pixelY(margins[0])
        + offsetY);
    // System.out.println(" originOfPage: "+originOfPage);
    originOnFirstPage = new Point(PBox.pixelX(margins[3]) + offsetX, PBox
        .pixelY(margins[0])
        + getFirstHeader().getHeight() + offsetY);
    // System.out.println(" originOnFirstPage: "+originOnFirstPage);
    originOnOtherPages = new Point(PBox.pixelX(margins[3]) + offsetX, PBox
        .pixelY(margins[0])
        + getHeader().getHeight() + offsetY);
    // System.out.println(" originOnOtherPages: "+originOnOtherPages);
    originFirstFooter = new Point(PBox.pixelX(margins[3]) + offsetX, PBox
        .pixelY(getPageHeight() - margins[2])
        - getFirstFooter().getHeight() + offsetY);
    // System.out.println(" originFirstFooter: "+originFirstFooter);
    originOtherFooters = new Point(PBox.pixelX(margins[3]) + offsetX, PBox
        .pixelY(getPageHeight() - margins[2])
        - getFooter().getHeight() + offsetY);
    // System.out.println(" originOtherFooters: "+originOtherFooters);
    numOfPages = layout(maxHeightForFirstPage, maxHeightForOtherPages);
  }
  /**
   * Returns the number of pages to be printed. Before calling this function,
   * you have to call PDocument.layout()
   * 
   * @return int
   */
  public int getNumOfPages() {
    /*
     * if (numOfPages == -1) throw new NullPointerException("Please call
     * layout() first.");
     */
    return numOfPages;
  }
  /**
   * Draws the given page number on the GC set by PBox.setParameters Before
   * calling this function, you have to call PDocument.layout()
   */
  public void draw(int page) {
    PPageNumber.pageNumber = page;
    if (page == 1) {
      if (getHeader(page) != null)
        getHeader(page).draw(1, originOfPage);
      super.draw(page, originOnFirstPage);
      if (getFooter(page) != null)
        getFooter(page).draw(1, originFirstFooter);
    } else {
      if (getHeader(page) != null)
        getHeader(page).draw(1, originOfPage);
      super.draw(page, originOnOtherPages);
      if (getFooter(page) != null)
        getFooter(page).draw(1, originOtherFooters);
    }
  }
  /**
   * @return PBox
   */
  public PContainer getFooter(int page) {
    if (page == 1)
      return firstFooter;
    return footer;
  }
  /**
   * @return PBox
   */
  public PContainer getHeader(int page) {
    if (page == 1)
      return firstHeader;
    return header;
  }
  /**
   * @return PContainer
   */
  public PContainer getFirstFooter() {
    return firstFooter;
  }
  /**
   * @return PContainer
   */
  public PContainer getFirstHeader() {
    return firstHeader;
  }
  /**
   * @return PContainer
   */
  public PContainer getFooter() {
    return footer;
  }
  /**
   * @return PContainer
   */
  public PContainer getHeader() {
    return header;
  }
  /**
   * @return double
   */
  public double getPageHeight() {
    return pageHeight;
  }
  /**
   * @return double
   */
  public double getPageWidth() {
    return pageWidth;
  }
  /**
   * Sets the pageheight.
   * 
   * @param pageheight
   *            The pageheight to set
   */
  public void setPageHeight(double pageHeight) {
    this.pageHeight = pageHeight;
  }
  /**
   * Sets the pageWidth.
   * 
   * @param pageWidth
   *            The pageWidth to set
   */
  public void setPageWidth(double pageWidth) {
    this.pageWidth = pageWidth;
  }
  /**
   * If you have already set the first footer, you can use this method to make
   * all footers equal to this first footer.
   */
  public void setAllFootersLikeFirst() {
    footer = firstFooter;
  }
  /**
   * If you have already set the first header, you can use this method to make
   * all headers equal to this first header.
   */
  public void setAllHeadersLikeFirst() {
    header = firstHeader;
  }
  /**
   * @return
   */
  public double getScale() {
    return scale;
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * A Container class for PBoxes. Used for PDocument, Headers and Footers.
 * 
 * @author Friederich Kupzog
 */
class PContainer {
  protected ArrayList children;
  protected PDocument doc;
  private int calculatedHeight;
  /**
   * 
   */
  public PContainer(PDocument doc) {
    this.doc = doc;
    children = new ArrayList(100);
    calculatedHeight = -1;
  }
  protected double getPossibleWidth() {
    return (doc.pageWidth - doc.margins[1] - doc.margins[3]);
  }
  protected void addChild(PBox child) {
    children.add(child);
  }
  /**
   * Returns the height of this Container on the first pages it occupies.
   * Usually only used with headers and footers. Does only work if the
   * container is already layouted.
   * 
   * @return int
   */
  protected int getHeight() {
    if (calculatedHeight == -1)
      return 0;
    return calculatedHeight;
  }
  protected void layoutResetTuning() {
    calculatedHeight = -1;
    for (Iterator iter = children.iterator(); iter.hasNext();) {
      PBox element = (PBox) iter.next();
      element.layoutResetTuning();
    }
  }
  /*
   * Gibt die Anzahl der gefullten Seiten zuruck.
   */
  protected int layout(int maxHeightForFirstPage, int maxHeightForOtherPages) {
    int currentPage = 1;
    Point currentOrgin = new Point(0, 0);
    Point spaceLeft = new Point(PBox.pixelX(getPossibleWidth()),
        maxHeightForFirstPage);
    resetElementIndex();
    List currentRow = getNextRow();
    // Schleife uber alle Elemente in "Zeilen"
    while (currentRow != null) {
      boolean pageBreakNeccessary;
      rowHorizontalLayout(currentRow, spaceLeft);
      do {
        pageBreakNeccessary = rowVerticalLayout(currentRow,
            currentOrgin, spaceLeft, currentPage);
        if (currentPage == 1 && calculatedHeight < currentOrgin.y)
          calculatedHeight = currentOrgin.y;
        if (pageBreakNeccessary) {
          currentPage++;
          PPageNumber.pageNumber++;
          currentOrgin = new Point(0, 0);
          spaceLeft = new Point(PBox.pixelX(getPossibleWidth()),
              maxHeightForOtherPages);
        }
      } while (pageBreakNeccessary);
      currentRow = getNextRow();
    }
    return currentPage;
  }
  /*
   * Gibt true zuruck, wenn ein Seitenumbruch notig ist. Wird in diesem Falle
   * von layout() nochmal fur die gleiche Zeile aber die nachste Seite
   * aufgerufen.
   */
  private boolean rowVerticalLayout(List row, Point origin, Point spaceLeft,
      int page) {
    int max = 0;
    boolean pageBreakNeccessary = false;
    boolean allOnNextPage = false;
    origin.x = 0;
    // Hohen verarbeiten
    for (Iterator iter = row.iterator(); iter.hasNext();) {
      PBox element = (PBox) iter.next();
      if (element instanceof PPageBreak)
        break;
      int height = element.layoutHowMuchWouldYouOccupyOf(spaceLeft, page);
      if (!element.layoutWouldYouFinishWithin(spaceLeft, page))
        pageBreakNeccessary = true;
      if (height < 0) {
        allOnNextPage = true;
        max = 0;
        break;
      } else if (height > max)
        max = height;
    }
    if (!allOnNextPage) {
      for (Iterator iter = row.iterator(); iter.hasNext();) {
        PBox element = (PBox) iter.next();
        if (element instanceof PPageBreak) {
          max = spaceLeft.y;
          break;
        }
        element.layoutOccupy(origin, spaceLeft, page);
        if (element.rowAlign)
          element.setForcedHeight(max);
        origin.x += element.getWidth();
      }
      origin.y += max;
      spaceLeft.y -= max;
      origin.x = 0;
      return pageBreakNeccessary;
    }
    return true;
  }
  // Breiten berechnen und setzen
  private void rowHorizontalLayout(List row, Point spaceLeft) {
    int numOfGrabbingElements = 0;
    int widthLeft = spaceLeft.x;
    for (Iterator iter = row.iterator(); iter.hasNext();) {
      PBox element = (PBox) iter.next();
      if (element.grabbing)
        numOfGrabbingElements++;
      else
        widthLeft -= element.getWidth();
    }
    if (widthLeft < 0)
      widthLeft = 0; // bad practice, but easy...
    if (numOfGrabbingElements > 0) {
      int grabWidth = widthLeft / numOfGrabbingElements;
      for (Iterator iter = row.iterator(); iter.hasNext();) {
        PBox element = (PBox) iter.next();
        if (element.grabbing)
          element.grabWidth = grabWidth;
      }
    }
  }
  private int elementIndex;
  private List getNextRow() {
    if (elementIndex == children.size())
      return null;
    int last = elementIndex;
    int save = elementIndex;
    boolean firstRun = true;
    for (; last < children.size(); last++) {
      PBox element = (PBox) children.get(last);
      if (!firstRun && element.below)
        break;
      firstRun = false;
    }
    elementIndex = last;
    return children.subList(save, last);
  }
  private void resetElementIndex() {
    elementIndex = 0;
  }
  public void draw(int page, Point origin) {
    for (Iterator iter = children.iterator(); iter.hasNext();) {
      PBox element = (PBox) iter.next();
      if (element.layoutIsOnPage(page)) {
        element.draw(page, origin);
      }
    }
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * Abstract superclass for all printable Objects.
 * 
 * For more details
 * 
 * @see PDocument
 * @author Friederich Kupzog
 */
class PBox {
  // Styles
  /**
   * Style flag that forces the PBox to be in a new line below the previous
   * one Cannot be used simultaniously to POS_RIGHT.
   */
  public static final int POS_BELOW = 1;
  /**
   * Style flag that forces the PBox to be in line with the previous one.
   * Cannot be used simultaniously to POS_BELOW.
   */
  public static final int POS_RIGHT = 2;
  /**
   * Style flag that can be used additionally to POS_BELOW/POS_RIGHT to tell
   * the PBox that it shoul consume all available horizontal space on the
   * page.
   */
  public static final int GRAB = 4;
  /**
   * Style flag that is mainly used by tables and forces all PBoxes in a line
   * to have the same height. All PBoxes in the line should be constructed
   * with this flag
   */
  public static final int ROW_ALIGN = 8;
  // static parameters (set by setParameters())
  protected static GC gc = null; // GC used thoughout the drawing system
  protected static Point pixelPerCm = new Point(0, 0);
  protected static Point pixelPerInch = new Point(0, 0);
  protected static Device device = null; // the Device on which the GC works.
  protected static int scalingPercent = 100; // The scaling factor (used for
  // previews in different sizes)
  // member variables
  // Misc:
  protected PContainer parent;
  protected PStyle boxStyle;
  protected boolean below;
  protected boolean rowAlign;
  protected int forcedHeight; // this variable is set to a value != 0 by
  // the layout method and determines a fixed pixel height
  // Positioning:
  protected PagePoint origin;
  protected int sizeCalculatedfor;
  protected double hWeight; // -1 = fixed width, see minCm.
  protected double minCm; // -1 = occupy existing space
  protected boolean grabbing;
  protected int grabWidth; // set by the layout function
  // which is able to calculate the width
  // of grabbing poxes.
  // Constructors
  /**
   * Constructs a Box with default size below the previous one.
   */
  public PBox(PContainer parent) {
    this.parent = parent;
    if (parent != null)
      parent.addChild(this);
    boxStyle = PStyle.getDefaultStyle();
    below = true;
    rowAlign = false;
    origin = new PagePoint();
    sizeCalculatedfor = 0;
    grabbing = false;
    grabWidth = 0;
    hWeight = -1;
    minCm = 0.0;
    forcedHeight = 0;
  }
  /**
   * Constructs a Box with default size.
   * 
   * @param parent
   * @param style
   *            Poition: POS_BELOW or POS_RIGHT.
   */
  public PBox(PContainer parent, int style) {
    this(parent);
    below = true;
    if ((style & POS_RIGHT) > 0)
      below = false;
    if ((style & POS_BELOW) > 0)
      below = true;
    if ((style & GRAB) > 0)
      grabbing = true;
    if ((style & ROW_ALIGN) > 0)
      rowAlign = true;
  }
  /**
   * Constructs a Box with default size.
   * 
   * @param parent
   * @param style
   *            Poition: POS_BELOW or POS_RIGHT. Also GRAB and/or ROW_ALIGN.
   * @param hWeight
   *            Determines, how much of the existing page width should be
   *            occupied. 1.0 = full page. -1 = fiexed width, see minCm.
   * @param minCm
   *            Minimum width in cm. If > 0.0, the box will at least have this
   *            width.
   */
  public PBox(PContainer parent, int style, double hWeight, double minCm) {
    this(parent, style);
    this.hWeight = hWeight;
    this.minCm = minCm;
  }
  public void dispose() {
    parent.children.remove(this);
  }
  /*
   * Sets the forced height. This means that the PBox will have this height
   * (in pixel) regardless of how high it wants to be.
   */
  protected void setForcedHeight(int height) {
    forcedHeight = height;
  }
  public void draw(int page, Point originOffset) {
    Point originForDrawing = new Point(this.origin.x + originOffset.x,
        this.origin.y + originOffset.y);
    if (layoutIsOnPage(page)) {
      int width = getWidth();
      int height = getHeight(page);
      gc.setBackground(boxStyle.getBackColor());
      gc.fillRectangle(originForDrawing.x, originForDrawing.y, width,
          height);
      gc.setBackground(boxStyle.getLineColor());
      if (boxStyle.hasLine(0)) {
        gc.fillRectangle(originForDrawing.x, originForDrawing.y, width,
            boxStyle.getLineWidth(0));
      }
      if (boxStyle.hasLine(1)) {
        gc.fillRectangle(originForDrawing.x + width
            - boxStyle.getLineWidth(1), originForDrawing.y,
            boxStyle.getLineWidth(1), height);
      }
      if (boxStyle.hasLine(2)) {
        gc.fillRectangle(originForDrawing.x, originForDrawing.y
            + height - boxStyle.getLineWidth(2), width, boxStyle
            .getLineWidth(2));
      }
      if (boxStyle.hasLine(3)) {
        gc.fillRectangle(originForDrawing.x, originForDrawing.y,
            boxStyle.getLineWidth(3), height);
      }
      gc.setBackground(boxStyle.getBackColor());
    }
  }
  /**
   * Returns the elements PDocument.
   * 
   * @return PDocument
   */
  public PDocument getDocument() {
    return parent.doc;
  }
  // /////////////////////////////////////////////////////////////////
  // LAYOUT API
  // /////////////////////////////////////////////////////////////////
  /*
   * Some elements can occupy more than one Page. Therefore this function
   * tests if the element has a part on the given page. @param page @return
   * boolean
   */
  protected boolean layoutIsOnPage(int page) {
    return (page == origin.page);
  }
  /*
   * Returns the space in y-direction the Element would occupy of the rest of
   * the page if told so. Convention: this method can be called several times
   * for one page, but only until layoutOccupy is called once for this page.
   * @param spaceLeft @return int -1, if the element deciedes not to have any
   * part on the given page
   */
  protected int layoutHowMuchWouldYouOccupyOf(Point spaceLeft, int page) {
    if (layoutAlreadyFinished())
      return 0;
    if (getHeight() > spaceLeft.y)
      return -1;
    return getHeight();
  }
  protected boolean layoutAlreadyFinished() {
    return origin.page > 0;
  }
  /*
   * Returns true if the box would fit or at least finish into/within the
   * given space in y-direction. Convention: this method can be called several
   * times for one page, but only until layoutOccupy is called once for this
   * page. @param spaceLeft
   */
  protected boolean layoutWouldYouFinishWithin(Point spaceLeft, int page) {
    if (getHeight() > spaceLeft.y)
      return false;
    return true;
  }
  /*
   * Tells the element to occupy the given space on the page. Returns the
   * space in y-direction the Element occupys of the rest of the page.
   * Convention: this method is only called once for one page, and after this
   * call there will be no further layoutHowMuchWouldYouOccpy-calls for this
   * page. @param spaceLeft @return int
   */
  protected int layoutOccupy(Point origin, Point spaceLeft, int page) {
    if (!layoutAlreadyFinished()) {
      this.origin.page = page;
      this.origin.x = origin.x;
      this.origin.y = origin.y;
    }
    return getHeight();
  }
  /*
   * use this method to make all tuning variables unvalid and so force a
   * recalculation of these variables.
   */
  protected void layoutResetTuning() {
    sizeCalculatedfor = 0;
    origin.page = 0;
    forcedHeight = 0;
  }
  /*
   * Gives the horizontal size of the element. (has only to work AFTER the
   * layout process, is used by draw().)
   */
  protected int getWidth() {
    if (grabbing)
      return grabWidth;
    if (hWeight < 0)
      return pixelX(minCm);
    return Math.max(pixelX(minCm), pixelX(parent.getPossibleWidth()
        * hWeight));
  }
  /*
   * Gives the vertical size of the element. Used by all layout* functions. If
   * multipage functionallity is needed, this mechanism does no longer work.
   * Use/overwrite getHeight(int page) instead.
   */
  protected int getHeight() {
    if (forcedHeight > 0)
      return forcedHeight;
    return 0;
  }
  protected int getHeight(int page) {
    if (origin.page == page) {
      if (rowAlign)
        return forcedHeight;
      return getHeight();
    }
    return 0;
  }
  // /////////////////////////////////////////////////////////////////
  // STATIC API
  // /////////////////////////////////////////////////////////////////
  protected static int pixelX(double cm) {
    long tmp = Math.round(cm * pixelPerCm.x * scalingPercent / 100);
    return (int) tmp;
  }
  protected static int pixelY(double cm) {
    long tmp = Math.round(cm * pixelPerCm.y * scalingPercent / 100);
    return (int) tmp;
  }
  /**
   * Sets the main parameters for a document to print.
   * 
   * @param theGC
   * @param theDevice
   * @param dpi
   */
  public static void setParameters(GC theGC, Device theDevice, Point dpi,
      int percent) {
    gc = theGC;
    device = theDevice;
    scalingPercent = percent;
    pixelPerInch = dpi;
    pixelPerCm = new Point((int) Math.round(dpi.x / 2.54), (int) Math
        .round(dpi.y / 2.54));
  }
  /**
   * @return PStyle
   */
  public PStyle getBoxStyle() {
    return boxStyle;
  }
  /**
   * Sets the boxStyle.
   * 
   * @param boxStyle
   *            The boxStyle to set
   */
  public void setBoxStyle(PStyle boxStyle) {
    this.boxStyle = boxStyle;
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * A static data storage and a GUI dialog to change the data. PDocument uses the
 * settings of the static variables in PageSetup. You can open a Dialog to
 * changes these values by creating a PageSetup and call the open() function.
 * 
 * @author Friederich Kupzog
 */
class PageSetup extends KDialog {
  protected Composite root;
  private Combo combFormat, cmbScalierung, cmbMargin;
  private Button butPortrait, butLandscape;
  public final static int MARGIN_SMALL = 0;
  public final static int MARGIN_MEDIUM = 1;
  public final static int MARGIN_HUGE = 2;
  public final static String[] formatNames = { "A3", "A4", "A5" };
  public final static String[] scalings = { "100%", "90%", "80%", "70%",
      "60%", "50%" };
  public static double paperHeight = 29.6;
  public static double paperWidth = 20.6;
  public static String format = "A4";
  public static boolean portrait = true;
  public static int scaling = 100;
  public static int marginStyle = MARGIN_MEDIUM;
  public PageSetup(Shell parent) {
    super(parent, "Seite einrichten", IconSource.getImage("print"));
    createContents();
    setDialogImage(IconSource.getImage("SeiteEinrichten"));
    addButtonRight("OK", "", true);
    addButtonRight("Abbrechen", "");
    combFormat.setText(format);
  }
  public int getShellStyle() {
    return SWT.CLOSE | SWT.APPLICATION_MODAL;
  }
  protected void createContents() {
    guiMainArea.setLayout(new FillLayout());
    root = new Composite(guiMainArea, SWT.NONE);
    final GridLayout gridLayout = new GridLayout();
    gridLayout.verticalSpacing = 10;
    gridLayout.numColumns = 2;
    root.setLayout(gridLayout);
    {
      final Label l = new Label(root, SWT.NONE);
      l.setText("Papierformat:");
      final GridData gridData_2 = new GridData();
      gridData_2.widthHint = 80;
      l.setLayoutData(gridData_2);
    }
    {
      combFormat = new Combo(root, SWT.BORDER | SWT.READ_ONLY);
      combFormat
          .setToolTipText("Bestimmt die PapiergroBe. Diese muss mit der Druckereinstellung ubereinstimmen.");
      for (int i = 0; i < formatNames.length; i++) {
        combFormat.add(formatNames[i]);
      }
      combFormat.setText(format);
      final GridData gridData_1 = new GridData(GridData.FILL_HORIZONTAL);
      gridData_1.widthHint = 180;
      combFormat.setLayoutData(gridData_1);
    }
    {
      final Label label = new Label(root, SWT.NONE);
      label.setText("Seitenrander:");
      label.setLayoutData(new GridData(GridData.FILL_BOTH));
    }
    {
      cmbMargin = new Combo(root, SWT.READ_ONLY);
      cmbMargin.setToolTipText("Bestimmt die Breite der Rander.");
      cmbMargin.add("Schmale Rander");
      cmbMargin.add("Normale Rander");
      cmbMargin.add("Breite Rander");
      cmbMargin.select(marginStyle);
      cmbMargin.setLayoutData(new GridData(GridData.FILL_BOTH));
    }
    {
      final Label label = new Label(root, SWT.NONE);
      final GridData gridData = new GridData(
          GridData.VERTICAL_ALIGN_BEGINNING);
      gridData.horizontalSpan = 1;
      label.setLayoutData(gridData);
      label.setText("Ausrichtung:");
    }
    {
      butPortrait = new Button(root, SWT.RADIO);
      butPortrait
          .setToolTipText("Bestimmt, ob das Papier hochkant oder Breit bedruckt werden soll. \nDiese Einstellung muss mit der des Druckers ubereinstimmen");
      butPortrait.setLayoutData(new GridData(
          GridData.VERTICAL_ALIGN_BEGINNING));
      butPortrait.setText("Hochformat");
      butPortrait.setSelection(portrait);
    }
    {
      final Label label = new Label(root, SWT.NONE);
    }
    {
      butLandscape = new Button(root, SWT.RADIO);
      butLandscape.setLayoutData(new GridData(
          GridData.VERTICAL_ALIGN_BEGINNING));
      butLandscape.setText("Breitformat");
      butLandscape.setSelection(!portrait);
      butLandscape
          .setToolTipText("Bestimmt, ob das Papier hochkant oder quer bedruckt werden soll. \nDiese Einstellung muss mit der des Druckers ubereinstimmen");
    }
    {
      final Label label = new Label(root, SWT.NONE);
      label.setText("Skalierung:");
      label.setLayoutData(new GridData(GridData.FILL_BOTH));
    }
    {
      cmbScalierung = new Combo(root, SWT.READ_ONLY);
      cmbScalierung.setItems(scalings);
      cmbScalierung.select(10 - (scaling / 10));
      cmbScalierung.setLayoutData(new GridData(GridData.FILL_BOTH));
      cmbScalierung
          .setToolTipText("Hiermit konnen Sie dir GroBe des Ausdrucks veringern, so daB mehr auf eine Seite passt.");
    }
  }
  /*
   * overridden from superclass
   */
  protected void onButton(Button button, String buttonText) {
    if (buttonText.equals("OK")) {
      saveSettings();
    }
    close();
  }
  protected void saveSettings() {
    format = combFormat.getText();
    scaling = 100 - 10 * (cmbScalierung.getSelectionIndex());
    marginStyle = cmbMargin.getSelectionIndex();
    portrait = butPortrait.getSelection();
    if (portrait) {
      paperHeight = getPaperHeightInCm(format);
      paperWidth = getPaperWidthInCm(format);
    } else {
      paperWidth = getPaperHeightInCm(format);
      paperHeight = getPaperWidthInCm(format);
    }
  }
  public static double getPaperHeightInCm(String formatName) {
    if (formatName.equals("A5")) {
      return 20.8;
    } else if (formatName.equals("A4")) {
      return 29.6;
    } else if (formatName.equals("A3")) {
      return 41.6;
    }
    return 1.0;
  }
  public static double getPaperWidthInCm(String formatName) {
    if (formatName.equals("A5")) {
      return 14.8;
    } else if (formatName.equals("A4")) {
      return 20.6;
    } else if (formatName.equals("A3")) {
      return 29.6;
    }
    return 1.0;
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * Used inside the KPrint implementation
 * 
 * @author Friederich Kupzog
 */
class PagePoint {
  /**
   * 
   */
  public int page;
  public int x, y;
  public PagePoint() {
    x = 0;
    y = 0;
    page = 0;
  }
  public PagePoint(Point p, int page) {
    x = p.x;
    y = p.y;
    this.page = page;
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * A Message Box class used to display messages.
 * 
 * @author Friederich Kupzog
 */
class MsgBox {
  /**
   * 
   */
  private Display d;
  private Shell s;
  private Label bild, meldung;
  private Control additionalControl;
  private boolean ende;
  /**
   * Der Text des Buttons, der vom Benutzer betatigt wurde
   */
  public String pressedButton;
  public MsgBox(Display d, String title, String message, String buttons) {
    this.d = d;
    this.s = new Shell(d, SWT.TITLE | SWT.APPLICATION_MODAL);
    this.s.setText(title);
    additionalControl = null;
    ende = false;
    FormLayout fl = new FormLayout();
    this.s.setLayout(fl);
    bild = new Label(this.s, SWT.LEFT);
    bild.setImage(IconSource.getImage("MsgBox"));
    bild.setBackground(d.getSystemColor(SWT.COLOR_WHITE));
    FormData f = new FormData();
    f.top = new FormAttachment(0, 0);
    f.left = new FormAttachment(0, 0);
    f.bottom = new FormAttachment(100, 0);
    bild.setLayoutData(f);
    Label separator = new Label(this.s, SWT.SEPARATOR);
    f = new FormData();
    f.top = new FormAttachment(0, 0);
    f.left = new FormAttachment(bild, 0);
    f.bottom = new FormAttachment(100, 0);
    separator.setLayoutData(f);
    meldung = new Label(s, SWT.LEFT | SWT.WRAP);
    meldung.setText(message);
    f = new FormData();
    f.top = new FormAttachment(0, 25);
    f.left = new FormAttachment(bild, 25);
    f.right = new FormAttachment(100, -25);
    f.bottom = new FormAttachment(100, -55);
    meldung.setLayoutData(f);
    ButtonBar butBar = new ButtonBar(s, 80);
    StringTokenizer t = new StringTokenizer(buttons, ",");
    boolean first = true;
    while (t.hasMoreTokens()) {
      Button but = butBar.addButton(t.nextToken(), "",
          new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
              pressedButton = ((Button) e.getSource()).getText();
              ende = true;
            }
          });
      if (first) {
        first = false;
        s.setDefaultButton(but);
      }
    }
    f = new FormData();
    f.bottom = new FormAttachment(100, -4);
    f.left = new FormAttachment(bild, 15);
    f.right = new FormAttachment(100, -15);
    butBar.setLayoutData(f);
  }
  /**
   * Erlaubt das Hinzufugen weiterer Steuerelemente zur MsgBox. Diese werden
   * unter dem Text und uber der Buttonleiste engezeigt.
   * 
   * Benutzung: MsgBox box = new MsgBox(display,"Box","Beispiel","OK"); Text
   * feld = new Text(box.getShell(),SWT.BORDER); box.addControl(feld);
   * box.open(); (hier Zugriff auf feld) box.dispose();
   * 
   * @param c
   *            das anzuzeigende Control.
   */
  public void addControl(Control c) {
    // Meldung neu abstutzen
    FormData f = new FormData();
    f.top = new FormAttachment(0, 25);
    f.left = new FormAttachment(bild, 25);
    f.right = new FormAttachment(100, -25);
    // f.bottom = new FormAttachment(100,-55);
    meldung.setLayoutData(f);
    // Neues Control layouten
    f = new FormData();
    f.top = new FormAttachment(meldung, 5);
    f.left = new FormAttachment(bild, 25);
    f.right = new FormAttachment(100, -25);
    f.bottom = new FormAttachment(100, -55);
    c.setLayoutData(f);
    additionalControl = c;
  }
  public void setImage(Image newImg) {
    bild.setImage(newImg);
  }
  /**
   * Gibt die Shell der MsgBox zuruck.
   * 
   * @return Shell
   */
  public Shell getShell() {
    return s;
  }
  /**
   * Zeigt die MsgBox an.
   */
  public void open() {
    s.pack();
    s.setLocation((d.getBounds().width - s.getBounds().width) / 2, (d
        .getBounds().height - s.getBounds().height) / 2);
    s.open();
    if (additionalControl != null)
      additionalControl.setFocus();
    while (!ende) {
      if (!d.readAndDispatch())
        d.sleep();
    }
  }
  /**
   * Muss nach box.open() aufgerufen werden!
   */
  public void dispose() {
    s.close();
    s.dispose();
  }
  /**
   * Baut eine fertige MsgBox auf und zeigt diese an.
   * 
   * @param d
   * @param title
   * @param message
   * @param buttons
   * @return String
   */
  public static String show(Display d, String title, String message,
      String buttons) {
    MsgBox box = new MsgBox(d, title, message, buttons);
    box.open();
    box.dispose();
    return box.pressedButton;
  }
  /**
   * Baut eine fertige MsgBox auf und zeigt diese an
   * 
   * @param d
   * @param message
   * @return String
   */
  public static String show(Display d, String message) {
    return show(d, "Meldung", message, "OK");
  }
  public static String show(String title, String message, String buttons) {
    MsgBox box = new MsgBox(Display.getCurrent(), title, message, buttons);
    box.open();
    box.dispose();
    return box.pressedButton;
  }
  public static String show(String message) {
    return show("Meldung", message, "OK");
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
class KPrintExample {
  /**
   * This example shows how to create well-layouted text and graphics using
   * KPrint classes. The layout is completely paper-format independent and
   * works with different paper sizes. (Try it by selecting A3 / A5 in the
   * page setup dialog)
   */
  private Display d;
  public KPrintExample() {
    d = new Display();
    // we call the page setup dialog so that the user can
    // do adjustments if he likes.
    // In an application with a main window and a menu bar
    // this should not be neccessary.
    PageSetup p = new PageSetup(null);
    p.open();
    // Now we create an example document using the page setup settings
    PDocument doc = new PDocument("KPrint example");
    // the following functions create the text
    generateHeader(doc);
    generateFooter(doc);
    generateTitle(doc);
    generateSubtitle(doc, "Introduction");
    generateParagraph(
        doc,
        "KPrint is a collection of Java classes that allows "
            + "the user to generate print layouts within the SWT framework. The way "
            + "a layout is created is comparable to the "
            + "technique used to generate GUI layouts in SWT. You have some "
            + "global container (Shell in SWT, PDocument in KPrint), on which "
            + "you can place other elements (PBoxes).");
    generateSubtitle(doc, "The KPrint layout concept");
    generateParagraph(
        doc,
        "In SWT, you use Layouts "
            + "to determine how the widgets are arranged on the window. KPrint "
            + "has just one simple layout concept.");
    generateParagraph(
        doc,
        "The elements you can place on the paper are text "
            + "boxes, images, lines and whitespace. "
            + "One element can either be on the right of the previous element or below "
            + "the previous line of elements.");
    generateImage(
        doc,
        "/gfx/fig1.gif",
        "Figure 1: The position of an element is "
            + "relative to the position of the previous element and determined by "
            + "the style flag which can be PBox.POS_RIGHT or PBox.POS_BELOW.");
    generateParagraph(
        doc,
        "This layout concept is both simple but powerful. "
            + "There are some layouts that cannot be generated by this concept, "
            + "but in most cases one can find a simpler solution that is possible "
            + "to describe with the KPrint layout concept.");
    new PPageBreak(doc);
    generateSubtitle(doc, "This Text as a KPrint example");
    generateParagraph(
        doc,
        "This text is created using the KPrint framework. "
            + "It shows that KPrint can be used to layout long text passages, e.g. "
            + "to print help system contents. ");
    generateImage(
        doc,
        "/gfx/fig2.gif",
        "Figure 2: For right adjusted elements "
            + "you need to put a grabbing PPox, e.g. a PHSpace or a PTextBox in front "
            + "of them. For an example see the header of this document.");
    generateSubtitle(doc, "Printing KTables");
    generateParagraph(
        doc,
        "KPrint offers the PTable class that allows to print KTables. "
            + "(for more information about KTable see de.kupzog.ktable, www.kupzog.de/fkmk_uk) "
            + "All you need to print a table is a KTableModel and a PTableBoxProvider. "
            + "The KTableModel offers the data and the column size information. The "
            + "box provider is comparable to a cell renderer. It creates a PBox for "
            + "each table cell. You can use a default box provider which creates "
            + "a PLittleTextBox or you can implement your own box provider with "
            + "custom font, colors, borders or that provides PImageBoxes. See the "
            + "PrintKTableExample class for an example how to print data from a "
            + "KTableModel. You need the KTable.jar from www.kupzog.de/fkmk_uk "
            + "on your classpath to be able to compile this example. ");
    generateParagraph(
        doc,
        "Printing a Table works like that: you just add "
            + "a PTable object to your document and set its table model and box "
            + "provider. When the document is layouted, the layout function replaces "
            + "the PTable object by PBoxes that are fetched from the box "
            + "provider for each table cell.");
    generateSubtitle(doc, "Printing SWT Tables");
    generateParagraph(
        doc,
        "KPrint offers also the possibility to print "
            + "the PTable SWT tables. It works pretty much like printing KTables, but "
            + "you will use thw SWTPTable class instead of PTable. Thanks to Onsel Armagan in "
            + "Istanbul, Turkey for his feature.");
    // at last we can open a print preview
    PrintPreview pr = new PrintPreview(null, "Test", IconSource
        .getImage("print"), doc);
    pr.open();
    d.dispose();
  }
  private void generateHeader(PDocument doc) {
    PTextBox t;
    // We want the companie"s logo right-adjusted on the first page
    // - to right-adjust the logo and the text,
    // we need a flexible (grabbing) filler.
    // This can be done with an empty text box.
    new PHSpace(doc.getFirstHeader(), PBox.GRAB, 0);
    // - the logo itself
    PImageBox i = new PImageBox(doc.getFirstHeader(), PBox.POS_RIGHT);
    i.setImage("/gfx/fkmk.gif", 96);
    // - some horizontal space between logo and text
    new PHSpace(doc.getFirstHeader(), PBox.POS_RIGHT, 0.2);
    // - a little Text
    t = new PTextBox(doc.getFirstHeader(), PBox.POS_RIGHT, 0, 3.4);
    t
        .setText("Friederich Kupzog\nElectronics & Software\nfkmk@kupzog.de\nwww.kupzog.de/fkmk");
    t.getTextStyle().fontSize = 9;
    // - some vertical space below
    new PVSpace(doc.getFirstHeader(), 1);
  }
  private void generateFooter(PDocument doc) {
    PTextBox box;
    // a line
    new PVSpace(doc.getFirstFooter(), 0.4);
    new PHLine(doc.getFirstFooter());
    new PVSpace(doc.getFirstFooter(), 0.4);
    // a flexible filler for right-adjustment
    box = new PTextBox(doc.getFirstFooter(), PBox.POS_BELOW | PBox.GRAB);
    box.setText("Generated by KPrintExample.java");
    // the page number
    box = new PPageNumber(doc.getFirstFooter(), PBox.POS_RIGHT);
    // this shall be on all pages:
    doc.setAllFootersLikeFirst();
  }
  private void generateSubtitle(PDocument doc, String text) {
    PTextBox t;
    // some vertical space
    new PVSpace(doc, 0.2);
    // the subtitle"s text
    t = new PTextBox(doc, PBox.POS_BELOW);
    t.setText(text);
    t.getTextStyle().fontSize = 12;
    t.getTextStyle().fontStyle = SWT.BOLD;
    // some vertical space
    new PVSpace(doc, 0.2);
  }
  private void generateParagraph(PDocument doc, String text) {
    PTextBox t;
    // some margin for the text
    new PHSpace(doc, PBox.POS_BELOW, 2);
    // the text grabs the rest of the page width
    t = new PTextBox(doc, PBox.POS_RIGHT | PBox.GRAB);
    t.setText(text);
    t.getTextStyle().fontSize = 10;
    // some vertical space
    new PVSpace(doc, 0.2);
  }
  private void generateImage(PDocument doc, String imgName, String text) {
    PTextBox t;
    // some vertical space
    new PVSpace(doc, 0.3);
    // some margin for the image
    new PHSpace(doc, PBox.POS_BELOW, 2);
    PImageBox i = new PImageBox(doc, PBox.POS_RIGHT);
    i.setImage(imgName, 96);
    // some margin for the text
    new PVSpace(doc, 0.3);
    new PVSpace(doc, 0.0);
    new PHSpace(doc, PBox.POS_BELOW, 2);
    // the text grabs the rest of the page width
    t = new PTextBox(doc, PBox.POS_RIGHT | PBox.GRAB);
    t.setText(text);
    t.getTextStyle().fontSize = 8;
    t.getTextStyle().fontStyle = SWT.BOLD;
    t.getTextStyle().fontColor = SWT.COLOR_DARK_GRAY;
    new PVSpace(doc, 0.3);
  }
  private void generateTitle(PDocument doc) {
    PTextBox t;
    t = new PTextBox(doc, PBox.POS_BELOW);
    t.setText("Creating print layouts using KPrint");
    t.getTextStyle().fontSize = 15;
    // a line below the text
    new PVSpace(doc, 0.2);
    new PHLine(doc, 0.02, SWT.COLOR_BLACK);
    new PVSpace(doc, 1);
  }
  public static void main(String[] args) {
    new KPrintExample();
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * This class is intended for subclassing.
 * 
 * It offers functionality for displaying a picture in the dialog"s header and
 * for adding buttons (right- and left-adjusted) in the dialogs footer.
 * Additionally, it offers an easy tool bar creating mechanism.
 * 
 * The events generated by buttons and toolitems can be handled in the method
 * onButton and onToolItem.
 * 
 * If not changed by the customer, the main Layout guiMainLayout has a
 * gridLayout(). Overwrite createMainAreaLayout() to change that.
 * 
 * @author Friederich Kupzog
 */
class KDialog {
  /**
   * 
   */
  protected Shell guiShell;
  protected Display guiDisplay;
  protected Composite guiPictureArea;
  protected Composite guiToolBarArea;
  protected Composite guiMainArea;
  protected Composite guiButtonArea;
  protected Button guiLastLeftBut, guiLastRightBut;
  protected Control guiLastToolControl;
  protected Layout guiMainAreaLayout;
  protected Label guiPictureLabel;
  protected ToolBar guiToolBar;
  protected GridData guiPictureGridData;
  protected GridData guiToolBarGridData;
  /**
   * Cretaes a new, top level dialog.
   */
  public KDialog() {
    createShell(null);
  }
  /**
   * Creates a new Dialog.
   * 
   * @param parent
   *            The parent shell for this dialog.
   */
  public KDialog(Shell parent) {
    createShell(parent);
  }
  /**
   * Creates a new Dialog.
   * 
   * @param parent
   *            The parent shell for this dialog.
   * @param title
   *            The Dialog"s title
   */
  public KDialog(Shell parent, String title) {
    this(parent);
    setTitle(title);
  }
  /**
   * Creates a new Dialog.
   * 
   * @param parent
   *            The parent shell for this dialog.
   * @param title
   *            The Dialog"s title
   * @param icon
   *            The dialog"s window icon.
   */
  public KDialog(Shell parent, String title, Image icon) {
    this(parent);
    setTitle(title);
    setShellImage(icon);
  }
  /*
   * Baut das Shell-Objekt auf und die Composits der 1. Ebene
   */
  protected void createShell(Shell parent) {
    guiDisplay = Display.getCurrent();
    // Shell
    if (parent != null)
      guiShell = new Shell(parent, getShellStyle());
    else
      guiShell = new Shell(Display.getCurrent(), getShellStyle());
    createShellLayout();
    createShellComposits();
  }
  protected void createShellComposits() {
    // picture area
    guiPictureArea = new Composite(guiShell, SWT.NONE);
    guiPictureGridData = new GridData();
    guiPictureGridData.grabExcessHorizontalSpace = true;
    guiPictureGridData.horizontalAlignment = GridData.FILL;
    guiPictureGridData.heightHint = 0;
    guiPictureArea.setLayoutData(guiPictureGridData);
    // ToolBar area
    guiToolBarArea = new Composite(guiShell, SWT.NONE);
    guiToolBarGridData = new GridData();
    guiToolBarGridData.grabExcessHorizontalSpace = true;
    guiToolBarGridData.horizontalAlignment = GridData.FILL;
    guiToolBarGridData.heightHint = 0;
    guiToolBarArea.setLayoutData(guiToolBarGridData);
    // main area
    guiMainArea = new Composite(guiShell, SWT.NONE);
    createMainAreaLayout();
    GridData gd = new GridData();
    gd.grabExcessHorizontalSpace = true;
    gd.horizontalAlignment = GridData.FILL;
    gd.grabExcessVerticalSpace = true;
    gd.verticalAlignment = GridData.FILL;
    guiMainArea.setLayoutData(gd);
    // button area
    createButtonBar();
  }
  protected void createButtonBar() {
    // AuBeres Composite
    guiButtonArea = new Composite(guiShell, SWT.NONE);
    GridData gd = new GridData();
    gd.grabExcessHorizontalSpace = true;
    gd.horizontalAlignment = GridData.FILL;
    guiButtonArea.setLayoutData(gd);
    FormLayout butLayout = new FormLayout();
    guiButtonArea.setLayout(butLayout);
    // Trennlinie
    Label sep = new Label(guiButtonArea, SWT.SEPARATOR | SWT.HORIZONTAL);
    FormData fd = new FormData();
    fd.bottom = new FormAttachment(100, -32);
    fd.left = new FormAttachment(0, 0);
    fd.right = new FormAttachment(100, 0);
    sep.setLayoutData(fd);
  }
  protected void createMainAreaLayout() {
    guiMainAreaLayout = new GridLayout();
    ((GridLayout) guiMainAreaLayout).makeColumnsEqualWidth = false;
    ((GridLayout) guiMainAreaLayout).numColumns = 1;
    guiMainArea.setLayout(guiMainAreaLayout);
  }
  /**
   * Factorymethod for pre-configured GridData objects
   * 
   * Configurates: grabExcessHorizontalSpace = true horizontalAlignment =
   * GridData.BEGINNING
   * 
   * @return GridData
   */
  public static GridData createGridData() {
    GridData gd = new GridData();
    gd.grabExcessHorizontalSpace = true;
    gd.horizontalAlignment = GridData.BEGINNING;
    return gd;
  }
  /**
   * Factorymethod for pre-configured GridData objects
   * 
   * Configurates: grabExcessHorizontalSpace = true horizontalAlignment =
   * GridData.BEGINNING heightHint = hint
   * 
   * @return GridData
   */
  public static GridData createGridDataHHint(int hint) {
    GridData gd = new GridData();
    gd.grabExcessHorizontalSpace = true;
    gd.heightHint = hint;
    gd.horizontalAlignment = GridData.BEGINNING;
    return gd;
  }
  /**
   * Factorymethod for pre-configured GridData objects
   * 
   * Configurates: grabExcessHorizontalSpace = true horizontalAlignment =
   * GridData.FILL horizontalSpan = columns verticalAlignment = GridData.FILL
   * 
   * @return GridData
   */
  public static GridData createGridDataFill(int columns) {
    GridData gd = new GridData();
    gd.grabExcessHorizontalSpace = true;
    gd.horizontalAlignment = GridData.FILL;
    gd.verticalAlignment = GridData.FILL;
    gd.horizontalSpan = columns;
    return gd;
  }
  /**
   * Factorymethod for pre-configured GridData objects
   * 
   * Configurates: grabExcessHorizontalSpace = true horizontalAlignment =
   * GridData.FILL horizontalSpan = columns verticalAlignment = GridData.FILL
   * horizontalIndent = hIndent
   * 
   * @return GridData
   */
  public static GridData createGridDataFill(int columns, int hIndent) {
    GridData gd = new GridData();
    gd.grabExcessHorizontalSpace = true;
    gd.horizontalAlignment = GridData.FILL;
    gd.verticalAlignment = GridData.FILL;
    gd.horizontalSpan = columns;
    gd.horizontalIndent = hIndent;
    return gd;
  }
  protected void createShellLayout() {
    GridLayout layout = new GridLayout(1, true);
    guiShell.setLayout(layout);
    layout.horizontalSpacing = 0;
    layout.verticalSpacing = 0;
    layout.marginHeight = 0;
    layout.marginWidth = 0;
    guiShell.setLayout(layout);
  }
  /**
   * Returns the style of the dialog. Is also used during shell creation.
   * Overwrite this method to give your dialog another style.
   * 
   * @return int
   */
  public int getShellStyle() {
    return SWT.CLOSE | SWT.RESIZE;
  }
  /**
   * This method should create the dialogs GUI and is NOT called by the
   * KDialog constructor. Overwrite this method to build add your own widgets
   * to the dialog. Do not forget to call it in your own constructor.
   */
  protected void createContents() {
    /*
     * new Text(guiMainArea,SWT.BORDER); addButton("Ha!",""); addButton("Du
     * langer Button",""); addButtonRight("Close","");
     * addButtonRight("Komfort","",true);
     */
  }
  /**
   * Overwrite this method, if you whish your dioalog having a specific size
   * (use guiShell.setSize())
   */
  protected void doLayout() {
    guiShell.pack();
  }
  /**
   * This method opens the dialogs and processes events until the shell is
   * closed. You do not need to overwrite this method. Use close() to close
   * the dialog programmatically.
   */
  public void open() {
    doLayout();
    doPositioning();
    guiShell.open();
    while (!guiShell.isDisposed()) {
      if (!guiDisplay.readAndDispatch())
        guiDisplay.sleep();
    }
    guiShell.dispose();
  }
  public void close() {
    guiShell.close();
    guiShell.dispose();
  }
  /**
   * This method centers the dialog on the screen. Overwrite this method if
   * you whish another position.
   */
  protected void doPositioning() {
    guiShell
        .setLocation(
            (guiDisplay.getBounds().width - guiShell.getBounds().width) / 2,
            (guiDisplay.getBounds().height - guiShell.getBounds().width) / 2);
  }
  /**
   * Sets the icon of the shell.
   * 
   * @param image
   */
  public void setShellImage(Image image) {
    guiShell.setImage(image);
  }
  /**
   * Sets the window title.
   * 
   * @param title
   */
  public void setTitle(String title) {
    guiShell.setText(title);
  }
  /**
   * Sets the image displayed in the dialogs header.
   * 
   * @param image
   */
  public void setDialogImage(Image image) {
    guiPictureArea
        .setBackground(guiDisplay.getSystemColor(SWT.COLOR_WHITE));
    guiPictureGridData.heightHint = image.getBounds().height + 2;
    GridLayout layout = new GridLayout(1, true);
    guiPictureArea.setLayout(layout);
    layout.horizontalSpacing = 0;
    layout.verticalSpacing = 0;
    layout.marginHeight = 0;
    layout.marginWidth = 0;
    guiPictureLabel = new Label(guiPictureArea, SWT.NONE);
    guiPictureLabel.setImage(image);
    // guiPictureLabel.setBackground(guiDisplay.getSystemColor(SWT.COLOR_WHITE));
    GridData gd = new GridData();
    // gd.grabExcessHorizontalSpace = true;
    // gd.horizontalAlignment = GridData.FILL;
    guiPictureLabel.setLayoutData(gd);
    Label line = new Label(guiPictureArea, SWT.SEPARATOR | SWT.HORIZONTAL);
    gd = new GridData();
    gd.grabExcessHorizontalSpace = true;
    gd.horizontalAlignment = GridData.FILL;
    line.setLayoutData(gd);
  }
  /**
   * Adds a ToolItem to the dialog"s toolbar. Creates the toolbar if not
   * already done.
   * 
   * @param name
   *            The name if the ToolItem. Although this name is never
   *            displayed to the user you can use it in onToolItem to identify
   *            the activated ToolItem.
   * @param tooltip
   *            The item"s tooltip
   * @param icon
   *            The icon to show.
   * @return ToolItem The ToolItem created by this method.
   */
  public ToolItem addToolItem(String name, String tooltip, Image icon) {
    if (guiToolBar == null) {
      FormLayout layout = new FormLayout();
      guiToolBarArea.setLayout(layout);
      // layout.horizontalSpacing = 0;
      // layout.verticalSpacing = 0;
      layout.marginHeight = 0;
      layout.marginWidth = 0;
      guiToolBar = new ToolBar(guiToolBarArea, SWT.FLAT);
      FormData fd = new FormData();
      fd.left = new FormAttachment(0, 0);
      fd.top = new FormAttachment(0, 0);
      guiToolBar.setLayoutData(fd);
      Label line = new Label(guiToolBarArea, SWT.SEPARATOR
          | SWT.HORIZONTAL);
      fd = new FormData();
      fd.left = new FormAttachment(0, 0);
      fd.top = new FormAttachment(guiToolBar, 1);
      fd.right = new FormAttachment(100, 0);
      line.setLayoutData(fd);
      guiLastToolControl = guiToolBar;
    }
    ToolItem ti = new ToolItem(guiToolBar, SWT.PUSH);
    ti.setImage(icon);
    ti.setToolTipText(tooltip);
    ti.setEnabled(true);
    ti.setData(name);
    ti.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        onToolItem((ToolItem) e.widget, (String) e.widget.getData());
      }
    });
    guiToolBarGridData.heightHint = guiToolBarArea.ruputeSize(SWT.DEFAULT,
        SWT.DEFAULT).y;
    return ti;
  }
  public void adjustToToolBar(Control c) {
    FormData fd = new FormData();
    fd.left = new FormAttachment(guiLastToolControl, 2);
    fd.top = new FormAttachment(0, 1);
    fd.bottom = new FormAttachment(0, 22);
    c.setLayoutData(fd);
    guiLastToolControl = c;
  }
  protected Button addButton(boolean rightAdjusted, String text, String tip) {
    Button erg = new Button(guiButtonArea, SWT.PUSH);
    erg.setText(text);
    erg.setToolTipText(tip);
    Point butPrefferedSize = erg.ruputeSize(SWT.DEFAULT, SWT.DEFAULT);
    FormData fd = new FormData();
    fd.bottom = new FormAttachment(100, -3);
    if (butPrefferedSize.x > 70)
      fd.width = butPrefferedSize.x + 4;
    else
      fd.width = 70;
    fd.height = 24;
    erg.setLayoutData(fd);
    if (rightAdjusted) {
      if (guiLastRightBut == null)
        fd.right = new FormAttachment(100, -3);
      else
        fd.right = new FormAttachment(guiLastRightBut, -3);
      guiLastRightBut = erg;
    } else {
      if (guiLastLeftBut == null)
        fd.left = new FormAttachment(0, 3);
      else
        fd.left = new FormAttachment(guiLastLeftBut, 3);
      guiLastLeftBut = erg;
    }
    erg.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent arg0) {
        onButton((Button) arg0.widget, ((Button) arg0.widget).getText());
      }
    });
    return erg;
  }
  /**
   * Puts a Button into the button bar in the dialog"s footer (right
   * adjusted). To handle the event produced by this button see onButton().
   * 
   * @param text
   * @param toolTip
   * @return Button The Button produced by this method.
   */
  public Button addButtonRight(String text, String toolTip) {
    return addButton(true, text, toolTip);
  }
  /**
   * Puts a Button into the button bar in the dialog"s footer (left adjusted).
   * To handle the event produced by this button see onButton().
   * 
   * @param text
   * @param toolTip
   * @return Button The Button produced by this method.
   */
  public Button addButton(String text, String toolTip) {
    return addButton(false, text, toolTip);
  }
  /**
   * Puts a Button into the button bar in the dialog"s footer (right
   * adjusted). To handle the event produced by this button see onButton().
   * 
   * @param text
   * @param toolTip
   * @param isDefault
   *            if true, this button will become the default button
   * @return Button The Button produced by this method.
   */
  public Button addButtonRight(String text, String toolTip, boolean isDefault) {
    Button erg = addButton(true, text, toolTip);
    if (isDefault)
      guiShell.setDefaultButton(erg);
    return erg;
  }
  /**
   * Puts a Button into the button bar in the dialog"s footer (left adjusted).
   * To handle the event produced by this button see onButton().
   * 
   * @param text
   * @param toolTip
   * @param isDefault
   *            if true, this button will become the default button
   * @return Button The Button produced by this method.
   */
  public Button addButton(String text, String toolTip, boolean isDefault) {
    Button erg = addButton(false, text, toolTip);
    if (isDefault)
      guiShell.setDefaultButton(erg);
    return erg;
  }
  /*
   * Button-clicks call this method. Overwrite it to react on button clicks.
   */
  protected void onButton(Button button, String buttonText) {
  }
  /*
   * clicked ToolItems call this method. Overwrite it to react on button
   * clicks.
   */
  protected void onToolItem(ToolItem toolitem, String name) {
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * This Class is intended for a cebtral access to all icons used throughout the
 * package.
 * 
 * Alter the getImage() function, if you use other techniques of image access.
 * 
 */
class IconSource {
  /** Returns the requested Image */
  public static Image getImage(String name) {
    return loadImageResource(Display.getCurrent(), "/gfx/" + name + ".gif");
  }
  /**
   * reads an Image as ressource (either from file system or from a jar)
   */
  public static Image loadImageResource(Display d, String name) {
    try {
      Image ret = null;
      Class clazz = new Object().getClass();
      InputStream is = clazz.getResourceAsStream(name);
      if (is != null) {
        ret = new Image(d, is);
        is.close();
      }
      if (ret == null)
        System.out.println("Error loading bitmap:\n" + name);
      return ret;
    } catch (Exception e1) {
      System.out.println("Error loading bitmap:\n" + name);
      return null;
    }
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * This example shows the basic use of KPrint classes by creating a little 9 x
 * 13 cm greeting card.
 * 
 * @author Friederich Kupzog
 * 
 */
class GreetingCardExample {
  private Display d;
  public GreetingCardExample() {
    d = new Display();
    // create an example document 13 cm x 9 cm with 1 cm borders
    PDocument doc = new PDocument(13, 9, 1, 1, 1, 1, 1.0, "Greeting Card");
    // put some text on it
    PTextBox t;
    t = new PTextBox(doc);
    t.setText("MANY GREETINGS FROM KPRINT");
    new PVSpace(doc, 0.1);
    new PHLine(doc, 0.2, SWT.COLOR_DARK_GREEN);
    new PVSpace(doc, 0.5);
    t = new PTextBox(doc, PBox.POS_BELOW, 0, 5);
    t
        .setText("We spent a nice time in this 5cm wide left adjusted Textbox.");
    new PHSpace(doc, PBox.POS_RIGHT, 0.3);
    t = new PTextBox(doc, PBox.POS_RIGHT, 0, 5);
    t
        .setText("The climate was fine and we had a lot of bright views. The class hierachie is unforgetable. Bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla.");
    new PVSpace(doc, 1);
    t = new PTextBox(doc, PBox.POS_BELOW, 1.0, 0);
    t.setText("See you soon: your personal swt programmer on holiday.");
    // Border lines are counted clockwise starting at the top.
    t.getBoxStyle().lines[0] = 0.05; // top
    t.getBoxStyle().lines[2] = 0.05; // bottom
    t.getBoxStyle().lineColor = SWT.COLOR_DARK_GREEN;
    // start a new Page
    new PPageBreak(doc);
    // some more text
    new PHSpace(doc, PBox.POS_BELOW | PBox.GRAB, 0);
    t = new PTextBox(doc, PBox.POS_RIGHT, 0, 1.3);
    t.setText("Affix stamp here");
    t.getBoxStyle().lines[0] = 0.01;
    t.getBoxStyle().lines[1] = 0.01;
    t.getBoxStyle().lines[2] = 0.01;
    t.getBoxStyle().lines[3] = 0.01;
    t.getTextStyle().setMarginBottom(0.1);
    t.getTextStyle().setMarginTop(0.1);
    t.getTextStyle().setMarginLeft(0.1);
    t.getTextStyle().setMarginRight(0.1);
    // open the print preview on this document
    PrintPreview pr = new PrintPreview(null, "Test", IconSource
        .getImage("print"), doc);
    pr.open();
    // dispose the document in the end
    d.dispose();
  }
  /**
   * This function would print the document witout the print preview.
   * 
   * @param doc
   */
  public void print(PDocument doc) {
    PrintDialog dialog = new PrintDialog(null, SWT.BORDER);
    PrinterData data = dialog.open();
    if (data == null)
      return;
    if (data.printToFile) {
      data.fileName = "print.out"; // you probably want to ask the user
      // for a filename
    }
    Printer printer = new Printer(data);
    GC gc = new GC(printer);
    PBox.setParameters(gc, printer, printer.getDPI(), 100);
    if (printer.startJob("DoSys Druckauftrag")) {
      printer.startPage();
      doc.layout();
      doc.draw(1);
      printer.endJob();
    }
    gc.dispose();
  }
  public static void main(String[] args) {
    new GreetingCardExample();
  }
}
/*
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * This is an example KTableModel that can be printed using the
 * PrintKTableExample.
 * 
 * @author Kupzog
 */
class ExampleTableModel implements KTableModel {
  private final static String[][] content = {
      { "Name", "Kupzog", "Hansson", "Walter", "Hutton" },
      { "Town", "Cologne", "Ystadt", "London", "Brighton" },
      { "Interest", "programming", "hunting", "rafting", "painting" } };
  public Object getContentAt(int col, int row) {
    return content[col][row];
  }
  public KTableCellEditor getCellEditor(int col, int row) {
    return null;
  }
  public void setContentAt(int col, int row, Object value) {
  }
  public int getRowCount() {
    return 5;
  }
  public int getFixedRowCount() {
    return 1;
  }
  public int getColumnCount() {
    return 3;
  }
  public int getFixedColumnCount() {
    return 0;
  }
  public int getColumnWidth(int col) {
    return 130;
  }
  public boolean isColumnResizable(int col) {
    return false;
  }
  public void setColumnWidth(int col, int value) {
  }
  public int getRowHeight() {
    return 20;
  }
  public int getFirstRowHeight() {
    return 20;
  }
  public boolean isRowResizable() {
    return false;
  }
  public int getRowHeightMinimum() {
    return 20;
  }
  public void setRowHeight(int value) {
  }
  public KTableCellRenderer getCellRenderer(int col, int row) {
    return null;
  }
}
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
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Author: Friederich Kupzog fkmk@kupzog.de www.kupzog.de/fkmk
 */
/**
 * Used by MsgBox.
 * 
 * @author Friederich Kupzog
 */
class ButtonBar extends Composite {
  private RowLayout myLayout;
  private ArrayList myButtons;
  private int myButtonWidth;
  /** Erzeugt neuen ButtonBar */
  public ButtonBar(Composite owner, int buttonWidth) {
    super(owner, SWT.NONE);
    myButtonWidth = buttonWidth;
    myLayout = new RowLayout();
    myLayout.justify = true;
    myLayout.type = SWT.HORIZONTAL;
    myLayout.wrap = true;
    myLayout.spacing = 4;
    this.setLayout(myLayout);
    myButtons = new ArrayList();
  }
  /**
   * Fugt einen Button zur Leiste hinzu. Gibt eine Referenz auf den angelegten
   * Button zuruck.
   */
  public Button addButton(String name, String toolTip,
      SelectionListener selListener) {
    Button b = new Button(this, SWT.PUSH);
    b.setText(name);
    b.setToolTipText(toolTip);
    b.setLayoutData(new RowData(myButtonWidth, 25));
    if (selListener != null)
      b.addSelectionListener(selListener);
    myButtons.add(b);
    return b;
  }
  /**
   * Fugt einen Button zur Leiste hinzu, und registriert ihn bei der in
   * myShell ubergebenen Shell als DefaultButton.
   */
  public Button addButton(String name, String toolTip, Shell myShell,
      SelectionListener selListener) {
    Button b = addButton(name, toolTip, selListener);
    myShell.setDefaultButton(b);
    return b;
  }
}
/*******************************************************************************
 * 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
 ******************************************************************************/
/*******************************************************************************
 * 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();
  }
}





Print selected items in a SWT table

/*
 * Table example snippet: print selected items in a table
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class Snippet64 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    final Table table = new Table(shell, SWT.BORDER | SWT.MULTI
        | SWT.V_SCROLL);
    for (int i = 0; i < 16; i++) {
      TableItem item = new TableItem(table, 0);
      item.setText("Item " + i);
    }
    table.setBounds(0, 0, 100, 100);
    table.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event e) {
        String string = "";
        TableItem[] selection = table.getSelection();
        for (int i = 0; i < selection.length; i++)
          string += selection[i] + " ";
        System.out.println("Selection={" + string + "}");
      }
    });
    table.addListener(SWT.DefaultSelection, new Listener() {
      public void handleEvent(Event e) {
        String string = "";
        TableItem[] selection = table.getSelection();
        for (int i = 0; i < selection.length; i++)
          string += selection[i] + " ";
        System.out.println("DefaultSelection={" + string + "}");
      }
    });
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Remove selected items in a SWT table

/*
 * Table example snippet: remove selected items
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class Snippet53 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    final Table table = new Table(shell, SWT.BORDER | SWT.MULTI);
    table.setSize(200, 200);
    for (int i = 0; i < 128; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText("Item " + i);
    }
    Menu menu = new Menu(shell, SWT.POP_UP);
    table.setMenu(menu);
    MenuItem item = new MenuItem(menu, SWT.PUSH);
    item.setText("Delete Selection");
    item.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        table.remove(table.getSelectionIndices());
      }
    });
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Reorder columns and reorder columns programmatically

/*
 * Allow user to reorder columns and reorder columns programmatically.
 * 
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class Snippet181 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new RowLayout(SWT.HORIZONTAL));
    final Table table = new Table(shell, SWT.BORDER | SWT.CHECK);
    table.setLayoutData(new RowData(-1, 300));
    table.setHeaderVisible(true);
    TableColumn column = new TableColumn(table, SWT.LEFT);
    column.setText("Column 0");
    column = new TableColumn(table, SWT.CENTER);
    column.setText("Column 1");
    column = new TableColumn(table, SWT.CENTER);
    column.setText("Column 2");
    column = new TableColumn(table, SWT.CENTER);
    column.setText("Column 3");
    column = new TableColumn(table, SWT.CENTER);
    column.setText("Column 4");
    for (int i = 0; i < 100; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      String[] text = new String[] { i + " 0", i + " 1", i + " 2",
          i + " 3", i + " 4" };
      item.setText(text);
    }
    Listener listener = new Listener() {
      public void handleEvent(Event e) {
        System.out.println("Move " + e.widget);
      }
    };
    TableColumn[] columns = table.getColumns();
    for (int i = 0; i < columns.length; i++) {
      columns[i].pack();
      columns[i].setMoveable(true);
      columns[i].addListener(SWT.Move, listener);
    }
    Button b = new Button(shell, SWT.PUSH);
    b.setText("invert column order");
    b.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event e) {
        int[] order = table.getColumnOrder();
        for (int i = 0; i < order.length / 2; i++) {
          int temp = order[i];
          order[i] = order[order.length - i - 1];
          order[order.length - i - 1] = temp;
        }
        table.setColumnOrder(order);
      }
    });
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Resize columns as SWT table resizes

/*
 * Table example snippet: resize columns as table resizes
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.ruposite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class Snippet77 {
public static void main(String[] args) {
  Display display = new Display();
  Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    
  final Composite comp = new Composite(shell, SWT.NONE);
  final Table table = new Table(comp, SWT.BORDER | SWT.V_SCROLL);
  table.setHeaderVisible(true);
  table.setLinesVisible(true);
  final TableColumn column1 = new TableColumn(table, SWT.NONE);
  column1.setText("Column 1");
  final TableColumn column2 = new TableColumn(table, SWT.NONE);
  column2.setText("Column 2");
  for (int i = 0; i < 10; i++) {
    TableItem item = new TableItem(table, SWT.NONE);
    item.setText(new String[] {"item 0" + i, "item 1"+i});
  }
  comp.addControlListener(new ControlAdapter() {
    public void controlResized(ControlEvent e) {
      Rectangle area = comp.getClientArea();
      Point preferredSize = table.ruputeSize(SWT.DEFAULT, SWT.DEFAULT);
      int width = area.width - 2*table.getBorderWidth();
      if (preferredSize.y > area.height + table.getHeaderHeight()) {
        // Subtract the scrollbar width from the total column width
        // if a vertical scrollbar will be required
        Point vBarSize = table.getVerticalBar().getSize();
        width -= vBarSize.x;
      }
      Point oldSize = table.getSize();
      if (oldSize.x > area.width) {
        // table is getting smaller so make the columns 
        // smaller first and then resize the table to
        // match the client area width
        column1.setWidth(width/3);
        column2.setWidth(width - column1.getWidth());
        table.setSize(area.width, area.height);
      } else {
        // table is getting bigger so make the table 
        // bigger first and then make the columns wider
        // to match the client area width
        table.setSize(area.width, area.height);
        column1.setWidth(width/3);
        column2.setWidth(width - column1.getWidth());
      }
    }
  });
    
  shell.open();
  while (!shell.isDisposed()) {
    if (!display.readAndDispatch())
      display.sleep();
  }
  display.dispose();
}
}





Scroll a SWT table (set the top index)

/*
 * Table example snippet: scroll a table (set the top index)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class Snippet51 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    Table table = new Table(shell, SWT.BORDER | SWT.MULTI);
    table.setSize(200, 200);
    for (int i = 0; i < 128; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText("Item " + i);
    }
    table.setTopIndex(95);
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Select an index (select and scroll) in a SWT table

/*
 * Table example snippet: select an index (select and scroll)
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class Snippet52 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    Table table = new Table(shell, SWT.BORDER | SWT.MULTI);
    table.setSize(200, 200);
    for (int i = 0; i < 128; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText("Item " + i);
    }
    table.setSelection(95);
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Shows the extensions on the system and their associated programs

//Send questions, comments, bug reports, etc. to the authors:
//Rob Warner (rwarner@interspatial.ru)
//Robert Harris (rbrt_harris@yahoo.ru)
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.*;
/**
 * This class shows the extensions on the system and their associated programs.
 */
public class ShowPrograms {
  /**
   * Runs the application
   */
  public void run() {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setText("Show Programs");
    createContents(shell);
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
    display.dispose();
  }
  /**
   * Creates the main window"s contents
   * 
   * @param shell the main window
   */
  private void createContents(Shell shell) {
    shell.setLayout(new GridLayout(2, false));
    // Create the label and combo for the extensions
    new Label(shell, SWT.NONE).setText("Extension:");
    Combo extensionsCombo = new Combo(shell, SWT.BORDER | SWT.READ_ONLY);
    extensionsCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    // Create the label and the
    new Label(shell, SWT.NONE).setText("Program:");
    final Label programName = new Label(shell, SWT.NONE);
    programName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    // Fill the combo with the extensions on the system
    String[] extensions = Program.getExtensions();
    for (int i = 0, n = extensions.length; i < n; i++) {
      extensionsCombo.add(extensions[i]);
    }
    // Add a handler to get the selected extension, look up the associated
    // program, and display the program"s name
    extensionsCombo.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        Combo combo = (Combo) event.widget;
        // Get the program for the extension
        Program program = Program.findProgram(combo.getText());
        // Display the program"s name
        programName.setText(program == null ? "(None)" : program.getName());
      }
    });
    // Create a list box to show all the programs on the system
    List allPrograms = new List(shell, SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL
        | SWT.V_SCROLL);
    GridData data = new GridData(GridData.FILL_BOTH);
    data.horizontalSpan = 2;
    allPrograms.setLayoutData(data);
    // Put all the known programs into the list box
    Program[] programs = Program.getPrograms();
    for (int i = 0, n = programs.length; i < n; i++) {
      String name = programs[i].getName();
      allPrograms.add(name);
      allPrograms.setData(name, programs[i]);
    }
    // Add a field for a data file
    new Label(shell, SWT.NONE).setText("Data File:");
    final Text dataFile = new Text(shell, SWT.BORDER);
    dataFile.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    // Double-clicking a program in the list launches the program
    allPrograms.addMouseListener(new MouseAdapter() {
      public void mouseDoubleClick(MouseEvent event) {
        List list = (List) event.widget;
        if (list.getSelectionCount() > 0) {
          String programName = list.getSelection()[0];
          Program program = (Program) list.getData(programName);
          program.execute(dataFile.getText());
        }
      }
    });
    // Let them use launch instead of execute
    Button launch = new Button(shell, SWT.PUSH);
    data = new GridData(GridData.FILL_HORIZONTAL);
    data.horizontalSpan = 2;
    launch.setLayoutData(data);
    launch.setText("Use Program.launch() instead of Program.execute()");
    launch.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        // Use launch
        Program.launch(dataFile.getText());
      }
    });
  }
  /**
   * The application entry point
   * 
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    new ShowPrograms().run();
  }
}





Simple File Browser in SWT Table

/******************************************************************************
 * Copyright (c) 1998, 2004 Jackwind Li Guojie
 * All right reserved. 
 * 
 * Created on Jan 7, 2004 2:38:45 PM by JACK
 * $Id$
 * 
 * visit: http://www.asprise.ru/swt
 *****************************************************************************/

import java.io.File;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class SimpleFileBrowser {
  Display display = new Display();
  Shell shell = new Shell(display);
  ImageRegistry imageRegistry;
  Table table;
  public SimpleFileBrowser() {
    init();
    shell.pack();
    shell.open();
    //textUser.forceFocus();
    // Set up the event loop.
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        // If no more entries in event queue
        display.sleep();
      }
    }
    display.dispose();
  }
  private void init() {
    shell.setText("File Browser");
    shell.setLayout(new GridLayout(1, true));
    
    Button button = new Button(shell, SWT.PUSH);
    button.setText("Browse ...");
    button.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        DirectoryDialog dialog = new DirectoryDialog(shell, SWT.NULL);
        String path = dialog.open();
        if (path != null) {
          File file = new File(path);
          if (file.isFile())
            displayFiles(new String[] { file.toString()});
          else
            displayFiles(file.list());
        }
      }
    });
    GridData gd = new GridData(GridData.FILL_BOTH);
    table = new Table(shell, SWT.MULTI);
    table.setLayoutData(gd);
    // creates an image registry and adds icons to the image registry.
    imageRegistry = new ImageRegistry();
    ImageDescriptor defaultIcon =
      ImageDescriptor.createFromFile(null, "jexp.gif");
    imageRegistry.put("default", defaultIcon);
    ImageDescriptor jarIcon =
      ImageDescriptor.createFromFile(null, "img/jar.gif");
    imageRegistry.put("jar", jarIcon);
  }
  public void displayFiles(String[] files) {
    // Removes all existing table items.
    table.removeAll();
    for (int i = 0; files != null && i < files.length; i++) {
      TableItem item = new TableItem(table, SWT.NULL);
      Image image = null;
      if (files[i].endsWith(".jar")) {
        image = imageRegistry.get("jar");
      } else {
        image = imageRegistry.get("default");
      }
      item.setImage(image);
      item.setText(files[i]);
    }
  }
  public void displayFiles2(String[] files) {
    // Disposes all of the images used by the table items first. 
    TableItem[] items = table.getItems();
    for(int i=0; items != null && i < items.length; i++) {
      if(items[i].getImage() != null)
        items[i].getImage().dispose();
    }
    
    // Removes all existing table items.
    table.removeAll();
    for (int i = 0; files != null && i < files.length; i++) {
      TableItem item = new TableItem(table, SWT.NULL);
      Image image = null;
      if (files[i].endsWith(".jar")) {
        image = new Image(display, "jexp.gif");
      } else {
        image = new Image(display, "img/default.gif");
      }
      item.setImage(image);
      item.setText(files[i]);
    }
  }  
  
  public static void main(String[] args) {
    new SimpleFileBrowser();
  }
}





Sort a SWT table by column

/*
 * Table example snippet: sort a table by column
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import java.text.Collator;
import java.util.Locale;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class Snippet2 {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    final Table table = new Table(shell, SWT.BORDER);
    table.setHeaderVisible(true);
    TableColumn column1 = new TableColumn(table, SWT.NONE);
    column1.setText("Column 1");
    TableColumn column2 = new TableColumn(table, SWT.NONE);
    column2.setText("Column 2");
    TableItem item = new TableItem(table, SWT.NONE);
    item.setText(new String[] { "a", "3" });
    item = new TableItem(table, SWT.NONE);
    item.setText(new String[] { "b", "2" });
    item = new TableItem(table, SWT.NONE);
    item.setText(new String[] { "c", "1" });
    column1.pack();
    column2.pack();
    column1.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event e) {
        // sort column 1
        TableItem[] items = table.getItems();
        Collator collator = Collator.getInstance(Locale.getDefault());
        for (int i = 1; i < items.length; i++) {
          String value1 = items[i].getText(0);
          for (int j = 0; j < i; j++) {
            String value2 = items[j].getText(0);
            if (collator.rupare(value1, value2) < 0) {
              String[] values = { items[i].getText(0),
                  items[i].getText(1) };
              items[i].dispose();
              TableItem item = new TableItem(table, SWT.NONE, j);
              item.setText(values);
              items = table.getItems();
              break;
            }
          }
        }
      }
    });
    column2.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event e) {
        // sort column 2
        TableItem[] items = table.getItems();
        Collator collator = Collator.getInstance(Locale.getDefault());
        for (int i = 1; i < items.length; i++) {
          String value1 = items[i].getText(1);
          for (int j = 0; j < i; j++) {
            String value2 = items[j].getText(1);
            if (collator.rupare(value1, value2) < 0) {
              String[] values = { items[i].getText(0),
                  items[i].getText(1) };
              items[i].dispose();
              TableItem item = new TableItem(table, SWT.NONE, j);
              item.setText(values);
              items = table.getItems();
              break;
            }
          }
        }
      }
    });
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





SWT Table Editor

/*
SWT/JFace in Action
GUI Design with Eclipse 3.0
Matthew Scarpino, Stephen Holder, Stanford Ng, and Laurent Mihalkovic
ISBN: 1932394273
Publisher: Manning
*/

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ruboBoxCellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.ruposite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class Ch9TableEditorComposite extends Composite {
  private static final Object[] CONTENT = new Object[] {
      new EditableTableItem("item 1", new Integer(0)),
      new EditableTableItem("item 2", new Integer(1)) };
  private static final String[] VALUE_SET = new String[] { "xxx", "yyy",
      "zzz" };
  private static final String NAME_PROPERTY = "name";
  private static final String VALUE_PROPERTY = "value";
  private TableViewer viewer;
  public Ch9TableEditorComposite(Composite parent) {
    super(parent, SWT.NULL);
    buildControls();
  }
  private class NewRowAction extends Action {
    public NewRowAction() {
      super("Insert New Row");
    }
    public void run() {
      EditableTableItem newItem = new EditableTableItem("new row",
          new Integer(2));
      viewer.add(newItem);
    }
  }
  protected void buildControls() {
    FillLayout compositeLayout = new FillLayout();
    setLayout(compositeLayout);
    final Table table = new Table(this, SWT.FULL_SELECTION);
    viewer = buildAndLayoutTable(table);
    attachContentProvider(viewer);
    attachLabelProvider(viewer);
    attachCellEditors(viewer, table);
    MenuManager popupMenu = new MenuManager();
    IAction newRowAction = new NewRowAction();
    popupMenu.add(newRowAction);
    Menu menu = popupMenu.createContextMenu(table);
    table.setMenu(menu);
    viewer.setInput(CONTENT);
  }
  private void attachLabelProvider(TableViewer viewer) {
    viewer.setLabelProvider(new ITableLabelProvider() {
      public Image getColumnImage(Object element, int columnIndex) {
        return null;
      }
      public String getColumnText(Object element, int columnIndex) {
        switch (columnIndex) {
        case 0:
          return ((EditableTableItem) element).name;
        case 1:
          Number index = ((EditableTableItem) element).value;
          return VALUE_SET[index.intValue()];
        default:
          return "Invalid column: " + columnIndex;
        }
      }
      public void addListener(ILabelProviderListener listener) {
      }
      public void dispose() {
      }
      public boolean isLabelProperty(Object element, String property) {
        return false;
      }
      public void removeListener(ILabelProviderListener lpl) {
      }
    });
  }
  private void attachContentProvider(TableViewer viewer) {
    viewer.setContentProvider(new IStructuredContentProvider() {
      public Object[] getElements(Object inputElement) {
        return (Object[]) inputElement;
      }
      public void dispose() {
      }
      public void inputChanged(Viewer viewer, Object oldInput,
          Object newInput) {
      }
    });
  }
  private TableViewer buildAndLayoutTable(final Table table) {
    TableViewer tableViewer = new TableViewer(table);
    TableLayout layout = new TableLayout();
    layout.addColumnData(new ColumnWeightData(50, 75, true));
    layout.addColumnData(new ColumnWeightData(50, 75, true));
    table.setLayout(layout);
    TableColumn nameColumn = new TableColumn(table, SWT.CENTER);
    nameColumn.setText("Name");
    TableColumn valColumn = new TableColumn(table, SWT.CENTER);
    valColumn.setText("Value");
    table.setHeaderVisible(true);
    return tableViewer;
  }
  private void attachCellEditors(final TableViewer viewer, Composite parent) {
    viewer.setCellModifier(new ICellModifier() {
      public boolean canModify(Object element, String property) {
        return true;
      }
      public Object getValue(Object element, String property) {
        if (NAME_PROPERTY.equals(property))
          return ((EditableTableItem) element).name;
        else
          return ((EditableTableItem) element).value;
      }
      public void modify(Object element, String property, Object value) {
        TableItem tableItem = (TableItem) element;
        EditableTableItem data = (EditableTableItem) tableItem
            .getData();
        if (NAME_PROPERTY.equals(property))
          data.name = value.toString();
        else
          data.value = (Integer) value;
        viewer.refresh(data);
      }
    });
    viewer.setCellEditors(new CellEditor[] { new TextCellEditor(parent),
        new ComboBoxCellEditor(parent, VALUE_SET) });
    viewer
        .setColumnProperties(new String[] { NAME_PROPERTY,
            VALUE_PROPERTY });
  }
}
class EditableTableItem {
  public String name;
  public Integer value;
  public EditableTableItem(String n, Integer v) {
    name = n;
    value = v;
  }
}





SWT Table Simple Demo

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
public class TableClass {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setSize(280, 300);
    shell.setText("Table Example");
    final Text text = new Text(shell, SWT.BORDER);
    text.setBounds(25, 240, 220, 25);
    Table table = new Table(shell, SWT.CHECK | SWT.BORDER | SWT.V_SCROLL
        | SWT.H_SCROLL);
    table.setHeaderVisible(true);
    String[] titles = { "Col 1", "Col 2", "Col 3", "Col 4" };
    for (int loopIndex = 0; loopIndex < titles.length; loopIndex++) {
      TableColumn column = new TableColumn(table, SWT.NULL);
      column.setText(titles[loopIndex]);
    }
    for (int loopIndex = 0; loopIndex < 24; loopIndex++) {
      TableItem item = new TableItem(table, SWT.NULL);
      item.setText("Item " + loopIndex);
      item.setText(0, "Item " + loopIndex);
      item.setText(1, "Yes");
      item.setText(2, "No");
      item.setText(3, "A table item");
    }
    for (int loopIndex = 0; loopIndex < titles.length; loopIndex++) {
      table.getColumn(loopIndex).pack();
    }
    table.setBounds(25, 25, 220, 200);
    table.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        if (event.detail == SWT.CHECK) {
          text.setText("You checked " + event.item);
        } else {
          text.setText("You selected " + event.item);
        }
      }
    });
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





TableEditor example

/*
 * TableEditor example snippet: edit a cell in a table (in place, fancy)
 * 
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
public class TableEditorExample {
  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    final Table table = new Table(shell, SWT.BORDER | SWT.MULTI);
    table.setLinesVisible(true);
    for (int i = 0; i < 3; i++) {
      TableColumn column = new TableColumn(table, SWT.NONE);
      column.setWidth(100);
    }
    for (int i = 0; i < 3; i++) {
      TableItem item = new TableItem(table, SWT.NONE);
      item.setText(new String[] { "" + i, "" + i, "" + i });
    }
    final TableEditor editor = new TableEditor(table);
    editor.horizontalAlignment = SWT.LEFT;
    editor.grabHorizontal = true;
    table.addListener(SWT.MouseDown, new Listener() {
      public void handleEvent(Event event) {
        Rectangle clientArea = table.getClientArea();
        Point pt = new Point(event.x, event.y);
        int index = table.getTopIndex();
        while (index < table.getItemCount()) {
          boolean visible = false;
          final TableItem item = table.getItem(index);
          for (int i = 0; i < table.getColumnCount(); i++) {
            Rectangle rect = item.getBounds(i);
            if (rect.contains(pt)) {
              final int column = i;
              final Text text = new Text(table, SWT.NONE);
              Listener textListener = new Listener() {
                public void handleEvent(final Event e) {
                  switch (e.type) {
                  case SWT.FocusOut:
                    item.setText(column, text.getText());
                    text.dispose();
                    break;
                  case SWT.Traverse:
                    switch (e.detail) {
                    case SWT.TRAVERSE_RETURN:
                      item
                          .setText(column, text
                              .getText());
                    //FALL THROUGH
                    case SWT.TRAVERSE_ESCAPE:
                      text.dispose();
                      e.doit = false;
                    }
                    break;
                  }
                }
              };
              text.addListener(SWT.FocusOut, textListener);
              text.addListener(SWT.Traverse, textListener);
              editor.setEditor(text, item, i);
              text.setText(item.getText(i));
              text.selectAll();
              text.setFocus();
              return;
            }
            if (!visible && rect.intersects(clientArea)) {
              visible = true;
            }
          }
          if (!visible)
            return;
          index++;
        }
      }
    });
    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}





Table Example

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class TableShellExample {
  Display d;
  Shell s;
  TableShellExample() {
    d = new Display();
    s = new Shell(d);
    s.setSize(250, 200);
    
    s.setText("A Table Shell Example");
    s.setLayout(new FillLayout());
    Table t = new Table(s, SWT.BORDER);
    TableColumn tc1 = new TableColumn(t, SWT.CENTER);
    TableColumn tc2 = new TableColumn(t, SWT.CENTER);
    TableColumn tc3 = new TableColumn(t, SWT.CENTER);
    tc1.setText("First Name");
    tc2.setText("Last Name");
    tc3.setText("Address");
    tc1.setWidth(70);
    tc2.setWidth(70);
    tc3.setWidth(80);
    t.setHeaderVisible(true);
    TableItem item1 = new TableItem(t, SWT.NONE);
    item1.setText(new String[] { "Tim", "Hatton", "Kentucky" });
    TableItem item2 = new TableItem(t, SWT.NONE);
    item2.setText(new String[] { "Caitlyn", "Warner", "Ohio" });
    TableItem item3 = new TableItem(t, SWT.NONE);
    item3.setText(new String[] { "Reese", "Miller", "Ohio" });
    s.open();
    while (!s.isDisposed()) {
      if (!d.readAndDispatch())
        d.sleep();
    }
    d.dispose();
  }
  public static void main(String[] argv) {
    new TableShellExample();
  }
}





Table Example 2

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
public class TableShellExample2 {
  Display d;
  Shell s;
  TableShellExample2() {
    d = new Display();
    s = new Shell(d);
    s.setSize(250, 200);
    
    s.setText("A Table Shell Example");
    GridLayout gl = new GridLayout();
    gl.numColumns = 2;
    s.setLayout(gl);
    final Table t = new Table(s, SWT.BORDER | SWT.CHECK | SWT.MULTI
        | SWT.FULL_SELECTION);
    final GridData gd = new GridData(GridData.FILL_BOTH);
    gd.horizontalSpan = 2;
    t.setLayoutData(gd);
    t.setHeaderVisible(true);
    final TableColumn tc1 = new TableColumn(t, SWT.LEFT);
    final TableColumn tc2 = new TableColumn(t, SWT.CENTER);
    final TableColumn tc3 = new TableColumn(t, SWT.CENTER);
    tc1.setText("First Name");
    tc2.setText("Last Name");
    tc3.setText("Address");
    tc1.setWidth(70);
    tc2.setWidth(70);
    tc3.setWidth(80);
    final TableItem item1 = new TableItem(t, SWT.NONE);
    item1.setText(new String[] { "Tim", "Hatton", "Kentucky" });
    final TableItem item2 = new TableItem(t, SWT.NONE);
    item2.setText(new String[] { "Caitlyn", "Warner", "Ohio" });
    final TableItem item3 = new TableItem(t, SWT.NONE);
    item3.setText(new String[] { "Reese", "Miller", "Ohio" });
    final Text input = new Text(s, SWT.SINGLE | SWT.BORDER);
    final Button searchBtn = new Button(s, SWT.BORDER | SWT.PUSH);
    searchBtn.setText("Search");
    searchBtn.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        TableItem[] tia = t.getItems();
        for (int i = 0; i < tia.length; i++) {
          if (tia[i].getText(2).equals(input.getText())) {
            tia[i].setBackground(new Color(d, 127, 178, 127));
          }
        }
      }
    });
    s.open();
    while (!s.isDisposed()) {
      if (!d.readAndDispatch())
        d.sleep();
    }
    d.dispose();
  }
  public static void main(String[] argv) {
    new TableShellExample2();
  }
}





Table Example 3

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.*;
public class TableShellExample3 {
    
    Display d;
    Shell s;
    TableShellExample3()    {
        d = new Display();
        s = new Shell(d);
        
        s.setSize(250,200);
        
        s.setText("A Table Shell Example");
        GridLayout gl = new GridLayout();
        gl.numColumns = 4;
        s.setLayout(gl);
        
        final Table t = new Table(s, SWT.BORDER | SWT.CHECK | 
            SWT.MULTI | SWT.FULL_SELECTION);
        final GridData gd = new GridData(GridData.FILL_BOTH);
        gd.horizontalSpan = 4;
        t.setLayoutData(gd);
        t.setHeaderVisible(true);
        final TableColumn tc1 = new TableColumn(t, SWT.LEFT);
        final TableColumn tc2 = new TableColumn(t, SWT.CENTER);
        final TableColumn tc3 = new TableColumn(t, SWT.CENTER);
        tc1.setText("First Name");
        tc2.setText("Last Name");
        tc3.setText("Address");
        tc1.setWidth(70);
        tc2.setWidth(70);
        tc3.setWidth(80);
        final TableItem item1 = new TableItem(t,SWT.NONE);
        item1.setText(new String[] {"Tim","Hatton","Kentucky"});
        final TableItem item2 = new TableItem(t,SWT.NONE);
        item2.setText(new String[] {"Caitlyn","Warner","Ohio"});
        final TableItem item3 = new TableItem(t,SWT.NONE);
        item3.setText(new String[] {"Reese","Miller","Ohio"});
        
        final Text find = new Text(s, SWT.SINGLE | SWT.BORDER);
        final Text replace = new Text(s, SWT.SINGLE | SWT.BORDER);
        final Button replaceBtn = new Button(s, SWT.BORDER | SWT.PUSH);
        replaceBtn.setText("Replace");
        replaceBtn.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                TableItem[] tia = t.getItems();
                
                for(int i = 0; i<tia.length;i++)
                {
                    if (tia[i].getText(2).equals(find.getText()))
                    {
                        tia[i].setText(2, replace.getText());
                    }
                    
                }
            }
        });
               
        s.open();
        while(!s.isDisposed()){
            if(!d.readAndDispatch())
                d.sleep();
        }
        d.dispose();
    }
  public static void main(String[] argv) {
    new TableShellExample3();
  }
}





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.ruposite;
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();
  }
}





Update SWT table item text

/*
 * Table example snippet: update table item text
 *
 * For a list of all SWT example snippets see
 * http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/dev.html#snippets
 */
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class Snippet103 {
  static char content = "a";
  public static void main(String[] args) {
    final Display display = new Display();
    Shell shell = new Shell(display);
    shell.setBounds(10, 10, 200, 240);
    Table table = new Table(shell, SWT.NONE);
    table.setBounds(10, 10, 160, 160);
    final TableItem[] items = new TableItem[4];
    for (int i = 0; i < 4; i++) {
      new TableColumn(table, SWT.NONE).setWidth(40);
    }
    for (int i = 0; i < 4; i++) {
      items[i] = new TableItem(table, SWT.NONE);
      populateItem(items[i]);
    }
    Button button = new Button(shell, SWT.PUSH);
    button.setBounds(10, 180, 50, 30);
    button.setText("Change");
    button.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        for (int i = 0; i < 4; i++) {
          populateItem(items[i]);
        }
      }
    });
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
  static void populateItem(TableItem item) {
    String stringContent = String.valueOf(content);
    item.setText(new String[] { stringContent, stringContent,
        stringContent, stringContent });
    content++;
    if (content > "z")
      content = "a";
  }
}