< prev index next >

src/java.desktop/share/classes/javax/swing/text/FlowView.java

Print this page




  53 
  54     /**
  55      * Constructs a FlowView for the given element.
  56      *
  57      * @param elem the element that this view is responsible for
  58      * @param axis may be either View.X_AXIS or View.Y_AXIS
  59      */
  60     public FlowView(Element elem, int axis) {
  61         super(elem, axis);
  62         layoutSpan = Integer.MAX_VALUE;
  63         strategy = new FlowStrategy();
  64     }
  65 
  66     /**
  67      * Fetches the axis along which views should be
  68      * flowed.  By default, this will be the axis
  69      * orthogonal to the axis along which the flow
  70      * rows are tiled (the axis of the default flow
  71      * rows themselves).  This is typically used
  72      * by the <code>FlowStrategy</code>.


  73      */
  74     public int getFlowAxis() {
  75         if (getAxis() == Y_AXIS) {
  76             return X_AXIS;
  77         }
  78         return Y_AXIS;
  79     }
  80 
  81     /**
  82      * Fetch the constraining span to flow against for
  83      * the given child index.  This is called by the
  84      * FlowStrategy while it is updating the flow.
  85      * A flow can be shaped by providing different values
  86      * for the row constraints.  By default, the entire
  87      * span inside of the insets along the flow axis
  88      * is returned.
  89      *
  90      * @param index the index of the row being updated.
  91      *   This should be a value &gt;= 0 and &lt; getViewCount().


  92      * @see #getFlowStart
  93      */
  94     public int getFlowSpan(int index) {
  95         return layoutSpan;
  96     }
  97 
  98     /**
  99      * Fetch the location along the flow axis that the
 100      * flow span will start at.  This is called by the
 101      * FlowStrategy while it is updating the flow.
 102      * A flow can be shaped by providing different values
 103      * for the row constraints.
 104 
 105      * @param index the index of the row being updated.
 106      *   This should be a value &gt;= 0 and &lt; getViewCount().


 107      * @see #getFlowSpan
 108      */
 109     public int getFlowStart(int index) {
 110         return 0;
 111     }
 112 
 113     /**
 114      * Create a View that should be used to hold a
 115      * a rows worth of children in a flow.  This is
 116      * called by the FlowStrategy when new children
 117      * are added or removed (i.e. rows are added or
 118      * removed) in the process of updating the flow.


 119      */
 120     protected abstract View createRow();
 121 
 122     // ---- BoxView methods -------------------------------------
 123 
 124     /**
 125      * Loads all of the children to initialize the view.
 126      * This is called by the <code>setParent</code> method.
 127      * This is reimplemented to not load any children directly
 128      * (as they are created in the process of formatting).
 129      * If the layoutPool variable is null, an instance of
 130      * LogicalView is created to represent the logical view
 131      * that is used in the process of formatting.
 132      *
 133      * @param f the view factory
 134      */
 135     protected void loadChildren(ViewFactory f) {
 136         if (layoutPool == null) {
 137             layoutPool = new LogicalView(getElement());
 138         }


 342                     try {
 343                         damageStart = fv.getDocument().createPosition(offset);
 344                     } catch (BadLocationException e) {
 345                         // shouldn't happen since offset is inside view bounds
 346                         assert(false);
 347                     }
 348                 }
 349             }
 350         }
 351 
 352         void unsetDamage() {
 353             damageStart = null;
 354         }
 355 
 356         /**
 357          * Gives notification that something was inserted into the document
 358          * in a location that the given flow view is responsible for.  The
 359          * strategy should update the appropriate changed region (which
 360          * depends upon the strategy used for repair).
 361          *

 362          * @param e the change information from the associated document
 363          * @param alloc the current allocation of the view inside of the insets.
 364          *   This value will be null if the view has not yet been displayed.
 365          * @see View#insertUpdate
 366          */
 367         public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) {
 368             // FlowView.loadChildren() makes a synthetic call into this,
 369             // passing null as e
 370             if (e != null) {
 371                 addDamage(fv, e.getOffset());
 372             }
 373 
 374             if (alloc != null) {
 375                 Component host = fv.getContainer();
 376                 if (host != null) {
 377                     host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
 378                 }
 379             } else {
 380                 fv.preferenceChanged(null, true, true);
 381             }
 382         }
 383 
 384         /**
 385          * Gives notification that something was removed from the document
 386          * in a location that the given flow view is responsible for.
 387          *

 388          * @param e the change information from the associated document
 389          * @param alloc the current allocation of the view inside of the insets.
 390          * @see View#removeUpdate
 391          */
 392         public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) {
 393             addDamage(fv, e.getOffset());
 394             if (alloc != null) {
 395                 Component host = fv.getContainer();
 396                 if (host != null) {
 397                     host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
 398                 }
 399             } else {
 400                 fv.preferenceChanged(null, true, true);
 401             }
 402         }
 403 
 404         /**
 405          * Gives notification from the document that attributes were changed
 406          * in a location that this view is responsible for.
 407          *


 409          * @param e      the <code>DocumentEvent</code> describing the changes
 410          *               done to the Document
 411          * @param alloc  Bounds of the View
 412          * @see View#changedUpdate
 413          */
 414         public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) {
 415             addDamage(fv, e.getOffset());
 416             if (alloc != null) {
 417                 Component host = fv.getContainer();
 418                 if (host != null) {
 419                     host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
 420                 }
 421             } else {
 422                 fv.preferenceChanged(null, true, true);
 423             }
 424         }
 425 
 426         /**
 427          * This method gives flow strategies access to the logical
 428          * view of the FlowView.


 429          */
 430         protected View getLogicalView(FlowView fv) {
 431             return fv.layoutPool;
 432         }
 433 
 434         /**
 435          * Update the flow on the given FlowView.  By default, this causes
 436          * all of the rows (child views) to be rebuilt to match the given
 437          * constraints for each row.  This is called by a FlowView.layout
 438          * to update the child views in the flow.
 439          *
 440          * @param fv the view to reflow
 441          */
 442         public void layout(FlowView fv) {
 443             View pool = getLogicalView(fv);
 444             int rowIndex, p0;
 445             int p1 = fv.getEndOffset();
 446 
 447             if (fv.majorAllocValid) {
 448                 if (damageStart == null) {


 478                 rowIndex++;
 479             }
 480             viewBuffer = null;
 481 
 482             if (rowIndex < rowCount) {
 483                 fv.replace(rowIndex, rowCount - rowIndex, null);
 484             }
 485             unsetDamage();
 486         }
 487 
 488         /**
 489          * Creates a row of views that will fit within the
 490          * layout span of the row.  This is called by the layout method.
 491          * This is implemented to fill the row by repeatedly calling
 492          * the createView method until the available span has been
 493          * exhausted, a forced break was encountered, or the createView
 494          * method returned null.  If the remaining span was exhausted,
 495          * the adjustRow method will be called to perform adjustments
 496          * to the row to try and make it fit into the given span.
 497          *

 498          * @param rowIndex the index of the row to fill in with views.  The
 499          *   row is assumed to be empty on entry.
 500          * @param pos  The current position in the children of
 501          *   this views element from which to start.
 502          * @return the position to start the next row
 503          */
 504         protected int layoutRow(FlowView fv, int rowIndex, int pos) {
 505             View row = fv.getView(rowIndex);
 506             float x = fv.getFlowStart(rowIndex);
 507             float spanLeft = fv.getFlowSpan(rowIndex);
 508             int end = fv.getEndOffset();
 509             TabExpander te = (fv instanceof TabExpander) ? (TabExpander)fv : null;
 510             final int flowAxis = fv.getFlowAxis();
 511 
 512             int breakWeight = BadBreakWeight;
 513             float breakX = 0f;
 514             float breakSpan = 0f;
 515             int breakIndex = -1;
 516             int n = 0;
 517 


 561                 spanLeft -= chunkSpan;
 562                 x += chunkSpan;
 563                 viewBuffer.add(v);
 564                 pos = v.getEndOffset();
 565                 n++;
 566             }
 567 
 568             View[] views = new View[viewBuffer.size()];
 569             viewBuffer.toArray(views);
 570             row.replace(0, row.getViewCount(), views);
 571             return (views.length > 0 ? row.getEndOffset() : pos);
 572         }
 573 
 574         /**
 575          * Adjusts the given row if possible to fit within the
 576          * layout span.  By default this will try to find the
 577          * highest break weight possible nearest the end of
 578          * the row.  If a forced break is encountered, the
 579          * break will be positioned there.
 580          *

 581          * @param rowIndex the row to adjust to the current layout
 582          *  span.
 583          * @param desiredSpan the current layout span &gt;= 0
 584          * @param x the location r starts at.
 585          */
 586         protected void adjustRow(FlowView fv, int rowIndex, int desiredSpan, int x) {
 587             final int flowAxis = fv.getFlowAxis();
 588             View r = fv.getView(rowIndex);
 589             int n = r.getViewCount();
 590             int span = 0;
 591             int bestWeight = BadBreakWeight;
 592             int bestSpan = 0;
 593             int bestIndex = -1;
 594             View v;
 595             for (int i = 0; i < n; i++) {
 596                 v = r.getView(i);
 597                 int spanLeft = desiredSpan - span;
 598 
 599                 int w = v.getBreakWeight(flowAxis, x + span, spanLeft);
 600                 if ((w >= bestWeight) && (w > BadBreakWeight)) {


 637         }
 638 
 639         void reparentViews(View pool, int startPos) {
 640             int n = pool.getViewIndex(startPos, Position.Bias.Forward);
 641             if (n >= 0) {
 642                 for (int i = n; i < pool.getViewCount(); i++) {
 643                     pool.getView(i).setParent(pool);
 644                 }
 645             }
 646         }
 647 
 648         /**
 649          * Creates a view that can be used to represent the current piece
 650          * of the flow.  This can be either an entire view from the
 651          * logical view, or a fragment of the logical view.
 652          *
 653          * @param fv the view holding the flow
 654          * @param startOffset the start location for the view being created
 655          * @param spanLeft the about of span left to fill in the row
 656          * @param rowIndex the row the view will be placed into


 657          */
 658         protected View createView(FlowView fv, int startOffset, int spanLeft, int rowIndex) {
 659             // Get the child view that contains the given starting position
 660             View lv = getLogicalView(fv);
 661             int childIndex = lv.getViewIndex(startOffset, Position.Bias.Forward);
 662             View v = lv.getView(childIndex);
 663             if (startOffset==v.getStartOffset()) {
 664                 // return the entire view
 665                 return v;
 666             }
 667 
 668             // return a fragment.
 669             v = v.createFragment(startOffset, v.getEndOffset());
 670             return v;
 671         }
 672     }
 673 
 674     /**
 675      * This class can be used to represent a logical view for
 676      * a flow.  It keeps the children updated to reflect the state




  53 
  54     /**
  55      * Constructs a FlowView for the given element.
  56      *
  57      * @param elem the element that this view is responsible for
  58      * @param axis may be either View.X_AXIS or View.Y_AXIS
  59      */
  60     public FlowView(Element elem, int axis) {
  61         super(elem, axis);
  62         layoutSpan = Integer.MAX_VALUE;
  63         strategy = new FlowStrategy();
  64     }
  65 
  66     /**
  67      * Fetches the axis along which views should be
  68      * flowed.  By default, this will be the axis
  69      * orthogonal to the axis along which the flow
  70      * rows are tiled (the axis of the default flow
  71      * rows themselves).  This is typically used
  72      * by the <code>FlowStrategy</code>.
  73      * @return the axis along which views should be
  74      * flowed
  75      */
  76     public int getFlowAxis() {
  77         if (getAxis() == Y_AXIS) {
  78             return X_AXIS;
  79         }
  80         return Y_AXIS;
  81     }
  82 
  83     /**
  84      * Fetch the constraining span to flow against for
  85      * the given child index.  This is called by the
  86      * FlowStrategy while it is updating the flow.
  87      * A flow can be shaped by providing different values
  88      * for the row constraints.  By default, the entire
  89      * span inside of the insets along the flow axis
  90      * is returned.
  91      *
  92      * @param index the index of the row being updated.
  93      *   This should be a value &gt;= 0 and &lt; getViewCount().
  94      * @return the constraining span to flow against for
  95      * the given child index
  96      * @see #getFlowStart
  97      */
  98     public int getFlowSpan(int index) {
  99         return layoutSpan;
 100     }
 101 
 102     /**
 103      * Fetch the location along the flow axis that the
 104      * flow span will start at.  This is called by the
 105      * FlowStrategy while it is updating the flow.
 106      * A flow can be shaped by providing different values
 107      * for the row constraints.
 108 
 109      * @param index the index of the row being updated.
 110      *   This should be a value &gt;= 0 and &lt; getViewCount().
 111      * @return the location along the flow axis that the
 112      * flow span will start at
 113      * @see #getFlowSpan
 114      */
 115     public int getFlowStart(int index) {
 116         return 0;
 117     }
 118 
 119     /**
 120      * Create a View that should be used to hold a
 121      * a rows worth of children in a flow.  This is
 122      * called by the FlowStrategy when new children
 123      * are added or removed (i.e. rows are added or
 124      * removed) in the process of updating the flow.
 125      * @return a View that should be used to hold a
 126      * a rows worth of children in a flow
 127      */
 128     protected abstract View createRow();
 129 
 130     // ---- BoxView methods -------------------------------------
 131 
 132     /**
 133      * Loads all of the children to initialize the view.
 134      * This is called by the <code>setParent</code> method.
 135      * This is reimplemented to not load any children directly
 136      * (as they are created in the process of formatting).
 137      * If the layoutPool variable is null, an instance of
 138      * LogicalView is created to represent the logical view
 139      * that is used in the process of formatting.
 140      *
 141      * @param f the view factory
 142      */
 143     protected void loadChildren(ViewFactory f) {
 144         if (layoutPool == null) {
 145             layoutPool = new LogicalView(getElement());
 146         }


 350                     try {
 351                         damageStart = fv.getDocument().createPosition(offset);
 352                     } catch (BadLocationException e) {
 353                         // shouldn't happen since offset is inside view bounds
 354                         assert(false);
 355                     }
 356                 }
 357             }
 358         }
 359 
 360         void unsetDamage() {
 361             damageStart = null;
 362         }
 363 
 364         /**
 365          * Gives notification that something was inserted into the document
 366          * in a location that the given flow view is responsible for.  The
 367          * strategy should update the appropriate changed region (which
 368          * depends upon the strategy used for repair).
 369          *
 370          * @param fv the flow view
 371          * @param e the change information from the associated document
 372          * @param alloc the current allocation of the view inside of the insets.
 373          *   This value will be null if the view has not yet been displayed.
 374          * @see View#insertUpdate
 375          */
 376         public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) {
 377             // FlowView.loadChildren() makes a synthetic call into this,
 378             // passing null as e
 379             if (e != null) {
 380                 addDamage(fv, e.getOffset());
 381             }
 382 
 383             if (alloc != null) {
 384                 Component host = fv.getContainer();
 385                 if (host != null) {
 386                     host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
 387                 }
 388             } else {
 389                 fv.preferenceChanged(null, true, true);
 390             }
 391         }
 392 
 393         /**
 394          * Gives notification that something was removed from the document
 395          * in a location that the given flow view is responsible for.
 396          *
 397          * @param fv the flow view
 398          * @param e the change information from the associated document
 399          * @param alloc the current allocation of the view inside of the insets.
 400          * @see View#removeUpdate
 401          */
 402         public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) {
 403             addDamage(fv, e.getOffset());
 404             if (alloc != null) {
 405                 Component host = fv.getContainer();
 406                 if (host != null) {
 407                     host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
 408                 }
 409             } else {
 410                 fv.preferenceChanged(null, true, true);
 411             }
 412         }
 413 
 414         /**
 415          * Gives notification from the document that attributes were changed
 416          * in a location that this view is responsible for.
 417          *


 419          * @param e      the <code>DocumentEvent</code> describing the changes
 420          *               done to the Document
 421          * @param alloc  Bounds of the View
 422          * @see View#changedUpdate
 423          */
 424         public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) {
 425             addDamage(fv, e.getOffset());
 426             if (alloc != null) {
 427                 Component host = fv.getContainer();
 428                 if (host != null) {
 429                     host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
 430                 }
 431             } else {
 432                 fv.preferenceChanged(null, true, true);
 433             }
 434         }
 435 
 436         /**
 437          * This method gives flow strategies access to the logical
 438          * view of the FlowView.
 439          * @param fv the FlowView
 440          * @return the logical view of the FlowView
 441          */
 442         protected View getLogicalView(FlowView fv) {
 443             return fv.layoutPool;
 444         }
 445 
 446         /**
 447          * Update the flow on the given FlowView.  By default, this causes
 448          * all of the rows (child views) to be rebuilt to match the given
 449          * constraints for each row.  This is called by a FlowView.layout
 450          * to update the child views in the flow.
 451          *
 452          * @param fv the view to reflow
 453          */
 454         public void layout(FlowView fv) {
 455             View pool = getLogicalView(fv);
 456             int rowIndex, p0;
 457             int p1 = fv.getEndOffset();
 458 
 459             if (fv.majorAllocValid) {
 460                 if (damageStart == null) {


 490                 rowIndex++;
 491             }
 492             viewBuffer = null;
 493 
 494             if (rowIndex < rowCount) {
 495                 fv.replace(rowIndex, rowCount - rowIndex, null);
 496             }
 497             unsetDamage();
 498         }
 499 
 500         /**
 501          * Creates a row of views that will fit within the
 502          * layout span of the row.  This is called by the layout method.
 503          * This is implemented to fill the row by repeatedly calling
 504          * the createView method until the available span has been
 505          * exhausted, a forced break was encountered, or the createView
 506          * method returned null.  If the remaining span was exhausted,
 507          * the adjustRow method will be called to perform adjustments
 508          * to the row to try and make it fit into the given span.
 509          *
 510          * @param fv the flow view
 511          * @param rowIndex the index of the row to fill in with views.  The
 512          *   row is assumed to be empty on entry.
 513          * @param pos  The current position in the children of
 514          *   this views element from which to start.
 515          * @return the position to start the next row
 516          */
 517         protected int layoutRow(FlowView fv, int rowIndex, int pos) {
 518             View row = fv.getView(rowIndex);
 519             float x = fv.getFlowStart(rowIndex);
 520             float spanLeft = fv.getFlowSpan(rowIndex);
 521             int end = fv.getEndOffset();
 522             TabExpander te = (fv instanceof TabExpander) ? (TabExpander)fv : null;
 523             final int flowAxis = fv.getFlowAxis();
 524 
 525             int breakWeight = BadBreakWeight;
 526             float breakX = 0f;
 527             float breakSpan = 0f;
 528             int breakIndex = -1;
 529             int n = 0;
 530 


 574                 spanLeft -= chunkSpan;
 575                 x += chunkSpan;
 576                 viewBuffer.add(v);
 577                 pos = v.getEndOffset();
 578                 n++;
 579             }
 580 
 581             View[] views = new View[viewBuffer.size()];
 582             viewBuffer.toArray(views);
 583             row.replace(0, row.getViewCount(), views);
 584             return (views.length > 0 ? row.getEndOffset() : pos);
 585         }
 586 
 587         /**
 588          * Adjusts the given row if possible to fit within the
 589          * layout span.  By default this will try to find the
 590          * highest break weight possible nearest the end of
 591          * the row.  If a forced break is encountered, the
 592          * break will be positioned there.
 593          *
 594          * @param fv the flow view
 595          * @param rowIndex the row to adjust to the current layout
 596          *  span.
 597          * @param desiredSpan the current layout span &gt;= 0
 598          * @param x the location r starts at.
 599          */
 600         protected void adjustRow(FlowView fv, int rowIndex, int desiredSpan, int x) {
 601             final int flowAxis = fv.getFlowAxis();
 602             View r = fv.getView(rowIndex);
 603             int n = r.getViewCount();
 604             int span = 0;
 605             int bestWeight = BadBreakWeight;
 606             int bestSpan = 0;
 607             int bestIndex = -1;
 608             View v;
 609             for (int i = 0; i < n; i++) {
 610                 v = r.getView(i);
 611                 int spanLeft = desiredSpan - span;
 612 
 613                 int w = v.getBreakWeight(flowAxis, x + span, spanLeft);
 614                 if ((w >= bestWeight) && (w > BadBreakWeight)) {


 651         }
 652 
 653         void reparentViews(View pool, int startPos) {
 654             int n = pool.getViewIndex(startPos, Position.Bias.Forward);
 655             if (n >= 0) {
 656                 for (int i = n; i < pool.getViewCount(); i++) {
 657                     pool.getView(i).setParent(pool);
 658                 }
 659             }
 660         }
 661 
 662         /**
 663          * Creates a view that can be used to represent the current piece
 664          * of the flow.  This can be either an entire view from the
 665          * logical view, or a fragment of the logical view.
 666          *
 667          * @param fv the view holding the flow
 668          * @param startOffset the start location for the view being created
 669          * @param spanLeft the about of span left to fill in the row
 670          * @param rowIndex the row the view will be placed into
 671          * @return a view that can be used to represent the current piece
 672          * of the flow
 673          */
 674         protected View createView(FlowView fv, int startOffset, int spanLeft, int rowIndex) {
 675             // Get the child view that contains the given starting position
 676             View lv = getLogicalView(fv);
 677             int childIndex = lv.getViewIndex(startOffset, Position.Bias.Forward);
 678             View v = lv.getView(childIndex);
 679             if (startOffset==v.getStartOffset()) {
 680                 // return the entire view
 681                 return v;
 682             }
 683 
 684             // return a fragment.
 685             v = v.createFragment(startOffset, v.getEndOffset());
 686             return v;
 687         }
 688     }
 689 
 690     /**
 691      * This class can be used to represent a logical view for
 692      * a flow.  It keeps the children updated to reflect the state


< prev index next >