asyncboxview.java
来自「linux下建立JAVA虚拟机的源码KAFFE」· Java 代码 · 共 1,481 行 · 第 1/3 页
JAVA
1,481 行
/* AsyncBoxView.java -- A box view that performs layout asynchronously Copyright (C) 2006 Free Software Foundation, Inc.This file is part of GNU Classpath.GNU Classpath is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU Classpath is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Classpath; see the file COPYING. If not, write to theFree Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA02110-1301 USA.Linking this library statically or dynamically with other modules ismaking a combined work based on this library. Thus, the terms andconditions of the GNU General Public License cover the wholecombination.As a special exception, the copyright holders of this library give youpermission to link this library with independent modules to produce anexecutable, regardless of the license terms of these independentmodules, and to copy and distribute the resulting executable underterms of your choice, provided that you also meet, for each linkedindependent module, the terms and conditions of the license of thatmodule. An independent module is a module which is not derived fromor based on this library. If you modify this library, you may extendthis exception to your version of the library, but you are notobligated to do so. If you do not wish to do so, delete thisexception statement from your version. */package javax.swing.text;import java.awt.Component;import java.awt.Graphics;import java.awt.Rectangle;import java.awt.Shape;import java.util.ArrayList;import javax.swing.event.DocumentEvent;import javax.swing.text.Position.Bias;/** * A {@link View} implementation that lays out its child views in a box, either * vertically or horizontally. The difference to {@link BoxView} is that the * layout is performed in an asynchronous manner. This helps to keep the * eventqueue free from non-GUI related tasks. * * This view is currently not used in standard text components. In order to * use it you would have to implement a special {@link EditorKit} with a * {@link ViewFactory} that returns this view. For example: * * <pre> * static class AsyncEditorKit extends StyledEditorKit implements ViewFactory * { * public View create(Element el) * { * if (el.getName().equals(AbstractDocument.SectionElementName)) * return new AsyncBoxView(el, View.Y_AXIS); * return super.getViewFactory().create(el); * } * public ViewFactory getViewFactory() { * return this; * } * } * </pre> * * @author Roman Kennke (kennke@aicas.com) * * @since 1.3 */public class AsyncBoxView extends View{ /** * Manages the effective position of child views. That keeps the visible * layout stable while the AsyncBoxView might be changing until the layout * thread decides to publish the new layout. */ public class ChildLocator { /** * The last valid location. */ protected ChildState lastValidOffset; /** * The last allocation. */ protected Rectangle lastAlloc; /** * A Rectangle used for child allocation calculation to avoid creation * of lots of garbage Rectangle objects. */ protected Rectangle childAlloc; /** * Creates a new ChildLocator. */ public ChildLocator() { lastAlloc = new Rectangle(); childAlloc = new Rectangle(); } /** * Receives notification that a child has changed. This is called by * child state objects that have changed it's major span. * * This sets the {@link #lastValidOffset} field to <code>cs</code> if * the new child state's view start offset is smaller than the start offset * of the current child state's view or when <code>lastValidOffset</code> * is <code>null</code>. * * @param cs the child state object that has changed */ public synchronized void childChanged(ChildState cs) { if (lastValidOffset == null || cs.getChildView().getStartOffset() < lastValidOffset.getChildView().getStartOffset()) { lastValidOffset = cs; } } /** * Returns the view index of the view that occupies the specified area, or * <code>-1</code> if there is no such child view. * * @param x the x coordinate (relative to <code>a</code>) * @param y the y coordinate (relative to <code>a</code>) * @param a the current allocation of this view * * @return the view index of the view that occupies the specified area, or * <code>-1</code> if there is no such child view */ public int getViewIndexAtPoint(float x, float y, Shape a) { setAllocation(a); float targetOffset = (getMajorAxis() == X_AXIS) ? x - lastAlloc.x : y - lastAlloc.y; int index = getViewIndexAtVisualOffset(targetOffset); return index; } /** * Returns the current allocation for a child view. This updates the * offsets for all children <em>before</em> the requested child view. * * @param index the index of the child view * @param a the current allocation of this view * * @return the current allocation for a child view */ public synchronized Shape getChildAllocation(int index, Shape a) { if (a == null) return null; setAllocation(a); ChildState cs = getChildState(index); if (cs.getChildView().getStartOffset() > lastValidOffset.getChildView().getStartOffset()) { updateChildOffsetsToIndex(index); } Shape ca = getChildAllocation(index); return ca; } /** * Paints all child views. * * @param g the graphics context to use */ public synchronized void paintChildren(Graphics g) { Rectangle clip = g.getClipBounds(); float targetOffset = (getMajorAxis() == X_AXIS) ? clip.x - lastAlloc.x : clip.y - lastAlloc.y; int index = getViewIndexAtVisualOffset(targetOffset); int n = getViewCount(); float offs = getChildState(index).getMajorOffset(); for (int i = index; i < n; i++) { ChildState cs = getChildState(i); cs.setMajorOffset(offs); Shape ca = getChildAllocation(i); if (ca.intersects(clip)) { synchronized (cs) { View v = cs.getChildView(); v.paint(g, ca); } } else { // done painting intersection break; } offs += cs.getMajorSpan(); } } /** * Returns the current allocation of the child view with the specified * index. Note that this will <em>not</em> update any location information. * * @param index the index of the requested child view * * @return the current allocation of the child view with the specified * index */ protected Shape getChildAllocation(int index) { ChildState cs = getChildState(index); if (! cs.isLayoutValid()) cs.run(); if (getMajorAxis() == X_AXIS) { childAlloc.x = lastAlloc.x + (int) cs.getMajorOffset(); childAlloc.y = lastAlloc.y + (int) cs.getMinorOffset(); childAlloc.width = (int) cs.getMajorSpan(); childAlloc.height = (int) cs.getMinorSpan(); } else { childAlloc.y = lastAlloc.y + (int) cs.getMajorOffset(); childAlloc.x = lastAlloc.x + (int) cs.getMinorOffset(); childAlloc.height = (int) cs.getMajorSpan(); childAlloc.width = (int) cs.getMinorSpan(); } return childAlloc; } /** * Sets the current allocation for this view. * * @param a the allocation to set */ protected void setAllocation(Shape a) { if (a instanceof Rectangle) lastAlloc.setBounds((Rectangle) a); else lastAlloc.setBounds(a.getBounds()); setSize(lastAlloc.width, lastAlloc.height); } /** * Returns the index of the view at the specified offset along the major * layout axis. * * @param targetOffset the requested offset * * @return the index of the view at the specified offset along the major * layout axis */ protected int getViewIndexAtVisualOffset(float targetOffset) { int n = getViewCount(); if (n > 0) { if (lastValidOffset == null) lastValidOffset = getChildState(0); if (targetOffset > majorSpan) return 0; else if (targetOffset > lastValidOffset.getMajorOffset()) return updateChildOffsets(targetOffset); else { float offs = 0f; for (int i = 0; i < n; i++) { ChildState cs = getChildState(i); float nextOffs = offs + cs.getMajorSpan(); if (targetOffset < nextOffs) return i; offs = nextOffs; } } } return n - 1; } /** * Updates all the child view offsets up to the specified targetOffset. * * @param targetOffset the offset up to which the child view offsets are * updated * * @return the index of the view at the specified offset */ private int updateChildOffsets(float targetOffset) { int n = getViewCount(); int targetIndex = n - 1;; int pos = lastValidOffset.getChildView().getStartOffset(); int startIndex = getViewIndexAtPosition(pos, Position.Bias.Forward); float start = lastValidOffset.getMajorOffset(); float lastOffset = start; for (int i = startIndex; i < n; i++) { ChildState cs = getChildState(i); cs.setMajorOffset(lastOffset); lastOffset += cs.getMajorSpan(); if (targetOffset < lastOffset) { targetIndex = i; lastValidOffset = cs; break; } } return targetIndex; } /** * Updates the offsets of the child views up to the specified index. * * @param index the index up to which the offsets are updated */ private void updateChildOffsetsToIndex(int index) { int pos = lastValidOffset.getChildView().getStartOffset(); int startIndex = getViewIndexAtPosition(pos, Position.Bias.Forward); float lastOffset = lastValidOffset.getMajorOffset(); for (int i = startIndex; i <= index; i++) { ChildState cs = getChildState(i); cs.setMajorOffset(lastOffset); lastOffset += cs.getMajorSpan(); } } } /** * Represents the layout state of a child view. */ public class ChildState implements Runnable { /** * The child view for this state record. */ private View childView; /** * Indicates if the minor axis requirements of this child view are valid * or not. */ private boolean minorValid; /** * Indicates if the major axis requirements of this child view are valid * or not. */ private boolean majorValid; /** * Indicates if the current child size is valid. This is package private * to avoid synthetic accessor method. */ boolean childSizeValid; /** * The child views minimumSpan. This is package private to avoid accessor * method. */ float minimum; /** * The child views preferredSpan. This is package private to avoid accessor * method. */ float preferred; /** * The current span of the child view along the major axis. */ private float majorSpan; /** * The current offset of the child view along the major axis. */ private float majorOffset; /** * The current span of the child view along the minor axis. */ private float minorSpan; /** * The current offset of the child view along the major axis. */ private float minorOffset; /** * The child views maximumSpan. */ private float maximum; /** * Creates a new <code>ChildState</code> object for the specified child * view. * * @param view the child view for which to create the state record */ public ChildState(View view) { childView = view; } /** * Returns the child view for which this <code>ChildState</code> represents * the layout state. * * @return the child view for this child state object */ public View getChildView() { return childView; } /** * Returns <code>true</code> if the current layout information is valid, * <code>false</code> otherwise. * * @return <code>true</code> if the current layout information is valid, * <code>false</code> otherwise */ public boolean isLayoutValid() { return minorValid && majorValid && childSizeValid; } /** * Performs the layout update for the child view managed by this * <code>ChildState</code>. */ public void run() { Document doc = getDocument(); if (doc instanceof AbstractDocument) { AbstractDocument abstractDoc = (AbstractDocument) doc; abstractDoc.readLock(); } try { if (!(minorValid && majorValid && childSizeValid) && childView.getParent() == AsyncBoxView.this) { synchronized(AsyncBoxView.this) { changing = this; } update(); synchronized(AsyncBoxView.this) { changing = null; } // Changing the major axis may cause the minor axis // requirements to have changed, so we need to do this again. update(); } } finally { if (doc instanceof AbstractDocument) { AbstractDocument abstractDoc = (AbstractDocument) doc; abstractDoc.readUnlock(); } } } /** * Performs the actual update after the run methods has made its checks
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?