Java Drawing DrawTop

Language

JP  US  UK

 

Line Breaker

 H. Jyounishi, Tokyo Japan
 

Frame (Index), No frame                 version:0.3(latest)  

Summary: The classes on this page provide the convenient methods for handling the java.text.AttributedString and java.text.AttributedCharacterIterator.
Relevant major classes of Java SE: java.awt.event.MouseListener, MouseMotionListener, MouseEvent
Classes on this page: LineBreaker, Line, StringTokenizerEx, CaretPosition


1. Class LineBreaker return=>page top
1.1 Overview

The attributed string (styled text) is broken into multiple lines which it the rectafngle area by the java.awt.font.LineBreakMeasurer. The LineBreakMeasurer doesn't break the attributed string at "\n" (line feed), so we prepare some special methods for handling "\n" (line feed).
The multiple lines are represented by the array of java.awt.font.TextLayout objects (TextLayout[] textLayouts) and the positions of the TextLayout objects are stored in the array of Point2D objects (Point2D[] textLayoutPositions). The textLayoutPositions[n] represents the left lower position of the corresponding TextLayout object (Figure 1.1 (a)), exactly it's the left position on the baseline (Figure 1.1 (b)).

: Text index, line index and column index.
Each index is represented by the following variable:
◦ textIndex - text index。
◦ lineindex - line index which is determined by the Linebreaker.
◦ columnIndex - local text index in the specified line which is determined by the Linebreaker.
: Line feed("\n")

A line feed is inserted by pressing enter key. The line feeds are placed such as the above figure. They aren't displayed on the canvas.

(a)TextLayout objects


(b) The parameters of TextLayout

Figure 1.1 LineBreaker


1.2 API
public class LineBreaker

Field

Description

textIterator private AttributedCharacterIterator textIterator
The text to be displayed.
textBox private TextBox textBox
The TextBox object which uses this LineBreaker object.
textArea private Rectangle2D textArea
The rectangle area in which the text is displayed.
textAlign private int textAlign
The text align. Left align: 0. Center Align; 1, Right align: 2.
lineSpace private int lineSpace
The line space.
lineList private ArrayList lineList
The ArrayList which stores Line objects.
widthLimit private int widthLimit=5
If the width of the textArea is 0, then the text wrapping width is given by this value.

Method Description
Constructor public LineBreaker(){}
setData public void setData(AttributedCharacterIterator textIterator, textBox textBox)
◦ Sets the textBox to the corresponding fields.

Gets values from the TextBox object and sets them to the textArea, textAlign and lineSpace fields.

◦ If the textIterator parameter isn't null, then calls the createMultipleLines method.
createMultipleLines private void createMultipleLines()
∙ Calls the createLineBreakPositions method.

Returns the line break positions (int[] breakPositions).


∙ Creates new TextLayout objects corresponding the multiple lines based on the line break positions and save them to the array (TextLayout[] textLayouts).

Gets the attributed string by the AttributedStringUtil.getTextLayoutString method.

: "\n" (Line feed) stored in a TextLayout object
The characters in a TextLayout are displayed on the DrawPanel by the TextLayout.draw method in the TextBox.drawText method. However, the "\n" in the TextLayout isn't display at all and "\n" can't be selected by the TextLayout.hitTestChar method in the TextBox.setCaretPositionOrSelection.
For this reason, "\n" is replaced with " "(space) or in AttributedStringUtil.getTextLayoutString method and displayed on the DrawPanel.

∙ Calls the createTextLayoutPositions method and saves the left lower positions of the TextLayout objects to the array (Point2D[] textLayoutPositions).

Point2D[] textLayoutPositions=createTextLayoutPositions(textLayouts);


∙ Creates new Line objects having all information of the lines and save the objects to the lineList.

Line line=new Line(breakPositions[i], breakPositions[i+1], textLayoutPositions[i], textLayouts[i], layoutStrings[i]);

createLineBreakPositions private int[] createLineBreakPositions(AttributedCharacterIterator textIterator,
float formatWidth)

Parameters:
textIterator - Same as the textIterator field.
formatWidth - The width of rectangle area in which the text is displayed.
Returns:
The line break positions.
Processing:
∙ Gets the string from the textIterator by the AttributedStringUtil.getString method and creates the StringTokenizerEx object with the string to break the string at "\n" (line feed)
∙ Gets the sub string which was broken at "\n" by the nextToken of the StringTokenizerEx and creates the java.awt.font.LineBreakMeasurer object.

The break positions can be got by the nextOffset method of the LineBreakMeasurer.

createTextLayoutPositions private Point2D[] createTextLayoutPositions(TextLayout[] layout)
Allocates the positions of the TextLayout objects (TextLayout[] textLayouts) from the left upper position of the textArea. To determine the positions, the getAscent, getAdvance and getDescent methods of the TextLayout are used.
createTextLayoutBounds private Rectangle2D[] createTextLayoutBounds(TextLayout[] layout, Point2D[] textLayoutPositions)
Returns the array of the Rectangle2D objects, each of which encloses the corresponding TextLayout object.
getString public String getString(CharacterIterator iterator, int begin, int end)
Returns the string of the [start, end] range of the textIterator.
getTextLayouts public TextLayout[] getTextLayouts()
Returns the array of the TextLayout objects. If there is no TextLayout object, return the array of 0-length.
getTextLayout public TextLayout getTextLayout(int lineIndex)
Returns the TextLayout object specified by the lineIndex.
getTextLayoutStrings public String[] getTextLayoutStrings()
Returns the array of the strings which are stored in the TextLayout objects.
To get the string, the Line.getTextLayoutString method is used.
getTextLayoutString
public String getTextLayoutString(int lineIndex)
Parameter:
lineIndex - The line index (lineIndex=0,1, 2,....)
Returns:
Returns the string which is stored in the TextLayout object specified by the lineIndex).
To get the string, the Line.getTextLayoutString method is used.
getPreceedingString private String getPreceedingString(int lineIndex, int columnIndex)
Parameter:
lineIndex - The line index (lineIndex=0,1, 2,....)
columnIndex - The character index in the lineIndex-th TextLayout object (textLayouts[lineIndex])
Returns:
The sub-string of the textIterator from top to the columnIndex-th character of the lineIndex-th TextLayout object (textLayouts[lineIndex]).
getPreceedingCharacter private String getPreceedingCharacter(int lineIndex, int columnIndex)
Parameter:
lineIndex - The line index (lineIndex=0,1, 2,....)
columnIndex - The character index in the lineIndex-th TextLayout object (textLayouts[lineIndex])
Returns:
The character of the textIterator at (lineIndex, columnIndex).
See (lineIndex, columnIndex) => Usage of the CaretPosition
getTextLayoutPositions public Point2D[] getTextLayoutPositions()
Returns the array of the positions of the TextLayout objects.
The position of the TextLayout object represents the left lower position of the TextLayout object (Figure 5.1 (a) textLayoutPositions[n]), exactly it's the left position on the baseline (Figure 5.1 (b)).
getBounds public Rectangle2D[] getBounds()
Returns the array the rectangles, each of which encloses the TextLayout object.
getBounds public Rectangle2D getBounds(int index)
returns the rectangle which encloses the index-th TextLayout object.
getCharacterCount public int getCharacterCount()
Retruns the number of the characters of the textIterator.
getCharacterCount public int getCharacterCount(int lineIndex)
Returns the number of the characters of the lineIndex-th line.
getCharacterCount public int getCharacterCount(int lineIndex, int columnIndex)
Returns the number of the characters of the textIterator from the top to (lineIndex, columnIndex.
(lineIndex, columnIndex) => Fig 5.1
getLineColumnIndices public int[] getLineColumnIndices(int textIndex)
Returns the line index and the column index which are converted from the text index (textIndex).
The returned int array indices stores the line index at indices[0] and the column index at indices[1].
getTextIndex public int getTextIndex(int lineIndex, int columnIndex)
Returns the text index which is converted from the line index (lineIndex) and the column index (columnIndex).
See (lineIndex, columnIndex) => Fig 5.1
updateCaretPosition public CaretPosition updateCaretPosition(int textIndex)
Deprecated. Uses CaretPosition.updateCaretPosition.

Parameter:
textIndex - the text index.
Returns:
The CaretPosition object.
Processing:
This method can be performed easily by using the above getLineColumnIndices method.
getOffsetCaretPosition public CaretPosition getOffsetCaretPosition(CaretPosition caretPosition, int offset)
Deprecated. Uses CaretPosition.columnOffset.

Parameter:
caretPosition - The CaretPosition object representing the current text cursor (caret) position.
offset - The offset value for the new cursor (caret) position. Minus offset is available.
Returns:
The CaretPosition object which represents the offset text cursor (caret) position from the current text cursor (caret) position.
Processing:
The method is called by the keyPressed method of the TextBox to move the text cursor (caret) to leftward or rightward.
getOffsetCaretPosition private CaretPosition getOffsetCaretPosition(int lineIndex, int columnIndex, int offset)
Deprecated. Uses CaretPosition.offsetCaretPosition.

Parameter:
lineIndex - The line index (lineIndex=0,1, 2,....)
columnIndex - The character index in the lineIndex-th TextLayout object (textLayouts[lineIndex])
(columnIndex=1, 2,....)
offset - The offset value for the new cursor (caret) position. Minus offset is available.
Returns:
The CaretPosition object which represents the offset text cursor (caret) position from the position of the (lineIndex, columnIndex).
Processing:
Returns the returned value of the updateCaretPosition.
getLineOffsetCaret
Position
public CaretPosition getLineOffsetCaretPosition(CaretPosition caretPosition, int lineOffset)
Deprecated. Uses CaretPosition.lineOffset.

Parameter:
caretPosition - The CaretPosition object representing the current text cursor (caret) position.
lineOffset - The line offset value for the new cursor (caret) position. Minus offset is available.
Returns:
The CaretPosition object which represents the offset text cursor (caret) position by line from the current text cursor (caret) position.
Processing:
The method is called by the keyPressed method of the TextBox to move the text cursor (caret) to upper or lower.
getCaretRectangle public Rectangle getCaretRectangle(CaretPosition caretPosition, int offset)
Parameter:
caretPosition - The CaretPosition object representing the current text cursor (caret) position.
offset - The offset value for the new cursor (caret) position. Minus offset is available.
Returns:
The Rectangle object which represents the shape of the offset text cursor(caret).
Processing:
The method is called by the getTextLocation and drawCaret methods of the TextBox. The offset value is used when the composed text exists and the text cursor (caret) should be drawn after the composed text.

(a) If the textIterator equals null, then performs the following.

This case happens when the textBox has no text. That is when the textBox was newly created or when the text in the textBox was completely deleted (Case (a)).
In this case the attributed string(Java Class AttributedString) doesn't exist in the textArea of the textBox, especially the appropriate height of the caret rectangle is unknown. So this method creates a temporal TextLayout object storing also the temporal attributed string of a space character and determine the height of the caret rectangle by the ascent and descent (Figure 1.1 (b)) of the temporal TextLayout. As the result, the left upper position of the textArea is assigned to position of the caret rectangle, the (ascent + descent) to the height of caret rectangle and 0 to its width.


(b) If the parameter: caretPosition points inside a existing line, then performs the following.

This case happens when at least one of the composed text and committed text is being displayed (Case (b)).
This method gets the caret shape by the getCaretShapes method of the TextLayout as follow.
Shape[] carets=textLayout.getCaretShapes(index);
And creates the caret rectangle by using the return value: carets[0].


(c)If the parameter: caretPosition points the end of a line, then performs the following.

In this case, this method displays the caret at the beginning of the next line (Case (c)).
This method gets the caret rectangle in the same way as in (b), and changes its position to the beginning of the next line. This processing can be calculated from ascent, descent and lineSpace values.


Case (a) Case (b) Case (c)
Figure Caret rectangle (red mark)
printTextLayoutPositions public void printTextLayoutPositions()
Prints the positions of the TextLayout objects for debug.
printTextLayouts public void printTextLayouts()
Prints the number of characters, the characters and so on of the TextLayout objects for debug.
printBounds public void printBounds()
Prints the bounds of the TextLayout objects for debug.
rangeCheck private void rangeCheck(int index, int indexMax) throws RangeException
If index>indexMax, this method throws the RangeException.
The purpose of this simple method is to call e.printStackTrace() when an error is detected.
textRangeError private boolean textRangeError(int lineIndex, String errMessage)
If textIndex>(the number of the characters in the textIterator), this method outputs the error message and the StackTrace.
lineRangeError private boolean lineRangeError(int lineIndex, String errMessage)
If lineIndex>this.lineList.size(), this method outputs the error message and the StackTrace.
lineColumnRangeError private boolean lineColumnRangeError(int lineIndex, int columnIndex, String errMessage)
If lineIndex>this.lineList.size() or columnIndex>columMax, this method outputs the error message and the StackTrace.


1.3 RangeException - Inner class of LineBreaker
code

class RangeException extends Exception {
RangeException() {}
public String toString() {
return "range Exception";
}
}



2. Class Line return=>page top
public class Line
This class represents the text line created by the LineBreaker.
Field Description
startCharPosition int startCharPosition
The text cursor (caret) position at the start of this line in the committed text.
endCharPosition int endCharPosition
The text cursor (caret) position at the end of this line in the committed text.
textLayoutPosition Point2D textLayoutPosition
The left edge point of the TextLayout object.
textLayout TextLayout textLayout
The TextLayout object of this line.
textLayoutString String textLayoutString
The text string of this line.

Method Description
Constructor public Line(int startCharPosition, int endCharPosition, Point2D textLayoutPosition, TextLayout textLayout, String textLayoutString)
Sets the parameters to the corresponding fields.
getStartCharPosition public int getStartCharPosition()
Returns the startCharPosition field.
getEndCharPosition public int getEndCharPosition()
Returns the endCharPosition field.
getTextLayoutPosition public Point2D getTextLayoutPosition()
Returns the textLayoutPosition field.
getTextLayout public TextLayout getTextLayout()
Returns the textLayout field.
getTextLayoutString public String getTextLayoutString()
Returns the ttextLayoutString field.


3. Class StringTokenizerEx return=>page top
public class StringTokenizerEx

The class performs the similar functions as the java.util.StringTokenizer. This class provides the methods which can break attributed text into lines at "\n"(line feed), if the "\n"(line feed) is specified as a delimiter. This class is used by the LineBreaker.

Field Description
str String str:The text to be broken into lines.
delim String delim:The delimiter string.
index int index:The index in the text.

Method Description
Constructor public StringTokenizerEx(String str, String delim)
Sets the parameters to the corresponding fields.
hasMoreTokens public boolean hasMoreTokens()
Tests if there are more tokens available from the str.
nextToken public String nextToken()
Returns the next token.


4. Class CaretPosition return=>page top
4.1 Usage of the CaretPosition
(1) The text cursor (caret) position

The text cursor (caret) position can be represented by the following two forms.

(a) Using the text index (one dimensional representation)

Let's denote the text index as textIndex (textIndex=0,1,...). The cursor position is denoted as textIndex before the textIndex-th character and denoted as textIndex+1 behind the textIndex-th character.

(b) Using the line index and the position in the line (two dimensional representation)

Let's denote the line index as lineIndex (lineIndex=0,1,2...,n) and the position in the line (local text index) as columnIndex
The two dimensional indexing of (lineIndex, columnIndex) determines the text cursor (caret) position.

(2) The conversion between textIndex and (lineIndex, columnIndex).

The (lineIndex, columnIndex) and the textIndex are one-to-one correspondence except the start position or the end position of the line, therefore they can generally be converted each other. It is necessary for this conversion to refer the array of the TextLayout objects given by the LineBreaker.


∙ (lineIndex, columnIndex)=> textIndex

Uses the LineBreaker.getTextIndext method.


∙ textIndex => (lineIndex, columnIndex)

Uses the LineBreaker.getLineColumnIndices method.


4.2 API
Hereafter, we represent the indexes of (i, j) and k as the variables of (lineIndex, index) and textIndex.
public class CaretPosition
Field Description
lineIndex int lineIndex=-1
The number of the TexyLayout object which corresponds the line number and on which the text cursor exists. The number of -1 means that no TexyLayout object exists.
columnIndex int columnIndex=-1
The text cursor position in the lineIndex-thTexyLayout object.
textIndex int textIndex=-1
The text cursor position in the text to be displayed.
lineFeedOption boolean lineFeedOption
If lineFeedOption==true and the text cursor (caret) position is located just behind a \n (line feed), then the cursor's position is automatically changed to the top position of the next line.

String str="";
if(lineFeedOption&&columnIndex>0){
str=lineBreaker.getPreceedingCharacter(lineIndex, columnIndex);
if(str.equals("\n")){
lineIndex++;
columnIndex=0;
}
}


: lineFeedOption
If the CaretPosition object is used for an ordinary word prosessor, sets true to the lineFeedOption.
If the two CaretPosition objects is used to show the bound of a selected text, sets false to the lineFeedOption. In this case, the first CaretPosition object specifies the position just before the top character of the selected text and the second object specifies the position just behind the last character of the selected text,
See => TextBox.selStart, TextBox.selEnd

Method Description
Constructor public CaretPosition(int lineIndex, int columnIndex)
The constructor is used to create a trivial CaretPosition object such as new CaretPosition(-1, -1), new CaretPosition(0, 0) or so on.
To create an object in which the textindex is consistent with the lineIndex and the lineColumnIndex, uses the CaretPosition.getCaretPosition static method.
Constructor public CaretPosition(int lineIndex, int columnIndex, boolean lineFeedOption)
Constructor public CaretPosition(int lineIndex, int columnIndex, int textIndex)
Constructor public CaretPosition(int lineIndex, int columnIndex, int textIndex, boolean lineFeedOption)
isValid public boolean isValid()
Returns true if lineindex>=0, columnIndex>=0 and textIndex>=0.
getLineIndex public int getLineIndex()
Returns the lineIndex.
getColumnIndex public int getColumnIndex()
Returns the positionInLine.
getTextIndex public int getTextIndex()
Returns the textIndex.
resetPosition public void resetPosition()
Sets 0 to all the field variablres.
updateCaretPosition public void updateCaretPosition(int newTextIndex, LineBreaker lineBreaker, String callFrom)
Parameter:

newTextIndex - The text index.
lineBreaker - The LineBreaker object.
callFrom - This is used for debug.
Returns:
The CaretPosition object.
Processing:
This method updates the field variables of the lineIndex and columIndex for the given newTextIndex.
This method calls the LineBreaker,.getLineColumnIndices method.
columnOffset public void columnOffset(int offset, LineBreaker lineBreaker) Parameter:
offset - the horizontal offset value. Minus offset is available.
lineBreaker - the LineBreaker object.
Processing:
The method is called by the TextBox.keyPressed method of the TextBox to move the text cursor (caret) to leftward or rightward. This method is performed by calling the offsetCaretposition method.
offsetCaretPosition private void offsetCaretPosition(int lineIndex, int columnIndex, int offset, LineBreaker lineBreaker) Parameter:
lineIndex - The line index.
columIndex - The column index.
offset - The horizontal offset value
lineBreaker - The LineBreaker object.
See => Figure 5.1, 5.1 The usage of the CaretPosition Processing:
This method is called from the columnOffset method mentioned above and the lineOffset method mentioned below. This method counts the number of characters from the top of the text to the position specified by the (lineIndex, columIndex) and gets the new textIndex (field variable) by adding the offset to the number of characters, and finally updates this object by calling the updateCaretPosition method.
lineOffset public void lineOffset(int lineOffset, LineBreaker lineBreaker)
Parameter:
lineOffset - the vertical offset value. Minus offset is available.
lineBreaker - LineBreaker object.
Processing:
The method is called by the TextBox.keyPressed method of the TextBox to move the text cursor (caret) to upper or lower. This method is performed by calling the offsetCaretposition method.
print public void print(String message)
Prints the caret position with the message for debug.
toString public String toString()
Return the string representing this object.
getCaretPosition
(static)
public static CaretPosition getCaretPosition(int textIndex, boolean lineFeedOption, LineBreaker lineBreaker, String callFrom)
Parameter:
textIndex - The text index.
lineFeedOption - line feed option(see=> field variable lineFeedOption)
lineBreaker - The LineBreaker object.
callFrom - The class name and method name calling this method (for debug)
Returns:
CaretPosition - The CaretPosition object.
Processing:
This method calculates the (lineIndex, columIndex) from the textIndex by the LineBreaker.getLineColumnIndices method and creates the new CaretPosition object.
getCaretPosition
(static)
public static CaretPosition getCaretPosition(int lineIndex, int columnIndex, boolean lineFeedOption, LineBreaker lineBreaker, String callFrom)
Parameter:
lineIndex - The line index.
columIndex - The column index.
lineFeedOption - line feed option(=> field variablelineFeedOption)
lineBreaker - The LineBreaker object.
callFrom - The class name and method name calling this method (for debug)
=> Figure 5.1, 5.1 The usage of the CaretPosition
Returns:
CaretPosition - The CaretPosition object.
Processing:
This method calculates the textIndex from the (lineIndex, columIndex) by the LineBreaker.getTextIndex method and creates the new CaretPosition object.




Copyright (c) 2009-2013
All other trademarks are property of their respective owners.