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

  1. /*
  2.  * @(#)CompositeView.java    1.28 98/01/09
  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.util.Vector;
  23. import java.awt.*;
  24. import com.sun.java.swing.event.*;
  25.  
  26. /**
  27.  * A view of a text model that has a children
  28.  * box.  If the box is vertical, it might be useful to represent
  29.  * something like a collection of lines or paragraphs.  If the
  30.  * box is horizontal, it might be used to represent unwrapped
  31.  * lines.
  32.  *
  33.  * @author  Timothy Prinzing
  34.  * @version 1.28 01/09/98
  35.  */
  36. public abstract class CompositeView extends View {
  37.  
  38.     /**
  39.      * Constructs a JCompositeView for the given element.
  40.      *
  41.      * @param elem  the element this view is responsible for
  42.      */
  43.     public CompositeView(Element elem) {
  44.     super(elem);
  45.     children = new View[1];
  46.     nchildren = 0;
  47.  
  48.     }
  49.  
  50.     /**
  51.      * Loads all of the children to initialize the view.
  52.      * This is called by the <code>setParent</code> method.
  53.      * Subclasses can reimplement this to initialize their
  54.      * child views in a different manner.  The default
  55.      * implementation creates a child view for each 
  56.      * child element.
  57.      *
  58.      * @param f the view factory
  59.      */
  60.     protected void loadChildren(ViewFactory f) {
  61.     Element e = getElement();
  62.     int n = e.getElementCount();
  63.     if (n > 0) {
  64.         View[] added = new View[n];
  65.         for (int i = 0; i < n; i++) {
  66.         added[i] = f.create(e.getElement(i));
  67.         }
  68.         replace(0, 0, added);
  69.     }
  70.     }
  71.  
  72.     /**
  73.      * Removes all of the children.
  74.      */
  75.     public void removeAll() {
  76.     replace(0, nchildren, ZERO);
  77.     }
  78.  
  79.     /**
  80.      * Inserts a single child view.
  81.      *
  82.      * @param offs the offset
  83.      * @param v the view
  84.      */
  85.     public void insert(int offs, View v) {
  86.     ONE[0] = v;
  87.     replace(offs, 0, ONE);
  88.     }
  89.  
  90.     /**
  91.      * Appends a single child view.
  92.      *
  93.      * @param v the view
  94.      */
  95.     public void append(View v) {
  96.     ONE[0] = v;
  97.     replace(nchildren, 0, ONE);
  98.     }
  99.  
  100.     /**
  101.      * Invalidates the layout and resizes the cache of requests/allocations.
  102.      *
  103.      * @param offset the starting offset into the child views
  104.      * @param length the length
  105.      * @param views the child views
  106.      */
  107.     public void replace(int offset, int length, View[] views) {
  108.     // update parent reference on removed views
  109.     for (int i = offset; i < offset + length; i++) {
  110.         children[i].setParent(null);
  111.     }
  112.     
  113.     // update the array
  114.     int delta = views.length - length;
  115.     int src = offset + length;
  116.     int nmove = nchildren - src;
  117.     int dest = src + delta;
  118.     if ((nchildren + delta) >= children.length) {
  119.         // need to grow the array
  120.         int newLength = Math.max(2*children.length, nchildren + delta);
  121.         View[] newChildren = new View[newLength];
  122.         System.arraycopy(children, 0, newChildren, 0, offset);
  123.         System.arraycopy(views, 0, newChildren, offset, views.length);
  124.         System.arraycopy(children, src, newChildren, dest, nmove);
  125.         children = newChildren;
  126.     } else {
  127.         // patch the existing array
  128.         System.arraycopy(children, src, children, dest, nmove);
  129.         System.arraycopy(views, 0, children, offset, views.length);
  130.     }
  131.     nchildren = nchildren + delta;
  132.  
  133.     // update parent reference on added views
  134.     for (int i = 0; i < views.length; i++) {
  135.         views[i].setParent(this);
  136.     }
  137.     }
  138.  
  139.     // --- View methods ---------------------------------------------
  140.  
  141.     /**
  142.      * Sets the parent of the view.
  143.      * This is reimplemented to provide the superclass
  144.      * behavior as well as calling the <code>loadChildren</code>
  145.      * method.  The children should not be loaded in the 
  146.      * constructor because the act of setting the parent
  147.      * may cause them to try to search up the hierarchy
  148.      * (to get the hosting Container for example).
  149.      *
  150.      * @param parent the parent of the view
  151.      */
  152.     public void setParent(View parent) {
  153.     super.setParent(parent);
  154.     if (parent != null) {
  155.         ViewFactory f = getViewFactory();
  156.         loadChildren(f);
  157.     }
  158.     }
  159.  
  160.     /** 
  161.      * Returns the number of views in this view.
  162.      *
  163.      * @return the number of views
  164.      * @see #getView
  165.      */
  166.     public int getViewCount() {
  167.     return nchildren;
  168.     }
  169.  
  170.     /** 
  171.      * Gets the n-th view in this container.
  172.      *
  173.      * @param n the number of the view to get
  174.      * @return the view
  175.      */
  176.     public View getView(int n) {
  177.     return children[n];
  178.     }
  179.  
  180.     /**
  181.      * Fetches the allocation for the given child view. 
  182.      * This enables finding out where various views
  183.      * are located, without assuming the views store
  184.      * their location.  
  185.      *
  186.      * @param index the index of the child
  187.      * @param a  the allocation to this view.
  188.      * @return the allocation to the child
  189.      */
  190.     public Shape getChildAllocation(int index, Shape a) {
  191.     Rectangle alloc = a.getBounds();
  192.     childAllocation(index, alloc);
  193.     return alloc;
  194.     }
  195.  
  196.     /**
  197.      * Provides a mapping from the document model coordinate space
  198.      * to the coordinate space of the view mapped to it.
  199.      *
  200.      * @param pos the position to convert
  201.      * @param a the allocated region to render into
  202.      * @return the bounding box of the given position
  203.      * @exception BadLocationException  if the given position does not represent a
  204.      *   valid location in the associated document
  205.      * @see View#modelToView
  206.      */
  207.     public Shape modelToView(int pos, Shape a) throws BadLocationException {
  208.     Rectangle alloc = getInsideAllocation(a);
  209.     View v = getViewAtPosition(pos, alloc);
  210.     if (v != null) {
  211.         int p0 = v.getStartOffset();
  212.         int p1 = v.getEndOffset();
  213.         if ((pos >= p0) && (pos < p1)) {
  214.         // get the childs idea of the coordinates
  215.         return v.modelToView(pos, alloc);
  216.         }
  217.     }
  218.     throw new BadLocationException("Position not represented by view", pos);
  219.     }
  220.  
  221.     /**
  222.      * Provides a mapping from the view coordinate space to the logical
  223.      * coordinate space of the model.
  224.      *
  225.      * @param x   x coordinate of the view location to convert
  226.      * @param y   y coordinate of the view location to convert
  227.      * @param a the allocated region to render into
  228.      * @return the location within the model that best represents the
  229.      *  given point in the view
  230.      * @see View#viewToModel
  231.      */
  232.     public int viewToModel(float x, float y, Shape a) {
  233.     Rectangle alloc = getInsideAllocation(a);
  234.     if (isBefore((int) x, (int) y, alloc)) {
  235.         // point is before the range represented
  236.         return getStartOffset();
  237.     } else if (isAfter((int) x, (int) y, alloc)) {
  238.         // point is after the range represented.
  239.         return getEndOffset() -1;
  240.     } else {
  241.         // locate the child and pass along the request
  242.         View v = getViewAtPoint((int) x, (int) y, alloc);
  243.         if (v != null) {
  244.           return v.viewToModel(x, y, alloc);
  245.         }
  246.     }
  247.     return -1;
  248.     }
  249.  
  250.     // --- local methods ----------------------------------------------------
  251.  
  252.  
  253.     /**
  254.      * Tests whether a point is before the rectangle range.
  255.      *
  256.      * @param x the X coordinate
  257.      * @param y the Y coordinate
  258.      * @param alloc the rectangle
  259.      * @return true if the point is before the specified range
  260.      */
  261.     protected abstract boolean isBefore(int x, int y, Rectangle alloc);
  262.  
  263.     /**
  264.      * Tests whether a point is after the rectangle range.
  265.      *
  266.      * @param x the X coordinate
  267.      * @param y the Y coordinate
  268.      * @param alloc the rectangle
  269.      * @return true if the point is after the specified range
  270.      */
  271.     protected abstract boolean isAfter(int x, int y, Rectangle alloc);
  272.  
  273.     /**
  274.      * Fetches the child view at the given point.
  275.      *
  276.      * @param x the X coordinate
  277.      * @param y the Y coordinate
  278.      * @param alloc the parent's allocation on entry, which should
  279.      *   be changed to the child's allocation on exit
  280.      * @return the child view
  281.      */
  282.     protected abstract View getViewAtPoint(int x, int y, Rectangle alloc);
  283.  
  284.     /**
  285.      * Returns the allocation for a given child.
  286.      *
  287.      * @param index the index of the child
  288.      * @param a  the allocation to the interior of the box on entry, 
  289.      *   and the allocation of the view containing the position on exit
  290.      */
  291.     protected abstract void childAllocation(int index, Rectangle a);
  292.  
  293.     /**
  294.      * Fetches the child view that represents the given position in
  295.      * the model.  This is implemented to fetch the view in the case
  296.      * where there is a child view for each child element.
  297.      *
  298.      * @param pos the position
  299.      * @param a  the allocation to the interior of the box on entry, 
  300.      *   and the allocation of the view containing the position on exit
  301.      * @returns  the view representing the given position, or 
  302.      *   null if there isn't one
  303.      */
  304.     protected View getViewAtPosition(int pos, Rectangle a) {
  305.     Element elem = getElement();
  306.     int index = elem.getElementIndex(pos);
  307.     Element child = elem.getElement(index);
  308.     if ((child != null) && (index < getViewCount())) {
  309.         View v = getView(index);
  310.         if (v.getElement() == child) {
  311.         if (a != null) {
  312.             childAllocation(index, a);
  313.         }
  314.         return v;
  315.         }
  316.     }
  317.     return null;
  318.     }
  319.  
  320.     /**
  321.      * Translates the allocation given to the view to the allocation used
  322.      * for composing the interior.  This takes into account any 
  323.      * margins that were specified.
  324.      *
  325.      * @param a The allocation given to the view.
  326.      * @returns The allocation that represents the inside of the 
  327.      *   view after the margins have all been removed.  If the
  328.      *   given allocation was null, the return value is null.
  329.      */
  330.     protected Rectangle getInsideAllocation(Shape a) {
  331.     if (a != null) {
  332.         Rectangle alloc = new Rectangle(a.getBounds());
  333.         alloc.x += left;
  334.         alloc.y += top;
  335.         alloc.width -= left + right;
  336.         alloc.height -= top + bottom;
  337.         return alloc;
  338.     }
  339.     return null;
  340.     }
  341.  
  342.     /**
  343.      * Sets the insets from the paragraph attributes specified in
  344.      * the given attributes.
  345.      *
  346.      * @param attr the attributes
  347.      */
  348.     protected final void setParagraphInsets(AttributeSet attr) {
  349.     // Since version 1.1 doesn't have scaling and assumes 
  350.     // a pixel is equal to a point, we just cast the point
  351.     // sizes to integers.
  352.     top = (short) StyleConstants.getSpaceAbove(attr);
  353.     left = (short) StyleConstants.getLeftIndent(attr);
  354.     bottom = (short) StyleConstants.getSpaceBelow(attr);
  355.     right = (short) StyleConstants.getRightIndent(attr);
  356.     }
  357.  
  358.     /**
  359.      * Sets the insets for the view.
  360.      *
  361.      * @param top the top inset
  362.      * @param left the left inset
  363.      * @param bottom the bottom inset
  364.      * @param right the right inset
  365.      */
  366.     protected final void setInsets(short top, short left, short bottom, short right) {
  367.     this.top = top;
  368.     this.left = left;
  369.     this.right = right;
  370.     this.bottom = bottom;
  371.     }
  372.  
  373.     /**
  374.      * Gets the left inset.
  375.      *
  376.      * @return the inset
  377.      */
  378.     protected final short getLeftInset() {
  379.     return left;
  380.     }
  381.  
  382.     /**
  383.      * Gets the right inset.
  384.      *
  385.      * @return the inset
  386.      */
  387.     protected final short getRightInset() {
  388.     return right;
  389.     }
  390.  
  391.     /**
  392.      * Gets the top inset.
  393.      *
  394.      * @return the inset
  395.      */
  396.     protected final short getTopInset() {
  397.     return top;
  398.     }
  399.  
  400.     /**
  401.      * Gets the bottom inset.
  402.      *
  403.      * @return the inset
  404.      */
  405.     protected final short getBottomInset() {
  406.     return bottom;
  407.     }
  408.  
  409.  
  410.     // ---- member variables ---------------------------------------------
  411.  
  412.     private static View[] ONE = new View[1];
  413.     private static View[] ZERO = new View[0];
  414.     
  415.     private View[] children;
  416.     private int nchildren;
  417.     private short left;
  418.     private short right;
  419.     private short top;
  420.     private short bottom;
  421. }
  422.