Print KTable (SWT Table)Example : Table « SWT JFace Eclipse « Java

Home
Java
1.2D Graphics GUI
2.3D
3.Advanced Graphics
4.Ant
5.Apache Common
6.Chart
7.Class
8.Collections Data Structure
9.Data Type
10.Database SQL JDBC
11.Design Pattern
12.Development Class
13.EJB3
14.Email
15.Event
16.File Input Output
17.Game
18.Generics
19.GWT
20.Hibernate
21.I18N
22.J2EE
23.J2ME
24.JDK 6
25.JNDI LDAP
26.JPA
27.JSP
28.JSTL
29.Language Basics
30.Network Protocol
31.PDF RTF
32.Reflection
33.Regular Expressions
34.Scripting
35.Security
36.Servlets
37.Spring
38.Swing Components
39.Swing JFC
40.SWT JFace Eclipse
41.Threads
42.Tiny Application
43.Velocity
44.Web Services SOA
45.XML
Java » SWT JFace Eclipse » TableScreenshots 
Print KTable (SWT Table)Example
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.Combo;
import org.eclipse.swt.widgets.Composite;
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 = (PDocumentparent;

      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 = (Fontiter.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 = (Fontfonts.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 >= && hWeight <= && 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 = (Stringiter.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 >= && 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 = (PTextPartpageList.get(page - origin.page);
    return part.numOfLines * lineHeight;
  }

  public void draw(int page, Point originOffset) {

    if (layoutIsOnPage(page)) {
      PTextPart part = (PTextPartpageList.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((StringtextLines
              .get(part.startLine + i)).x;
          alignPixel = (getWidth()
              - pixelX(textStyle.getMarginLeft())
              - pixelX(textStyle.getMarginRight()) - textWidth2;
        else if (textStyle.textAlign == PTextStyle.ALIGN_RIGHT) {
          gc.setFont(font);
          int textWidth = gc.stringExtent((StringtextLines
              .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((StringtextLines.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.0050.010.0050.0 };
    if (row == 0)
      boxStyle.lines[00.02;
    if (col == 0)
      boxStyle.lines[30.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[00.0;
    lines[10.0;
    lines[20.0;
    lines[30.0;
    lineColor = SWT.COLOR_BLACK;
    backColor = SWT.COLOR_WHITE;

    // setDebugStyle();
  }

  private void setDebugStyle() {
    lines[00.01;
    lines[10.01;
    lines[20.01;
    lines[30.01;
    lineColor = SWT.COLOR_GRAY;
  }

  public static PStyle getDefaultStyle() {
    return new PStyle();
  }

  public int getLineWidth(int num) {
    int pixel = 0;
    if (num == || num == 2)
      pixel = PBox.pixelY(lines[num]);
    if (num == || 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[num0;
  }

  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(300400);
    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(((Comboarg0.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.computeSize(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 = (intMath.round(document.getPageHeight() 2.54 * dpi.y
          * percent / 100 5);
      int w = (intMath.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 - 50, newImage
          .getBounds().width - 5, newImage.getBounds().height);

      gc.setBackground(Display.getCurrent().getSystemColor(
          SWT.COLOR_WIDGET_BACKGROUND));
      gc.fillRectangle(0, newImage.getBounds().height - 55, newImage
          .getBounds().height);
      gc.fillRectangle(newImage.getBounds().width - 50, 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.computeSize(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.computeSize(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, -10);
    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 >= && hWeight <= && 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 = (Stringiter.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 >= && 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((StringtextLines.get(i)).x;
          alignPixel = (getWidth()
              - pixelX(textStyle.getMarginLeft())
              - pixelX(textStyle.getMarginRight()) - textWidth2;
        else if (textStyle.textAlign == PTextStyle.ALIGN_RIGHT) {
          int textWidth = gc.stringExtent((StringtextLines.get(i)).x;
          alignPixel = (getWidth()
              - pixelX(textStyle.getMarginLeft())
              - pixelX(textStyle.getMarginRight()) - textWidth);
        }

        gc.drawText((StringtextLines.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(00);
      imgOriginalSize.x = image.getImageData().width;
      imgOriginalSize.y = image.getImageData().height;

      imgTargetSize = new Point(00);
      imgTargetSize.x = (int) (imgOriginalSize.x * scalingPercent / 100 (pixelPerInch.x / (doubleimgDPI));
      imgTargetSize.y = (int) (imgOriginalSize.y * scalingPercent / 100 (pixelPerInch.y / (doubleimgDPI));

      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(1010);
      imgTargetSize = new Point(1010);
      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, 00, 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.00.0);
    this.thickness = thickness;
    boxStyle.lines = new double[] { 0.00.00.00.0 };
    boxStyle.backColor = color;
  }

  /**
   * Creates a black thin horizontal line.
   */
  public PHLine(PContainer parent) {
    super(parent, POS_BELOW, 1.00.0);
    this.thickness = 0.01;
    boxStyle.lines = new double[] { 0.00.00.00.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 * / scale;
    this.pageWidth = pageWidth * / 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, 0000,
        (doublePageSetup.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 = (doublePageSetup.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).computeTrim(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).computeTrim(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 = (PBoxiter.next();
      element.layoutResetTuning();
    }
  }

  /*
   * Gibt die Anzahl der gefullten Seiten zuruck.
   */
  protected int layout(int maxHeightForFirstPage, int maxHeightForOtherPages) {
    int currentPage = 1;
    Point currentOrgin = new Point(00);
    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 == && calculatedHeight < currentOrgin.y)
          calculatedHeight = currentOrgin.y;
        if (pageBreakNeccessary) {
          currentPage++;
          PPageNumber.pageNumber++;
          currentOrgin = new Point(00);
          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 = (PBoxiter.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 = (PBoxiter.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 = (PBoxiter.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 = (PBoxiter.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 = (PBoxchildren.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 = (PBoxiter.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(00);

  protected static Point pixelPerInch = new Point(00);

  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_RIGHT0)
      below = false;
    if ((style & POS_BELOW0)
      below = true;
    if ((style & GRAB0)
      grabbing = true;
    if ((style & ROW_ALIGN0)
      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 (inttmp;
  }

  protected static int pixelY(double cm) {
    long tmp = Math.round(cm * pixelPerCm.y * scalingPercent / 100);
    return (inttmp;
  }

  /**
   * 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((intMath.round(dpi.x / 2.54)(intMath
        .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(00);
    f.left = new FormAttachment(00);
    f.bottom = new FormAttachment(1000);
    bild.setLayoutData(f);

    Label separator = new Label(this.s, SWT.SEPARATOR);

    f = new FormData();
    f.top = new FormAttachment(00);
    f.left = new FormAttachment(bild, 0);
    f.bottom = new FormAttachment(1000);
    separator.setLayoutData(f);

    meldung = new Label(s, SWT.LEFT | SWT.WRAP);
    meldung.setText(message);

    f = new FormData();
    f.top = new FormAttachment(025);
    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 = ((Buttone.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(025);
    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().width2(d
        .getBounds().height - s.getBounds().height2);

    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, 03.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(00);
    fd.right = new FormAttachment(1000);
    sep.setLayoutData(fd);

  }

  protected void createMainAreaLayout() {
    guiMainAreaLayout = new GridLayout();
    ((GridLayoutguiMainAreaLayout).makeColumnsEqualWidth = false;
    ((GridLayoutguiMainAreaLayout).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(1true);
    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().width2,
            (guiDisplay.getBounds().height - guiShell.getBounds().width2);
  }

  /**
   * 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(1true);
    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(00);
      fd.top = new FormAttachment(00);
      guiToolBar.setLayoutData(fd);

      Label line = new Label(guiToolBarArea, SWT.SEPARATOR
          | SWT.HORIZONTAL);
      fd = new FormData();
      fd.left = new FormAttachment(00);
      fd.top = new FormAttachment(guiToolBar, 1);
      fd.right = new FormAttachment(1000);
      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((ToolIteme.widget, (Stringe.widget.getData());
      }
    });

    guiToolBarGridData.heightHint = guiToolBarArea.computeSize(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(01);
    fd.bottom = new FormAttachment(022);

    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.computeSize(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(03);
      else
        fd.left = new FormAttachment(guiLastLeftBut, 3);
      guiLastLeftBut = erg;
    }

    erg.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent arg0) {
        onButton((Buttonarg0.widget, ((Buttonarg0.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(13911111.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, 05);
    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, 05);
    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.00);
    t.setText("See you soon: your personal swt programmer on holiday.");
    // Border lines are counted clockwise starting at the top.
    t.getBoxStyle().lines[00.05// top
    t.getBoxStyle().lines[20.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, 01.3);
    t.setText("Affix stamp here");
    t.getBoxStyle().lines[00.01;
    t.getBoxStyle().lines[10.01;
    t.getBoxStyle().lines[20.01;
    t.getBoxStyle().lines[30.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, -100);

    int x = getColumnLeft(col1;
    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() + row - m_TopRow)
          * m_Model.getRowHeight();
    int width = m_Model.getColumnWidth(col1;
    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() + m_RowsVisible)
          * m_Model.getRowHeight() 1;
    }

    gc.setBackground(getBackground());
    gc.fillRectangle(r);
    gc.fillRectangle(getLastColumnRight() 20, 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(000, 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() 10, 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, -101100100);
        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 + 10, 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 - right3) {
        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 = ((y - m_Model.getFirstRowHeight()) / m_Model
        .getRowHeight());
    int rowY = m_Model.getFirstRowHeight() + row * m_Model.getRowHeight();

    if (Math.abs(rowY - y&& 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() == ? m_TopRow : 0);
    y -= m_Model.getFirstRowHeight();
    int row = (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== && (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 == -|| 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