home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / jfc.bin / Utilities.java < prev    next >
Text File  |  1998-02-26  |  11KB  |  363 lines

  1. /*
  2.  * @(#)Utilities.java    1.13 98/01/31
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing.text;
  21.  
  22. import java.awt.Rectangle;
  23. import java.awt.Graphics;
  24. import java.awt.FontMetrics;
  25. import java.text.*;
  26.  
  27. /**
  28.  * A collection of methods to deal with various text
  29.  * related activities.
  30.  * 
  31.  * @author  Timothy Prinzing
  32.  * @version 1.13 01/31/98
  33.  */
  34. public class Utilities {
  35.  
  36.     /**
  37.      * Draws the given text, expanding any tabs that are contained
  38.      * using the given tab expansion technique.  This particular
  39.      * implementation renders in a 1.1 style coordinate system
  40.      * where ints are used and 72dpi is assumed.
  41.      * 
  42.      * @param s  the source of the text
  43.      * @param x  the X origin
  44.      * @param y  the Y origin
  45.      * @param g  the graphics context
  46.      * @param e  how to expand the tabs
  47.      * @param startOffset starting offset in the document of the text
  48.      * @returns  the location at the end of the rendered text
  49.      */
  50.     public static final int drawTabbedText(Segment s, int x, int y, Graphics g, 
  51.                        TabExpander e, int startOffset) {
  52.     FontMetrics metrics = g.getFontMetrics();
  53.     int nextX = x;
  54.     char[] txt = s.array;
  55.     int flushLen = 0;
  56.     int flushIndex = s.offset;
  57.     int n = s.offset + s.count;
  58.     for (int i = s.offset; i < n; i++) {
  59.         if (txt[i] == '\t') {
  60.         if (flushLen > 0) {
  61.             g.drawChars(txt, flushIndex, flushLen, x, y);
  62.             flushLen = 0;
  63.         }
  64.         flushIndex = i + 1;
  65.         nextX = (int) e.nextTabStop((float) nextX, startOffset + i - s.offset);
  66.         x = nextX;
  67.         } else if ((txt[i] == '\n') || (txt[i] == '\r')) {
  68.         if (flushLen > 0) {
  69.             g.drawChars(txt, flushIndex, flushLen, x, y);
  70.             flushLen = 0;
  71.         }
  72.         flushIndex = i + 1;
  73.         x = nextX;
  74.         } else {
  75.         flushLen += 1;
  76.         nextX += metrics.charWidth(txt[i]);
  77.         }
  78.     } 
  79.     if (flushLen > 0) {
  80.         g.drawChars(txt, flushIndex, flushLen, x, y);
  81.     }
  82.     return nextX;
  83.     }
  84.  
  85.     /**
  86.      * Determines the width of the given segment of text taking tabs 
  87.      * into consideration.  This is implemented in a 1.1 style coordinate 
  88.      * system where ints are used and 72dpi is assumed.
  89.      *
  90.      * @param s  the source of the text
  91.      * @param metrics the font metrics to use for the calculation
  92.      * @param x  the X origin
  93.      * @param e  how to expand the tabs
  94.      * @param startOffset starting offset in the document of the text
  95.      * @returns  the width of the text
  96.      */
  97.     public static final int getTabbedTextWidth(Segment s, FontMetrics metrics, int x, 
  98.                            TabExpander e, int startOffset) {
  99.     int nextX = x;
  100.     char[] txt = s.array;
  101.     int n = s.offset + s.count;
  102.     for (int i = s.offset; i < n; i++) {
  103.         if (txt[i] == '\t') {
  104.         nextX = (int) e.nextTabStop((float) nextX,
  105.                         startOffset + i - s.offset);
  106.         } else {
  107.         nextX += metrics.charWidth(txt[i]);
  108.         }
  109.     }
  110.     return nextX - x;
  111.     }
  112.  
  113.     /**
  114.      * Determines the relative offset into the given text that
  115.      * best represents the given span in the view coordinate
  116.      * system.  This is implemented in a 1.1 style coordinate 
  117.      * system where ints are used and 72dpi is assumed.
  118.      *
  119.      * @param s  the source of the text
  120.      * @param metrics the font metrics to use for the calculation
  121.      * @param x0 the starting view location representing the start
  122.      *   of the given text.
  123.      * @param x  the target view location to translate to an
  124.      *   offset into the text.
  125.      * @param e  how to expand the tabs
  126.      * @param startOffset starting offset in the document of the text
  127.      * @returns  the offset into the text
  128.      */
  129.     public static final int getTabbedTextOffset(Segment s, FontMetrics metrics, 
  130.                          int x0, int x, TabExpander e,
  131.                          int startOffset) {
  132.  
  133.     int currX = x0;
  134.     int nextX = currX;
  135.     char[] txt = s.array;
  136.     int n = s.offset + s.count;
  137.     for (int i = s.offset; i < n; i++) {
  138.         if (txt[i] == '\t') {
  139.         nextX = (int) e.nextTabStop((float) nextX,
  140.                         startOffset + i - s.offset);
  141.         } else {
  142.         nextX += metrics.charWidth(txt[i]);
  143.         }
  144.         if ((x >= currX) && (x < nextX)) {
  145.         // found the hit position... return the appropriate side
  146.         if ((x - currX) < (nextX - x)) {
  147.             return i - s.offset;
  148.         } else {
  149.             return i + 1 - s.offset;
  150.         }
  151.         }
  152.         currX = nextX;
  153.     }
  154.  
  155.     // didn't find, return end offset
  156.     return s.count;
  157.     }
  158.  
  159.     /**
  160.      * Determine the position in the model of the row start in the view 
  161.      * that the given model position resides. 
  162.      */
  163.     static final int getRowStart(JTextComponent c, int offs) throws BadLocationException {
  164.     Rectangle r = c.modelToView(offs);
  165.     int lastOffs = offs;
  166.     int y = r.y;
  167.     while ((r != null) && (y == r.y)) {
  168.         offs = lastOffs;
  169.         lastOffs -= 1;
  170.         r = (lastOffs >= 0) ? c.modelToView(lastOffs) : null;
  171.     }
  172.     return offs;
  173.     }
  174.  
  175.     /**
  176.      * Determine the position in the model of the row end in the view 
  177.      * that the given model position resides. 
  178.      */
  179.     static final int getRowEnd(JTextComponent c, int offs) throws BadLocationException {
  180.     Rectangle r = c.modelToView(offs);
  181.     int n = c.getDocument().getLength();
  182.     int lastOffs = offs;
  183.     int y = r.y;
  184.     while ((r != null) && (y == r.y)) {
  185.         offs = lastOffs;
  186.         lastOffs += 1;
  187.         r = (lastOffs <= n) ? c.modelToView(lastOffs) : null;
  188.     }
  189.     return offs;
  190.     }
  191.  
  192.     /**
  193.      * Determine the position in the model that is closest to the given 
  194.      * view location in the row above.
  195.      */
  196.     static final int getPositionAbove(JTextComponent c, int offs, int x) throws BadLocationException {
  197.     int lastOffs = getRowStart(c, offs) - 1;
  198.     int bestSpan = Short.MAX_VALUE;
  199.     int y = 0;
  200.     Rectangle r = null;
  201.     if (lastOffs >= 0) {
  202.         r = c.modelToView(lastOffs);
  203.         y = r.y;
  204.     }
  205.     while ((r != null) && (y == r.y)) {
  206.         int span = Math.abs(r.x - x);
  207.         if (span < bestSpan) {
  208.         offs = lastOffs;
  209.         bestSpan = span;
  210.         }
  211.         lastOffs -= 1;
  212.         r = (lastOffs >= 0) ? c.modelToView(lastOffs) : null;
  213.     }
  214.     return offs;
  215.     }
  216.  
  217.     /**
  218.      * Determine the position in the model that is closest to the given 
  219.      * view location in the row below.
  220.      */
  221.     static final int getPositionBelow(JTextComponent c, int offs, int x) throws BadLocationException {
  222.     int lastOffs = getRowEnd(c, offs) + 1;
  223.     int bestSpan = Short.MAX_VALUE;
  224.     int n = c.getDocument().getLength();
  225.     int y = 0;
  226.     Rectangle r = null;
  227.     if (lastOffs <= n) {
  228.         r = c.modelToView(lastOffs);
  229.         y = r.y;
  230.     }
  231.     while ((r != null) && (y == r.y)) {
  232.         int span = Math.abs(x - r.x);
  233.         if (span < bestSpan) {
  234.         offs = lastOffs;
  235.         bestSpan = span;
  236.         }
  237.         lastOffs += 1;
  238.         r = (lastOffs <= n) ? c.modelToView(lastOffs) : null;
  239.     }
  240.     return offs;
  241.     }
  242.  
  243.     /**
  244.      * Determine the start of a word for the given location.
  245.      * 
  246.      * @returns the location in the model of the word start.
  247.      */
  248.     static final int getWordStart(JTextComponent c, int offs) throws BadLocationException {
  249.     Document doc = c.getDocument();
  250.     Element line = getParagraphElement(c, offs);
  251.     int lineStart = line.getStartOffset();
  252.     int lineEnd = Math.min(line.getEndOffset(), doc.getLength());
  253.     
  254.     String s = doc.getText(lineStart, lineEnd - lineStart);
  255.     if(s != null && s.length() > 0) {
  256.         BreakIterator words = BreakIterator.getWordInstance();
  257.         words.setText(s);
  258.         int wordPosition = offs - lineStart;
  259.         if(wordPosition >= words.last()) {
  260.         wordPosition = words.last() - 1;
  261.         } 
  262.         words.following(wordPosition);
  263.         offs = lineStart + words.previous();
  264.     }
  265.     return offs;
  266.     }
  267.  
  268.     /**
  269.      * Determine the end of a word for the given location.
  270.      * 
  271.      * @returns the location in the model of the word end.
  272.      */
  273.     static final int getWordEnd(JTextComponent c, int offs) throws BadLocationException {
  274.     Document doc = c.getDocument();
  275.     Element line = getParagraphElement(c, offs);
  276.     int lineStart = line.getStartOffset();
  277.     int lineEnd = Math.min(line.getEndOffset(), doc.getLength());
  278.     
  279.     String s = doc.getText(lineStart, lineEnd - lineStart);
  280.     if(s != null && s.length() > 0) {
  281.         BreakIterator words = BreakIterator.getWordInstance();
  282.         words.setText(s);
  283.         int wordPosition = offs - lineStart;
  284.         if(wordPosition >= words.last()) {
  285.         wordPosition = words.last() - 1;
  286.         } 
  287.         offs = lineStart + words.following(wordPosition);
  288.     }
  289.     return offs;
  290.     }
  291.  
  292.     /**
  293.      * Determine the start of the next word for the given location.
  294.      * 
  295.      * @returns the location in the model of the word start.
  296.      */
  297.     static final int getNextWord(JTextComponent c, int offs) throws BadLocationException {
  298.     Document doc = c.getDocument();
  299.     Element line = getParagraphElement(c, offs);
  300.     int lineStart = line.getStartOffset();
  301.     int lineEnd = Math.min(line.getEndOffset(), doc.getLength());
  302.     String s = doc.getText(lineStart, lineEnd - lineStart);
  303.     if(s != null && s.length() > 0) {
  304.         BreakIterator words = BreakIterator.getWordInstance();
  305.         words.setText(s);
  306.         int wordPosition = offs - lineStart;
  307.         if(wordPosition >= words.last()) {
  308.         wordPosition = words.last() - 1;
  309.         } 
  310.         words.following(wordPosition);
  311.         offs = lineStart + words.next();
  312.     }
  313.     return offs;
  314.     }
  315.  
  316.     /**
  317.      * Determine the start of the next word for the given location.
  318.      * 
  319.      * @returns the location in the model of the word start.
  320.      */
  321.     static final int getPreviousWord(JTextComponent c, int offs) throws BadLocationException {
  322.     Document doc = c.getDocument();
  323.     Element line = getParagraphElement(c, offs);
  324.     int lineStart = line.getStartOffset();
  325.     int lineEnd = Math.min(line.getEndOffset(), doc.getLength());
  326.     String s = doc.getText(lineStart, lineEnd - lineStart);
  327.     if(s != null && s.length() > 0) {
  328.         BreakIterator words = BreakIterator.getWordInstance();
  329.         words.setText(s);
  330.         int wordPosition = offs - lineStart;
  331.         if(wordPosition >= words.last()) {
  332.         wordPosition = words.last() - 1;
  333.         } 
  334.         words.following(wordPosition);
  335.         if (offs == (lineStart + words.previous())) {
  336.         words.previous();
  337.         int o = words.previous();
  338.         if (o == BreakIterator.DONE) {
  339.             offs = lineStart;
  340.         } else {
  341.             offs = lineStart + o;
  342.         }
  343.         }
  344.     }
  345.     return offs;
  346.     }
  347.  
  348.     /**
  349.      * Determine the element to use for a paragraph/line
  350.      */
  351.     static final Element getParagraphElement(JTextComponent c, int offs) {
  352.     Document doc = c.getDocument();
  353.     if (doc instanceof StyledDocument) {
  354.         return ((StyledDocument)doc).getParagraphElement(offs);
  355.     }
  356.     Element map = doc.getDefaultRootElement();
  357.     int index = map.getElementIndex(offs);
  358.     Element paragraph = map.getElement(index);
  359.     return paragraph;
  360.     }
  361.  
  362. }
  363.