mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
parent
793ad1faae
commit
09d28eb30c
46 changed files with 3421 additions and 937 deletions
|
@ -24,9 +24,9 @@ import docking.widgets.fieldpanel.support.RowColLocation;
|
|||
|
||||
/**
|
||||
* An object that wraps a string and provides data that describes how to render
|
||||
* that string.
|
||||
* that string.
|
||||
* <p>
|
||||
* This class was created as a place to house attributes of rendering that
|
||||
* This class was created as a place to house attributes of rendering that
|
||||
* are not described by Java's Font object, like underlining.
|
||||
*
|
||||
*
|
||||
|
@ -83,7 +83,7 @@ abstract public class AbstractTextFieldElement implements FieldElement {
|
|||
|
||||
@Override
|
||||
public int getMaxCharactersForWidth(int width) {
|
||||
return attributedString.getColumnPosition(width);
|
||||
return attributedString.getCharPosition(width);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,7 +112,8 @@ abstract public class AbstractTextFieldElement implements FieldElement {
|
|||
@Override
|
||||
public RowColLocation getDataLocationForCharacterIndex(int characterIndex) {
|
||||
if (characterIndex < 0 || characterIndex > attributedString.getText().length()) {
|
||||
throw new IllegalArgumentException("columnPosition is out of range: " + characterIndex);
|
||||
throw new IllegalArgumentException("columnPosition is out of range: " + characterIndex +
|
||||
"; range is [0," + attributedString.getText().length() + "]");
|
||||
}
|
||||
return new RowColLocation(row, column + characterIndex);
|
||||
}
|
||||
|
|
|
@ -24,9 +24,9 @@ import docking.util.GraphicsUtils;
|
|||
|
||||
/**
|
||||
* An object that wraps a string and provides data that describes how to render
|
||||
* that string.
|
||||
* that string.
|
||||
* <p>
|
||||
* This class was created as a place to house attributes of rendering that
|
||||
* This class was created as a place to house attributes of rendering that
|
||||
* are not described by Java's Font object, like underlining.
|
||||
*
|
||||
*
|
||||
|
@ -136,11 +136,11 @@ public class AttributedString {
|
|||
return fontMetrics.getMaxDescent() + UNDERLINE_HEIGHT;
|
||||
}
|
||||
|
||||
public int getColumnPosition(int width) {
|
||||
public int getCharPosition(int x) {
|
||||
int subWidth = getIconWidth();
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
subWidth += fontMetrics.charWidth(text.charAt(i));
|
||||
if (subWidth > width) {
|
||||
if (subWidth > x) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,8 +106,7 @@ public class ClippingTextField implements TextField {
|
|||
|
||||
@Override
|
||||
public int getCol(int row, int x) {
|
||||
int xPos = Math.max(x - startX, 0); // make x relative to this fields
|
||||
// coordinate system.
|
||||
int xPos = Math.max(x - startX, 0); // make x relative to this fields coordinate system
|
||||
return textElement.getMaxCharactersForWidth(xPos);
|
||||
}
|
||||
|
||||
|
@ -134,7 +133,13 @@ public class ClippingTextField implements TextField {
|
|||
}
|
||||
|
||||
private int getNumCols() {
|
||||
return textElement.length() + 1; // allow one column past the end of the text
|
||||
// allow one column past the end of the text to allow the cursor to be placed after the text
|
||||
return textElement.length() + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumDataRows() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -217,7 +222,8 @@ public class ClippingTextField implements TextField {
|
|||
|
||||
@Override
|
||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight) {
|
||||
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc,
|
||||
int rowHeight) {
|
||||
if (context.isPrinting()) {
|
||||
print(g, context);
|
||||
}
|
||||
|
@ -329,14 +335,21 @@ public class ClippingTextField implements TextField {
|
|||
*/
|
||||
@Override
|
||||
public RowColLocation screenToDataLocation(int screenRow, int screenColumn) {
|
||||
return textElement.getDataLocationForCharacterIndex(screenColumn);
|
||||
return originalElement.getDataLocationForCharacterIndex(screenColumn);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
||||
int column = textElement.getCharacterIndexForDataLocation(dataRow, dataColumn);
|
||||
return new RowColLocation(0, Math.max(column, 0));
|
||||
if (column < 0) {
|
||||
// place at the end if past the end
|
||||
if (dataColumn >= textElement.length()) {
|
||||
return new DefaultRowColLocation(0, textElement.length());
|
||||
}
|
||||
return new DefaultRowColLocation();
|
||||
}
|
||||
return new RowColLocation(0, column);
|
||||
}
|
||||
|
||||
private int findX(int col) {
|
||||
|
@ -381,7 +394,8 @@ public class ClippingTextField implements TextField {
|
|||
|
||||
@Override
|
||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||
return new RowColLocation(0, Math.min(textOffset, textElement.getText().length() - 1));
|
||||
// allow the max position to be just after the last character
|
||||
return new RowColLocation(0, Math.min(textOffset, textElement.getText().length()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -395,9 +409,6 @@ public class ClippingTextField implements TextField {
|
|||
|
||||
@Override
|
||||
public FieldElement getFieldElement(int screenRow, int screenColumn) {
|
||||
// TODO - this used to return the clipped value, which is not our clients wanted (at least one). If
|
||||
// any odd navigation/tracking/action issues appear, then this could be the culprit.
|
||||
// return textElement.getFieldElement(screenColumn);
|
||||
return originalElement.getFieldElement(screenColumn);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -27,7 +26,7 @@ import javax.swing.JComponent;
|
|||
public class CompositeAttributedString extends AttributedString {
|
||||
|
||||
private String fullText;
|
||||
private AttributedString[] attributedStrings;
|
||||
protected AttributedString[] attributedStrings;
|
||||
private int heightAbove = -1;
|
||||
private int heightBelow = -1;
|
||||
|
||||
|
@ -35,7 +34,7 @@ public class CompositeAttributedString extends AttributedString {
|
|||
this(stringList.toArray(new AttributedString[stringList.size()]));
|
||||
}
|
||||
|
||||
public CompositeAttributedString(AttributedString[] attributedStrings) {
|
||||
public CompositeAttributedString(AttributedString... attributedStrings) {
|
||||
this.attributedStrings = attributedStrings;
|
||||
}
|
||||
|
||||
|
@ -54,17 +53,17 @@ public class CompositeAttributedString extends AttributedString {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getColumnPosition(int width) {
|
||||
int remainingWidth = width;
|
||||
public int getCharPosition(int x) {
|
||||
int remainingWidth = x;
|
||||
int totalCharacters = 0;
|
||||
for (int i = 0; i < attributedStrings.length; i++) {
|
||||
int nextWidth = attributedStrings[i].getStringWidth();
|
||||
for (AttributedString attributedString : attributedStrings) {
|
||||
int nextWidth = attributedString.getStringWidth();
|
||||
if (nextWidth >= remainingWidth) {
|
||||
totalCharacters += attributedStrings[i].getColumnPosition(remainingWidth);
|
||||
totalCharacters += attributedString.getCharPosition(remainingWidth);
|
||||
break;
|
||||
}
|
||||
remainingWidth -= nextWidth;
|
||||
totalCharacters += attributedStrings[i].length();
|
||||
totalCharacters += attributedString.length();
|
||||
}
|
||||
|
||||
return totalCharacters;
|
||||
|
@ -86,8 +85,8 @@ public class CompositeAttributedString extends AttributedString {
|
|||
public int getHeightAbove() {
|
||||
if (heightAbove < 0) {
|
||||
heightAbove = 0;
|
||||
for (int i = 0; i < attributedStrings.length; i++) {
|
||||
heightAbove = Math.max(heightAbove, attributedStrings[i].getHeightAbove());
|
||||
for (AttributedString attributedString : attributedStrings) {
|
||||
heightAbove = Math.max(heightAbove, attributedString.getHeightAbove());
|
||||
}
|
||||
}
|
||||
return heightAbove;
|
||||
|
@ -97,23 +96,23 @@ public class CompositeAttributedString extends AttributedString {
|
|||
public int getHeightBelow() {
|
||||
if (heightBelow < 0) {
|
||||
heightBelow = 0;
|
||||
for (int i = 0; i < attributedStrings.length; i++) {
|
||||
heightBelow = Math.max(heightBelow, attributedStrings[i].getHeightBelow());
|
||||
for (AttributedString attributedString : attributedStrings) {
|
||||
heightBelow = Math.max(heightBelow, attributedString.getHeightBelow());
|
||||
}
|
||||
}
|
||||
return heightBelow;
|
||||
}
|
||||
|
||||
// =============================================================================================
|
||||
// font metrics methods
|
||||
// =============================================================================================
|
||||
// =============================================================================================
|
||||
// font metrics methods
|
||||
// =============================================================================================
|
||||
|
||||
@Override
|
||||
public int getStringWidth() {
|
||||
if (textWidth == -1) {
|
||||
textWidth = 0;
|
||||
for (int i = 0; i < attributedStrings.length; i++) {
|
||||
textWidth += attributedStrings[i].getStringWidth();
|
||||
for (AttributedString attributedString : attributedStrings) {
|
||||
textWidth += attributedString.getStringWidth();
|
||||
}
|
||||
}
|
||||
return textWidth;
|
||||
|
@ -123,24 +122,24 @@ public class CompositeAttributedString extends AttributedString {
|
|||
public String getText() {
|
||||
if (fullText == null) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (int i = 0; i < attributedStrings.length; i++) {
|
||||
buffer.append(attributedStrings[i].getText());
|
||||
for (AttributedString attributedString : attributedStrings) {
|
||||
buffer.append(attributedString.getText());
|
||||
}
|
||||
fullText = buffer.toString();
|
||||
}
|
||||
return fullText;
|
||||
}
|
||||
|
||||
// =============================================================================================
|
||||
// paint methods
|
||||
// =============================================================================================
|
||||
// =============================================================================================
|
||||
// paint methods
|
||||
// =============================================================================================
|
||||
|
||||
@Override
|
||||
public void paint(JComponent c, Graphics g, int x, int y) {
|
||||
int xPos = x;
|
||||
for (int i = 0; i < attributedStrings.length; i++) {
|
||||
attributedStrings[i].paint(c, g, xPos, y);
|
||||
xPos += attributedStrings[i].getStringWidth();
|
||||
for (AttributedString attributedString : attributedStrings) {
|
||||
attributedString.paint(c, g, xPos, y);
|
||||
xPos += attributedString.getStringWidth();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import javax.swing.JComponent;
|
|||
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||
|
||||
/**
|
||||
* A FieldElement that is composed of other FieldElements.
|
||||
* A FieldElement that is composed of other FieldElements. The elements are laid out horizontally.
|
||||
*/
|
||||
public class CompositeFieldElement implements FieldElement {
|
||||
|
||||
|
@ -34,19 +34,14 @@ public class CompositeFieldElement implements FieldElement {
|
|||
private int textWidth = -1;
|
||||
private String fullText;
|
||||
|
||||
public CompositeFieldElement(List<? extends FieldElement> stringList) {
|
||||
this(stringList.toArray(new FieldElement[stringList.size()]));
|
||||
public CompositeFieldElement(List<? extends FieldElement> elements) {
|
||||
this(elements.toArray(new FieldElement[elements.size()]));
|
||||
}
|
||||
|
||||
public CompositeFieldElement(FieldElement[] fieldElements) {
|
||||
this.fieldElements = fieldElements;
|
||||
}
|
||||
|
||||
public CompositeFieldElement(FieldElement[] elements, int start, int length) {
|
||||
fieldElements = new FieldElement[length];
|
||||
System.arraycopy(elements, start, fieldElements, 0, length);
|
||||
}
|
||||
|
||||
private IndexedOffset getIndexedOffsetForCharPosition(int charPosition) {
|
||||
int n = 0;
|
||||
for (int i = 0; i < fieldElements.length; i++) {
|
||||
|
@ -114,7 +109,7 @@ public class CompositeFieldElement implements FieldElement {
|
|||
|
||||
//==================================================================================================
|
||||
// FontMetrics methods
|
||||
//==================================================================================================
|
||||
//==================================================================================================
|
||||
|
||||
@Override
|
||||
public int getStringWidth() {
|
||||
|
@ -130,7 +125,7 @@ public class CompositeFieldElement implements FieldElement {
|
|||
@Override
|
||||
public String getText() {
|
||||
if (fullText == null) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
for (FieldElement fieldElement : fieldElements) {
|
||||
buffer.append(fieldElement.getText());
|
||||
}
|
||||
|
@ -141,7 +136,7 @@ public class CompositeFieldElement implements FieldElement {
|
|||
|
||||
//==================================================================================================
|
||||
// Paint methods
|
||||
//==================================================================================================
|
||||
//==================================================================================================
|
||||
|
||||
@Override
|
||||
public void paint(JComponent c, Graphics g, int x, int y) {
|
||||
|
@ -217,9 +212,14 @@ public class CompositeFieldElement implements FieldElement {
|
|||
return getText().length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Location Info
|
||||
//==================================================================================================
|
||||
//==================================================================================================
|
||||
|
||||
@Override
|
||||
public RowColLocation getDataLocationForCharacterIndex(int characterIndex) {
|
||||
|
@ -229,12 +229,14 @@ public class CompositeFieldElement implements FieldElement {
|
|||
|
||||
@Override
|
||||
public int getCharacterIndexForDataLocation(int dataRow, int dataColumn) {
|
||||
int columnCount = 0;
|
||||
int columnsSoFar = 0;
|
||||
for (int i = fieldElements.length - 1; i >= 0; i--) {
|
||||
columnCount += fieldElements[i].length();
|
||||
columnsSoFar += fieldElements[i].length();
|
||||
int column = fieldElements[i].getCharacterIndexForDataLocation(dataRow, dataColumn);
|
||||
if (column != -1) {
|
||||
return length() - columnCount + column;
|
||||
// column value is relative to the current field; convert it to this field's offset
|
||||
int fieldStart = length() - columnsSoFar;
|
||||
return fieldStart + column;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,596 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.widgets.fieldpanel.field;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
||||
import docking.widgets.fieldpanel.internal.PaintContext;
|
||||
import docking.widgets.fieldpanel.support.*;
|
||||
import generic.json.Json;
|
||||
|
||||
/**
|
||||
* A {@link TextField} that takes in other TextFields.
|
||||
*
|
||||
* <P>This class allows clients to create custom text layout behavior by combining individual
|
||||
* TextFields that dictate layout behavior. As an example, consider this rendering:
|
||||
* <pre>
|
||||
* 1) This is some text...
|
||||
* 2) This
|
||||
* is
|
||||
* more
|
||||
* text
|
||||
* </pre>
|
||||
* In this example, 1) is a row of text inside of a {@link ClippingTextField}. Row 2) is a
|
||||
* multi-line text rendering specified in a single {@link FlowLayoutTextField}, using a
|
||||
* narrow width to trigger the field to place each element on its own line.
|
||||
*/
|
||||
public class CompositeVerticalLayoutTextField implements TextField {
|
||||
|
||||
// the view rows, which may be a clipped version of the client fields
|
||||
private List<FieldRow> fieldRows;
|
||||
private int startX;
|
||||
private int width;
|
||||
private int preferredWidth;
|
||||
private HighlightFactory hlFactory;
|
||||
|
||||
private int height;
|
||||
private int heightAbove;
|
||||
private int numRows;
|
||||
private int numDataRows;
|
||||
private boolean isPrimary;
|
||||
|
||||
private String fullText;
|
||||
|
||||
// all text, including any clipped text; lines.size() == fields.size()
|
||||
private List<String> lines;
|
||||
|
||||
// used in the getText() method to separate rows without adding newlines
|
||||
private String rowSeparator;
|
||||
|
||||
private boolean isClipped;
|
||||
|
||||
public CompositeVerticalLayoutTextField(List<TextField> fields, int startX, int width,
|
||||
int maxLines, HighlightFactory hlFactory) {
|
||||
this(fields, startX, width, maxLines, hlFactory, " ");
|
||||
}
|
||||
|
||||
protected CompositeVerticalLayoutTextField(List<TextField> fields, int startX, int width,
|
||||
int maxLines, HighlightFactory hlFactory, String rowSeparator) {
|
||||
|
||||
this.startX = startX;
|
||||
this.width = width;
|
||||
|
||||
this.hlFactory = hlFactory;
|
||||
this.rowSeparator = rowSeparator;
|
||||
|
||||
lines = generateLines(fields);
|
||||
fullText = generateText(fields, rowSeparator);
|
||||
|
||||
heightAbove = (fields.get(0)).getHeightAbove();
|
||||
fieldRows = layoutRows(fields, maxLines);
|
||||
|
||||
calculateRows(fields);
|
||||
calculatePreferredWidth();
|
||||
calculateHeight();
|
||||
}
|
||||
|
||||
private List<String> generateLines(List<TextField> fields) {
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
for (TextField field : fields) {
|
||||
list.add(field.getTextWithLineSeparators());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private String generateText(List<TextField> fields, String delimiter) {
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (TextField element : fields) {
|
||||
buf.append(element.getText()).append(delimiter);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private List<FieldRow> layoutRows(List<TextField> fields, int maxLines) {
|
||||
|
||||
List<FieldRow> newSubFields = new ArrayList<>();
|
||||
int heightSoFar = -heightAbove;
|
||||
int currentRow = 0;
|
||||
boolean tooManyLines = fields.size() > maxLines;
|
||||
for (int i = 0; i < fields.size() && i < maxLines; i++) {
|
||||
TextField field = fields.get(i);
|
||||
if (tooManyLines && (i == maxLines - 1)) {
|
||||
FieldElement element = field.getFieldElement(0, 0);
|
||||
TextField newField = createClippedField(element);
|
||||
newSubFields.add(new FieldRow(newField, currentRow, heightSoFar));
|
||||
isClipped = true;
|
||||
}
|
||||
else {
|
||||
newSubFields.add(new FieldRow(field, currentRow, heightSoFar));
|
||||
isClipped |= field.isClipped();
|
||||
}
|
||||
|
||||
heightSoFar += field.getHeight();
|
||||
currentRow += field.getNumRows();
|
||||
}
|
||||
|
||||
isClipped |= tooManyLines;
|
||||
|
||||
return newSubFields;
|
||||
}
|
||||
|
||||
private ClippingTextField createClippedField(FieldElement element) {
|
||||
|
||||
FieldElement[] elements = new FieldElement[] {
|
||||
element,
|
||||
new StrutFieldElement(500)
|
||||
};
|
||||
FieldElement compositeElement = new CompositeFieldElement(elements);
|
||||
return new ClippingTextField(startX, width, compositeElement, hlFactory);
|
||||
}
|
||||
|
||||
private void calculateHeight() {
|
||||
for (FieldRow row : fieldRows) {
|
||||
height += row.field.getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
private void calculatePreferredWidth() {
|
||||
preferredWidth = 0;
|
||||
for (FieldRow row : fieldRows) {
|
||||
preferredWidth = Math.max(preferredWidth, row.field.getPreferredWidth());
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateRows(List<TextField> fields) {
|
||||
numRows = 0;
|
||||
for (FieldRow row : fieldRows) {
|
||||
numRows += row.field.getNumRows();
|
||||
}
|
||||
|
||||
numDataRows = 0;
|
||||
for (TextField field : fields) {
|
||||
numDataRows += field.getNumDataRows();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredWidth() {
|
||||
return preferredWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartX() {
|
||||
return startX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumDataRows() {
|
||||
return numDataRows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumRows() {
|
||||
return numRows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeightAbove() {
|
||||
return heightAbove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeightBelow() {
|
||||
return height - heightAbove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimary() {
|
||||
return isPrimary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rowHeightChanged(int newHeightAbove, int newHeightBelow) {
|
||||
// don't care
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClipped() {
|
||||
return isClipped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimary(boolean state) {
|
||||
isPrimary = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return fullText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTextWithLineSeparators() {
|
||||
return StringUtils.join(lines, '\n');
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(JComponent c, Graphics g, PaintContext context, Rectangle clip,
|
||||
FieldBackgroundColorManager colorManager, RowColLocation cursorLocation,
|
||||
int rowHeight) {
|
||||
|
||||
// the graphics have been translated such that the first line of text's base line is
|
||||
// at y=0 (So if we are not clipped, we will drawing from a negative value that is the
|
||||
// font's height above the baseline (-heightAbove) to rowHeight (-heightAbove)
|
||||
int myStartY = -heightAbove;
|
||||
int myEndY = myStartY + rowHeight;
|
||||
int clipStartY = clip.y;
|
||||
int clipEndY = clip.y + clip.height;
|
||||
|
||||
Color fieldBackgroundColor = colorManager.getBackgroundColor();
|
||||
if (fieldBackgroundColor != null) {
|
||||
g.setColor(fieldBackgroundColor);
|
||||
|
||||
// restrict background rectangle to clipping rectangle
|
||||
int startY = Math.max(myStartY, clipStartY);
|
||||
int endY = Math.min(myEndY, clipEndY);
|
||||
int clippedHeight = endY - startY;
|
||||
g.fillRect(startX, startY, width, clippedHeight);
|
||||
}
|
||||
|
||||
FieldRow cursorRow = null;
|
||||
if (cursorLocation != null) {
|
||||
cursorRow = getFieldRow(cursorLocation.row());
|
||||
}
|
||||
|
||||
int startY = myStartY;
|
||||
int translatedY = 0;
|
||||
|
||||
for (int i = 0; i < fieldRows.size(); i++) {
|
||||
|
||||
// if past clipping region we are done
|
||||
if (startY > clipEndY) {
|
||||
break;
|
||||
}
|
||||
|
||||
FieldRow fieldRow = fieldRows.get(i);
|
||||
TextField field = fieldRow.field;
|
||||
int subFieldHeight = fieldRow.field.getHeight();
|
||||
int endY = startY + subFieldHeight;
|
||||
|
||||
// if any part of the line is in the clip region, draw it
|
||||
if (endY >= clipStartY) {
|
||||
RowColLocation cursor = null;
|
||||
if (fieldRow == cursorRow) {
|
||||
int relativeRow = fieldRow.getRelativeRow(cursorLocation.row());
|
||||
cursor = cursorLocation.withRow(relativeRow);
|
||||
}
|
||||
|
||||
field.paint(c, g, context, clip, colorManager, cursor, rowHeight);
|
||||
}
|
||||
|
||||
// translate for next row of text
|
||||
startY += subFieldHeight;
|
||||
g.translate(0, subFieldHeight);
|
||||
translatedY += subFieldHeight;
|
||||
}
|
||||
|
||||
// restore the graphics to where it was when we started.
|
||||
g.translate(0, -translatedY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int y) {
|
||||
if ((x >= startX) && (x < startX + width) && (y >= -heightAbove) &&
|
||||
(y < height - heightAbove)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getRowSeparator() {
|
||||
return rowSeparator;
|
||||
}
|
||||
|
||||
private FieldRow getFieldRow(int screenRow) {
|
||||
int currentRow = 0;
|
||||
for (FieldRow row : fieldRows) {
|
||||
int n = row.field.getNumRows();
|
||||
if (currentRow + n > screenRow) {
|
||||
return row;
|
||||
}
|
||||
currentRow += n;
|
||||
}
|
||||
return fieldRows.get(fieldRows.size() - 1);
|
||||
}
|
||||
|
||||
private FieldRow getFieldRowFromDataRow(int dataRow) {
|
||||
int currentRow = 0;
|
||||
for (FieldRow row : fieldRows) {
|
||||
if (currentRow >= dataRow) {
|
||||
return row;
|
||||
}
|
||||
currentRow += row.field.getNumDataRows();
|
||||
}
|
||||
return fieldRows.get(fieldRows.size() - 1);
|
||||
}
|
||||
|
||||
// get all rows from 0 to max inclusive
|
||||
private List<FieldRow> getAllRows(int maxRow) {
|
||||
int currentRow = 0;
|
||||
List<FieldRow> list = new ArrayList<>();
|
||||
for (FieldRow row : fieldRows) {
|
||||
if (currentRow > maxRow) {
|
||||
break;
|
||||
}
|
||||
|
||||
list.add(row);
|
||||
currentRow += row.field.getNumRows();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// for testing
|
||||
protected List<TextField> getAllRowsUpTo(int maxRowInclusive) {
|
||||
return getAllRows(maxRowInclusive)
|
||||
.stream()
|
||||
.map(fieldRow -> fieldRow.field)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldElement getFieldElement(int screenRow, int screenColumn) {
|
||||
FieldRow fieldRow = getFieldRow(screenRow);
|
||||
int relativeRow = fieldRow.getRelativeRow(screenRow);
|
||||
return fieldRow.field.getFieldElement(relativeRow, screenColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumCols(int row) {
|
||||
FieldRow fieldRow = getFieldRow(row);
|
||||
int relativeRow = fieldRow.getRelativeRow(row);
|
||||
return fieldRow.field.getNumCols(relativeRow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX(int row, int col) {
|
||||
FieldRow fieldRow = getFieldRow(row);
|
||||
int relativeRow = fieldRow.getRelativeRow(row);
|
||||
return fieldRow.field.getX(relativeRow, col);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY(int row) {
|
||||
|
||||
int y = -heightAbove;
|
||||
List<FieldRow> rows = getAllRows(row);
|
||||
for (FieldRow fieldRow : rows) {
|
||||
y += fieldRow.field.getHeight();
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRow(int y) {
|
||||
if (y < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int heightSoFar = 0;
|
||||
for (FieldRow fieldRow : fieldRows) {
|
||||
int fieldHeight = fieldRow.field.getHeight();
|
||||
int bottom = fieldHeight + heightSoFar;
|
||||
if (bottom > y) {
|
||||
int relativeY = y - heightSoFar;
|
||||
int relativeRow = fieldRow.field.getRow(relativeY);
|
||||
int displayRow = fieldRow.fromRelativeRow(relativeRow);
|
||||
return displayRow;
|
||||
}
|
||||
heightSoFar += fieldHeight;
|
||||
}
|
||||
return getNumRows() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCol(int row, int x) {
|
||||
|
||||
FieldRow fieldRow = getFieldRow(row);
|
||||
int relativeRow = fieldRow.getRelativeRow(row);
|
||||
return fieldRow.field.getCol(relativeRow, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(int row, int col) {
|
||||
|
||||
if ((row < 0) || (row >= getNumRows())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FieldRow fieldRow = getFieldRow(row);
|
||||
int relativeRow = fieldRow.getRelativeRow(row);
|
||||
return fieldRow.field.isValid(relativeRow, col);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getCursorBounds(int row, int col) {
|
||||
|
||||
if ((row < 0) || (row >= getNumRows())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<FieldRow> rows = getAllRows(row);
|
||||
FieldRow cursorRow = rows.get(rows.size() - 1);
|
||||
int relativeRow = cursorRow.getRelativeRow(row);
|
||||
Rectangle r = cursorRow.field.getCursorBounds(relativeRow, col);
|
||||
|
||||
for (int i = 0; i < rows.size() - 1; i++) {
|
||||
FieldRow previousRow = rows.get(i);
|
||||
r.y += previousRow.field.getHeight();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScrollableUnitIncrement(int topOfScreen, int direction, int max) {
|
||||
|
||||
if ((topOfScreen < -heightAbove) || (topOfScreen > height - heightAbove)) {
|
||||
return max;
|
||||
}
|
||||
|
||||
int row = getRow(topOfScreen);
|
||||
int y = getY(row);
|
||||
int rowOffset = topOfScreen - y;
|
||||
FieldRow fieldRow = getFieldRow(row);
|
||||
int rowHeight = fieldRow.field.getHeight();
|
||||
if (direction > 0) { // if scrolling down
|
||||
return rowHeight - rowOffset;
|
||||
}
|
||||
else if (rowOffset == 0) {
|
||||
return -rowHeight;
|
||||
}
|
||||
else {
|
||||
return -rowOffset;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowColLocation screenToDataLocation(int screenRow, int screenColumn) {
|
||||
|
||||
screenRow = Math.min(screenRow, numRows - 1);
|
||||
screenRow = Math.max(screenRow, 0);
|
||||
|
||||
FieldRow fieldRow = getFieldRow(screenRow);
|
||||
|
||||
screenColumn = Math.min(screenColumn, fieldRow.field.getText().length());
|
||||
screenColumn = Math.max(screenColumn, 0);
|
||||
|
||||
int relativeRow = fieldRow.getRelativeRow(screenRow);
|
||||
return fieldRow.field.screenToDataLocation(relativeRow, screenColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
||||
FieldRow fieldRow = getFieldRowFromDataRow(dataRow);
|
||||
RowColLocation location = fieldRow.field.dataToScreenLocation(dataRow, dataColumn);
|
||||
int relativeRow = fieldRow.fromRelativeRow(location.row());
|
||||
return location.withRow(relativeRow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int screenLocationToTextOffset(int row, int col) {
|
||||
|
||||
if (row >= numRows) {
|
||||
return getText().length();
|
||||
}
|
||||
|
||||
int extraSpace = rowSeparator.length();
|
||||
int len = 0;
|
||||
List<FieldRow> rows = getAllRows(row);
|
||||
int n = rows.size() - 1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
FieldRow fieldRow = rows.get(i);
|
||||
len += fieldRow.field.getText().length() + extraSpace;
|
||||
}
|
||||
|
||||
FieldRow lastRow = rows.get(n);
|
||||
int relativeRow = lastRow.getRelativeRow(row);
|
||||
len += lastRow.field.screenLocationToTextOffset(relativeRow, col);
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||
|
||||
int extraSpace = rowSeparator.length();
|
||||
int n = fieldRows.size();
|
||||
int textOffsetSoFar = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
|
||||
if (textOffsetSoFar > textOffset) {
|
||||
break;
|
||||
}
|
||||
|
||||
FieldRow fieldRow = fieldRows.get(i);
|
||||
int length = fieldRow.field.getText().length() + extraSpace;
|
||||
int end = textOffsetSoFar + length;
|
||||
if (end > textOffset) {
|
||||
int relativeOffset = textOffset - textOffsetSoFar;
|
||||
RowColLocation location = fieldRow.field.textOffsetToScreenLocation(relativeOffset);
|
||||
int screenRow = fieldRow.fromRelativeRow(location.row());
|
||||
return location.withRow(screenRow);
|
||||
}
|
||||
|
||||
textOffsetSoFar += length;
|
||||
}
|
||||
|
||||
FieldRow lastRow = fieldRows.get(fieldRows.size() - 1);
|
||||
int length = lastRow.field.getText().length();
|
||||
return new DefaultRowColLocation(numRows - 1, length);
|
||||
}
|
||||
|
||||
private class FieldRow {
|
||||
private TextField field;
|
||||
private int displayRowOffset;
|
||||
private int yOffset;
|
||||
|
||||
FieldRow(TextField field, int rowOffset, int yOffset) {
|
||||
this.field = field;
|
||||
this.displayRowOffset = rowOffset;
|
||||
}
|
||||
|
||||
// used to turn given row into 0 for this composite field
|
||||
int getRelativeRow(int displayRow) {
|
||||
return displayRow - displayRowOffset;
|
||||
}
|
||||
|
||||
int fromRelativeRow(int relativeRow) {
|
||||
return relativeRow + displayRowOffset;
|
||||
}
|
||||
|
||||
int getY() {
|
||||
return yOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Json.toString(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ import javax.swing.JComponent;
|
|||
|
||||
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
||||
import docking.widgets.fieldpanel.internal.PaintContext;
|
||||
import docking.widgets.fieldpanel.support.DefaultRowColLocation;
|
||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||
|
||||
/**
|
||||
|
@ -79,6 +80,11 @@ public class EmptyTextField implements Field {
|
|||
return startX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumDataRows() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumRows() {
|
||||
return 1;
|
||||
|
@ -123,7 +129,8 @@ public class EmptyTextField implements Field {
|
|||
|
||||
@Override
|
||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc, int rowHeight) {
|
||||
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc,
|
||||
int rowHeight) {
|
||||
paintCursor(g, context.getCursorColor(), cursorLoc);
|
||||
}
|
||||
|
||||
|
@ -227,7 +234,7 @@ public class EmptyTextField implements Field {
|
|||
|
||||
@Override
|
||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||
return new RowColLocation(0, 0);
|
||||
return new DefaultRowColLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,155 +30,180 @@ import docking.widgets.fieldpanel.support.RowColLocation;
|
|||
public interface Field {
|
||||
|
||||
/**
|
||||
* Returns the current width of this field.
|
||||
* Returns the current width of this field
|
||||
* @return the current width of this field
|
||||
*/
|
||||
int getWidth();
|
||||
public int getWidth();
|
||||
|
||||
/**
|
||||
* The minimum required width to paint the contents of this field
|
||||
* @return the minimum required width to paint the contents of this field
|
||||
*/
|
||||
int getPreferredWidth();
|
||||
public int getPreferredWidth();
|
||||
|
||||
/**
|
||||
* Returns the height of this field when populated with the given data.
|
||||
* Returns the height of this field when populated with the given data
|
||||
* @return the height
|
||||
*/
|
||||
int getHeight();
|
||||
public int getHeight();
|
||||
|
||||
/**
|
||||
* Returns the height above the baseLine.
|
||||
* Returns the height above the baseLine
|
||||
* @return the height above
|
||||
*/
|
||||
int getHeightAbove();
|
||||
public int getHeightAbove();
|
||||
|
||||
/**
|
||||
* Returns the height below the baseLine.
|
||||
* Returns the height below the baseLine
|
||||
* @return the height below
|
||||
*/
|
||||
int getHeightBelow();
|
||||
public int getHeightBelow();
|
||||
|
||||
/**
|
||||
* Returns the horizontal position of this field.
|
||||
* Returns the horizontal position of this field
|
||||
* @return the position
|
||||
*/
|
||||
int getStartX();
|
||||
public int getStartX();
|
||||
|
||||
/**
|
||||
* Paints this field.
|
||||
* Paints this field
|
||||
* @param c the component to paint onto
|
||||
* @param g the graphics context.
|
||||
* @param g the graphics context
|
||||
* @param context common paint parameters
|
||||
* @param clip the clipping region to paint into
|
||||
* @param colorManager contains background color information for the field.
|
||||
* @param clip the clipping region to paint into
|
||||
* @param colorManager contains background color information for the field
|
||||
* @param cursorLoc the row,column cursor location within the field or null if the field does
|
||||
* not contain the cursor
|
||||
* @param rowHeight the number of pixels in each row of text in the field.
|
||||
* @param rowHeight the number of pixels in each row of text in the field
|
||||
*/
|
||||
void paint(JComponent c, Graphics g, PaintContext context, Rectangle clip,
|
||||
public void paint(JComponent c, Graphics g, PaintContext context, Rectangle clip,
|
||||
FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight);
|
||||
|
||||
/**
|
||||
* Returns true if the given point is in this field.
|
||||
* @param x the horizontal coordinate of the point.
|
||||
* @param y the relatve y position in this layout
|
||||
* Returns true if the given point is in this field
|
||||
* @param x the horizontal coordinate of the point
|
||||
* @param y the relative y position in this layout
|
||||
* @return true if the given point is in this field
|
||||
*/
|
||||
boolean contains(int x, int y);
|
||||
public boolean contains(int x, int y);
|
||||
|
||||
/**
|
||||
* Returns the number of data model rows represented by this field. Some fields may change
|
||||
* the row count by wrapping or truncating. The value returned here will be the original data
|
||||
* row count before any transformations were applied.
|
||||
* @return the number of data rows
|
||||
*/
|
||||
public int getNumDataRows();
|
||||
|
||||
/**
|
||||
* Returns the number of rows in this field
|
||||
* @return the number of rows in this field
|
||||
*/
|
||||
int getNumRows();
|
||||
public int getNumRows();
|
||||
|
||||
/**
|
||||
* Returns the number of columns in the given row.
|
||||
* @param row the row from which to get the number of columns.
|
||||
* Returns the number of columns in the given row
|
||||
* @param row the row from which to get the number of columns; this is the screen row
|
||||
* @return the number of columns
|
||||
*/
|
||||
int getNumCols(int row);
|
||||
public int getNumCols(int row);
|
||||
|
||||
/**
|
||||
* Returns the x coordinate for the given cursor position.
|
||||
* @param row the text row of interest.
|
||||
* @param col the character column.
|
||||
* Returns the x coordinate for the given cursor position
|
||||
* @param row the text row of interest
|
||||
* @param col the character column
|
||||
* @return the x value
|
||||
*/
|
||||
int getX(int row, int col);
|
||||
public int getX(int row, int col);
|
||||
|
||||
/**
|
||||
* Returns the y coordinate for the given row.
|
||||
* @param row the text row of interest.
|
||||
* Returns the y coordinate for the given row
|
||||
* @param row the text row of interest
|
||||
* @return the y value
|
||||
*/
|
||||
int getY(int row);
|
||||
public int getY(int row);
|
||||
|
||||
/**
|
||||
* Returns the row containing the given y coordinate.
|
||||
* @param y vertical pixel coordinate relative to the top of the screen.
|
||||
* Returns the row containing the given y coordinate
|
||||
* @param y vertical pixel coordinate relative to the top of the screen
|
||||
* @return the row
|
||||
*/
|
||||
int getRow(int y);
|
||||
public int getRow(int y);
|
||||
|
||||
/**
|
||||
* Returns the cursor column position for the given x coordinate on the given
|
||||
* row.
|
||||
* @param row the text row to find the column on.
|
||||
* @param x the horizontal pixel coordinate for which to find the character position.
|
||||
* Returns the cursor column position for the given x coordinate on the given row
|
||||
* @param row the text row to find the column on
|
||||
* @param x the horizontal pixel coordinate for which to find the character position
|
||||
* @return the column
|
||||
*/
|
||||
int getCol(int row, int x);
|
||||
public int getCol(int row, int x);
|
||||
|
||||
/**
|
||||
* Returns true if the given row and column represent a valid location for
|
||||
* this field with the given data;
|
||||
* @param row the text row.
|
||||
* @param col the character position.
|
||||
* Returns true if the given row and column represent a valid location for this field with
|
||||
* the given data
|
||||
* @param row the text row
|
||||
* @param col the character position
|
||||
* @return tru if valid
|
||||
*/
|
||||
boolean isValid(int row, int col);
|
||||
public boolean isValid(int row, int col);
|
||||
|
||||
/**
|
||||
* Returns a bounding rectangle for the cursor at the given position.
|
||||
* @param row the text row.
|
||||
* @param col the character postion.
|
||||
* Returns a bounding rectangle for the cursor at the given position
|
||||
* @param row the text row
|
||||
* @param col the character position
|
||||
* @return the rectangle
|
||||
*/
|
||||
Rectangle getCursorBounds(int row, int col);
|
||||
public Rectangle getCursorBounds(int row, int col);
|
||||
|
||||
/**
|
||||
* Returns the amount to scroll to the next or previous line
|
||||
* @param topOfScreen - the current y pos of the top of the screen.
|
||||
* @param direction - the direction of the scroll (1 down, -1 up)
|
||||
* @param max - the maximum amount to scroll for the entire row - will
|
||||
* be positive for down, and negative for up)
|
||||
* @param topOfScreen the current y position of the top of the screen
|
||||
* @param direction the direction of the scroll (1 down, -1 up)
|
||||
* @param max the maximum amount to scroll for the entire row - will be positive for down, and
|
||||
* negative for up)
|
||||
* @return the scroll amount
|
||||
*/
|
||||
int getScrollableUnitIncrement(int topOfScreen, int direction, int max);
|
||||
public int getScrollableUnitIncrement(int topOfScreen, int direction, int max);
|
||||
|
||||
/**
|
||||
* Returns true if this field is "primary" (the most important)
|
||||
* field; used to determine the "primary" line in the layout.
|
||||
* Returns true if this field is "primary" (the most important) field; used to determine the
|
||||
* "primary" line in the layout
|
||||
* @return true if this field is "primary"
|
||||
*/
|
||||
boolean isPrimary();
|
||||
public boolean isPrimary();
|
||||
|
||||
/**
|
||||
* notifies field that the rowHeight changed
|
||||
* @param heightAbove the height above the baseline
|
||||
* @param heightBelow the height below the baseline.
|
||||
* @param heightBelow the height below the baseline
|
||||
*/
|
||||
void rowHeightChanged(int heightAbove, int heightBelow);
|
||||
public void rowHeightChanged(int heightAbove, int heightBelow);
|
||||
|
||||
/**
|
||||
* Returns a string containing all the text in the field.
|
||||
* Returns a string containing all the text in the field
|
||||
* @return the string
|
||||
*/
|
||||
String getText();
|
||||
public String getText();
|
||||
|
||||
/**
|
||||
* Returns a string containing all the text in the field with extra linefeeds
|
||||
* @return
|
||||
* Returns a string containing all the text in the field with extra newlines
|
||||
* @return a string containing all the text in the field with extra newlines
|
||||
*/
|
||||
String getTextWithLineSeparators();
|
||||
public String getTextWithLineSeparators();
|
||||
|
||||
/**
|
||||
* Returns the row, column position for an offset into the string returned by getText().
|
||||
* @param textOffset the offset into the entire text string for this field.
|
||||
* Returns the row, column position for an offset into the string returned by getText()
|
||||
* @param textOffset the offset into the entire text string for this field
|
||||
* @return a RowColLocation that contains the row,column location in the field for a position in
|
||||
* the overall field text.
|
||||
* the overall field text
|
||||
*/
|
||||
RowColLocation textOffsetToScreenLocation(int textOffset);
|
||||
public RowColLocation textOffsetToScreenLocation(int textOffset);
|
||||
|
||||
/**
|
||||
* Returns the text offset in the overall field text string for the given row and column.
|
||||
* @param row the row.
|
||||
* @param col the column.
|
||||
* Returns the text offset in the overall field text string for the given row and column
|
||||
* @param row the row
|
||||
* @param col the column
|
||||
* @return the offset
|
||||
*/
|
||||
int screenLocationToTextOffset(int row, int col);
|
||||
public int screenLocationToTextOffset(int row, int col);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import javax.swing.JComponent;
|
|||
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||
|
||||
/**
|
||||
* Used by {@link Field}s to combine text, attributes and location information (for example to and
|
||||
* Used by {@link Field}s to combine text, attributes and location information (for example to and
|
||||
* from screen and data locations). FieldFactory classes can use the various implementations
|
||||
* of this interface, or create new ones, to include additional information specific to the fields
|
||||
* that they create.
|
||||
|
@ -37,14 +37,14 @@ public interface FieldElement {
|
|||
public String getText();
|
||||
|
||||
/**
|
||||
* Returns the length of the text within this element. This is a convenience method for
|
||||
* Returns the length of the text within this element. This is a convenience method for
|
||||
* calling <code>getText().length()</code>.
|
||||
* @return the length of the text within this element.
|
||||
*/
|
||||
public int length();
|
||||
|
||||
/**
|
||||
* Returns the string width of this element. The width is based upon the associated
|
||||
* Returns the string width of this element. The width is based upon the associated
|
||||
* FontMetrics object within this element.
|
||||
* @return the string width of this element.
|
||||
*/
|
||||
|
@ -87,7 +87,7 @@ public interface FieldElement {
|
|||
public FieldElement substring(int start);
|
||||
|
||||
/**
|
||||
* Returns a new FieldElement containing just the characters beginning at the given start
|
||||
* Returns a new FieldElement containing just the characters beginning at the given start
|
||||
* index (inclusive) and ending at the given end index (exclusive).
|
||||
*
|
||||
* @param start The starting index (inclusive) from which to substring this element.
|
||||
|
@ -97,11 +97,11 @@ public interface FieldElement {
|
|||
public FieldElement substring(int start, int end);
|
||||
|
||||
/**
|
||||
* Returns a new FieldElement with all occurrences of the target characters replaced with the
|
||||
* Returns a new FieldElement with all occurrences of the target characters replaced with the
|
||||
* given replacement character.
|
||||
* @param targets The array of characters to replace.
|
||||
* @param replacement The replacement character.
|
||||
* @return a new FieldElement with all occurrences of the target characters replaced with the
|
||||
* @return a new FieldElement with all occurrences of the target characters replaced with the
|
||||
* given replacement character.
|
||||
*/
|
||||
public FieldElement replaceAll(char[] targets, char replacement);
|
||||
|
@ -111,13 +111,13 @@ public interface FieldElement {
|
|||
* element that will fit within the given width.
|
||||
*
|
||||
* @param width The width constraint
|
||||
* @return the maximum number of characters from this field element that will fit within
|
||||
* @return the maximum number of characters from this field element that will fit within
|
||||
* the given width.
|
||||
*/
|
||||
public int getMaxCharactersForWidth(int width);
|
||||
|
||||
/**
|
||||
* Translates the given character index to a data location related to the data model, as
|
||||
* Translates the given character index to a data location related to the data model, as
|
||||
* determined by the FieldFactory.
|
||||
*
|
||||
* @param characterIndex The character index to translate.
|
||||
|
@ -129,13 +129,15 @@ public interface FieldElement {
|
|||
* Returns the character index appropriate for the given data location
|
||||
* @param dataRow the row in the data model as determined by the creating field factory.
|
||||
* @param dataColumn the column in the data model as determined by the creating field factory.
|
||||
* @return the character index appropriate for the given data location
|
||||
* @return the character index appropriate for the given data location; -1 if this field does
|
||||
* not contain the given location
|
||||
*/
|
||||
public int getCharacterIndexForDataLocation(int dataRow, int dataColumn);
|
||||
|
||||
/**
|
||||
* Paints the text contained in this field element at the given x,y screen coordinate using the
|
||||
* given Graphics object.
|
||||
* @param c the component being painted.
|
||||
* @param g the Graphics object used to paint the field text.
|
||||
* @param x the horizontal screen position to paint
|
||||
* @param y the vertical screen position to paint.
|
||||
|
@ -144,7 +146,7 @@ public interface FieldElement {
|
|||
|
||||
/**
|
||||
* Returns the inner-most FieldElement inside this field element at the given location
|
||||
* @param column the charactor offset.
|
||||
* @param column the character offset.
|
||||
* @return the inner-most FieldElement inside this field element at the given location
|
||||
*/
|
||||
public FieldElement getFieldElement(int column);
|
||||
|
|
|
@ -15,67 +15,82 @@
|
|||
*/
|
||||
package docking.widgets.fieldpanel.field;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import docking.widgets.fieldpanel.support.HighlightFactory;
|
||||
|
||||
/**
|
||||
* This class provides a TextField implementation that takes multiple
|
||||
* AttributedStrings and places as many that will fit on a line without clipping
|
||||
* before continuing to the next line.
|
||||
* This class provides a TextField implementation that takes multiple AttributedStrings and places
|
||||
* as many that will fit on a line without clipping before continuing to the next line.
|
||||
*/
|
||||
public class FlowLayoutTextField extends VerticalLayoutTextField {
|
||||
|
||||
/**
|
||||
* This constructor will create a text field that will render one line of
|
||||
* text. If <code>metrics.stringWidth(text) > width</code>, then the text
|
||||
* will be clipped. No wrapping will be performed. If <code>text</code>
|
||||
* contains the highlight string, then it will be highlighted using the
|
||||
* This constructor will create a text field that will render one line of text. If
|
||||
* <code>metrics.stringWidth(text) > width</code>, then the text will be wrapped.
|
||||
* If <code>text</code> contains the highlight string, then it will be highlighted using the
|
||||
* highlight color.
|
||||
*
|
||||
* @param textElements
|
||||
* the AttributedStrings to display
|
||||
* @param startX
|
||||
* the x position to draw the string
|
||||
* @param width
|
||||
* the max width allocated to this field
|
||||
* @param maxLines
|
||||
* the max number of lines to display
|
||||
* @param hlFactory
|
||||
* the highlight factory
|
||||
* @param textElements the AttributedStrings to display
|
||||
* @param startX the x position to draw the string
|
||||
* @param width the max width allocated to this field
|
||||
* @param maxLines the max number of lines to display
|
||||
* @param hlFactory the highlight factory
|
||||
* @deprecated use the constructor that takes a list
|
||||
*/
|
||||
@Deprecated(since = "10.1", forRemoval = true)
|
||||
public FlowLayoutTextField(FieldElement[] textElements, int startX,
|
||||
int width, int maxLines, HighlightFactory hlFactory) {
|
||||
super(createLineElements(textElements, width), startX, width, maxLines, hlFactory,"");
|
||||
this(Arrays.asList(textElements), startX, width, maxLines, hlFactory);
|
||||
}
|
||||
|
||||
private static FieldElement[] createLineElements(FieldElement[] textElements, int width) {
|
||||
List<FieldElement> subFields = new ArrayList<FieldElement>();
|
||||
/**
|
||||
* This constructor will create a text field that will render one line of text. If
|
||||
* <code>metrics.stringWidth(text) > width</code>, then the text will be wrapped.
|
||||
* If <code>text</code> contains the highlight string, then it will be highlighted using the
|
||||
* highlight color.
|
||||
*
|
||||
* @param elements the AttributedStrings to display
|
||||
* @param startX the x position to draw the string
|
||||
* @param width the max width allocated to this field
|
||||
* @param maxLines the max number of lines to display
|
||||
* @param hlFactory the highlight factory
|
||||
*/
|
||||
public FlowLayoutTextField(List<FieldElement> elements, int startX,
|
||||
int width, int maxLines, HighlightFactory hlFactory) {
|
||||
super(createLineElements(elements, width), startX, width, maxLines, hlFactory, "");
|
||||
}
|
||||
|
||||
private static List<FieldElement> createLineElements(List<FieldElement> elements,
|
||||
int width) {
|
||||
List<FieldElement> subFields = new ArrayList<>();
|
||||
int currentIndex = 0;
|
||||
while (currentIndex < textElements.length) {
|
||||
int numberPerLine = getNumberOfElementsPerLine(textElements, currentIndex, width);
|
||||
subFields.add(new CompositeFieldElement(textElements, currentIndex, numberPerLine));
|
||||
while (currentIndex < elements.size()) {
|
||||
int numberPerLine = getNumberOfElementsPerLine(elements, currentIndex, width);
|
||||
subFields.add(createLine(elements, currentIndex, numberPerLine));
|
||||
currentIndex += numberPerLine;
|
||||
}
|
||||
|
||||
return subFields.toArray(new FieldElement[subFields.size()]);
|
||||
return subFields;
|
||||
}
|
||||
|
||||
private static int getNumberOfElementsPerLine(FieldElement[] elements, int start, int width) {
|
||||
private static CompositeFieldElement createLine(List<FieldElement> elements, int from,
|
||||
int length) {
|
||||
return new CompositeFieldElement(elements.subList(from, from + length));
|
||||
}
|
||||
|
||||
private static int getNumberOfElementsPerLine(List<FieldElement> elements, int start,
|
||||
int width) {
|
||||
int currentWidth = 0;
|
||||
int count = 0;
|
||||
int n = elements.length;
|
||||
for (int i = start; i < n; i++) {
|
||||
currentWidth += elements[i].getStringWidth();
|
||||
for (FieldElement element : elements) {
|
||||
currentWidth += element.getStringWidth();
|
||||
count++;
|
||||
if (currentWidth > width) {
|
||||
return Math.max(count - 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return elements.length - start;
|
||||
return elements.size() - start;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ public class ReverseClippingTextField implements TextField {
|
|||
}
|
||||
|
||||
isClipped = true;
|
||||
// get the index of the start character that will fit
|
||||
// get the index of the start character that will fit
|
||||
startingCharIndex =
|
||||
textElement.getMaxCharactersForWidth(w - (availableWidth - DOT_DOT_DOT_WIDTH)) + 1;
|
||||
startingCharIndex = Math.min(startingCharIndex, textElement.length());
|
||||
|
@ -150,6 +150,11 @@ public class ReverseClippingTextField implements TextField {
|
|||
return textElement.length() + 1; // allow one column past the end of the text
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumDataRows() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumRows() {
|
||||
return 1;
|
||||
|
@ -230,7 +235,8 @@ public class ReverseClippingTextField implements TextField {
|
|||
|
||||
@Override
|
||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight) {
|
||||
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc,
|
||||
int rowHeight) {
|
||||
if (context.isPrinting()) {
|
||||
print(g, context);
|
||||
}
|
||||
|
@ -341,7 +347,10 @@ public class ReverseClippingTextField implements TextField {
|
|||
@Override
|
||||
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
||||
int column = textElement.getCharacterIndexForDataLocation(dataRow, dataColumn);
|
||||
return new RowColLocation(0, Math.max(column, 0));
|
||||
if (column < 0) {
|
||||
return new DefaultRowColLocation();
|
||||
}
|
||||
return new RowColLocation(0, column);
|
||||
}
|
||||
|
||||
private int findX(int col) {
|
||||
|
@ -389,7 +398,9 @@ public class ReverseClippingTextField implements TextField {
|
|||
@Override
|
||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||
int col = textOffset + startingCharIndex;
|
||||
col = Math.max(col, 0);
|
||||
if (col < 0) {
|
||||
return new DefaultRowColLocation();
|
||||
}
|
||||
return new RowColLocation(0, Math.min(col, textElement.getText().length() - 1));
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import javax.swing.JComponent;
|
|||
|
||||
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
||||
import docking.widgets.fieldpanel.internal.PaintContext;
|
||||
import docking.widgets.fieldpanel.support.DefaultRowColLocation;
|
||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||
|
||||
/**
|
||||
|
@ -46,7 +47,8 @@ public class SimpleImageField implements Field {
|
|||
* @param startY the starting y coordinate of the field.
|
||||
* @param width the width of the field.
|
||||
*/
|
||||
public SimpleImageField(ImageIcon icon, FontMetrics metrics, int startX, int startY, int width) {
|
||||
public SimpleImageField(ImageIcon icon, FontMetrics metrics, int startX, int startY,
|
||||
int width) {
|
||||
this(icon, metrics, startX, startY, width, false);
|
||||
}
|
||||
|
||||
|
@ -115,6 +117,11 @@ public class SimpleImageField implements Field {
|
|||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumDataRows() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumRows() {
|
||||
return 1;
|
||||
|
@ -180,7 +187,8 @@ public class SimpleImageField implements Field {
|
|||
|
||||
@Override
|
||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc, int rowHeight) {
|
||||
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc,
|
||||
int rowHeight) {
|
||||
if (icon == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -263,7 +271,7 @@ public class SimpleImageField implements Field {
|
|||
|
||||
@Override
|
||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||
return new RowColLocation(0, 0);
|
||||
return new DefaultRowColLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -110,10 +110,15 @@ public class SimpleTextField implements Field {
|
|||
return startX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumDataRows() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see docking.widgets.fieldpanel.field.Field#getNumRows()
|
||||
*/
|
||||
*
|
||||
* @see docking.widgets.fieldpanel.field.Field#getNumRows()
|
||||
*/
|
||||
@Override
|
||||
public int getNumRows() {
|
||||
return 1;
|
||||
|
@ -199,7 +204,8 @@ public class SimpleTextField implements Field {
|
|||
|
||||
@Override
|
||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight) {
|
||||
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc,
|
||||
int rowHeight) {
|
||||
paintSelection(g, colorManager, 0);
|
||||
paintHighlights(g, hlFactory.getHighlights(this, text, -1));
|
||||
g.setFont(metrics.getFont());
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -24,75 +23,94 @@ import javax.swing.JComponent;
|
|||
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||
|
||||
/**
|
||||
* Used to force a clip to happen when the max lines is exceeded in the VerticalLayoutTextField
|
||||
* Used to force a clip to happen by using this field with space characters and size that far
|
||||
* exceeds the available painting width.
|
||||
*/
|
||||
|
||||
public class EmptyFieldElement implements FieldElement {
|
||||
public class StrutFieldElement implements FieldElement {
|
||||
|
||||
private final int width;
|
||||
|
||||
public EmptyFieldElement(int width) {
|
||||
public StrutFieldElement(int width) {
|
||||
this.width = width;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return ' ';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterIndexForDataLocation(int dataRow, int dataColumn) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Color getColor(int charIndex) {
|
||||
return Color.BLACK;
|
||||
return -1; // we have not characters
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowColLocation getDataLocationForCharacterIndex(int characterIndex) {
|
||||
return new RowColLocation(0, 0);
|
||||
}
|
||||
|
||||
public FieldElement getFieldElement(int column) {
|
||||
@Override
|
||||
public Color getColor(int charIndex) {
|
||||
return Color.BLACK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldElement getFieldElement(int characterOffset) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeightAbove() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeightBelow() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxCharactersForWidth(int stringWidth) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStringWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return width == 0 ? "" : " ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return width == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(JComponent c, Graphics g, int x, int y) {
|
||||
// nothing to paint
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldElement replaceAll(char[] targets, char replacement) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldElement substring(int start) {
|
||||
return new EmptyFieldElement(0);
|
||||
return new StrutFieldElement(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldElement substring(int start, int end) {
|
||||
return new EmptyFieldElement(0);
|
||||
return new StrutFieldElement(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ""; // empty text placeholder
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,37 +15,40 @@
|
|||
*/
|
||||
package docking.widgets.fieldpanel.field;
|
||||
|
||||
import docking.widgets.fieldpanel.support.DefaultRowColLocation;
|
||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||
|
||||
|
||||
public interface TextField extends Field {
|
||||
|
||||
/**
|
||||
* Sets this field to be primary such that its row is primary
|
||||
* @param b this field to be primary such that its row is primary
|
||||
*/
|
||||
public void setPrimary(boolean b);
|
||||
|
||||
/**
|
||||
* Translates a screen coordinate to a row and column in the data from the factory
|
||||
* @param screenRow the row in the displayed field text.
|
||||
* @param screenColumn the column in the displayed field text.
|
||||
* @return a RowColLocation containing the row and column within the data from the factory.
|
||||
*/
|
||||
public RowColLocation screenToDataLocation(int screenRow, int screenColumn);
|
||||
|
||||
/**
|
||||
* Translates a data row and column into a screen row and column.
|
||||
* @param dataRow row as defined by the factory
|
||||
* @param dataColumn the character offset into the dataRow
|
||||
* @return row and column in the screen coordinate system.
|
||||
*/
|
||||
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn);
|
||||
|
||||
/**
|
||||
* Returns true if the field is not displaying all the text information
|
||||
*/
|
||||
/**
|
||||
* Translates a screen coordinate to a row and column in the data from the factory
|
||||
* @param screenRow the row in the displayed field text.
|
||||
* @param screenColumn the column in the displayed field text.
|
||||
* @return a RowColLocation containing the row and column within the data from the factory.
|
||||
*/
|
||||
public RowColLocation screenToDataLocation(int screenRow, int screenColumn);
|
||||
|
||||
/**
|
||||
* Translates a data row and column into a screen row and column.
|
||||
* @param dataRow row as defined by the factory
|
||||
* @param dataColumn the character offset into the dataRow
|
||||
* @return row and column in the screen coordinate system; a {@link DefaultRowColLocation} if
|
||||
* this field does not contain the given column
|
||||
*/
|
||||
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn);
|
||||
|
||||
/**
|
||||
* Returns true if the field is not displaying all the text information
|
||||
* @return true if the field is not displaying all the text information
|
||||
*/
|
||||
public boolean isClipped();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the FieldElement at the given screen location.
|
||||
* @param screenRow the row on the screen
|
||||
|
@ -54,5 +56,5 @@ public interface TextField extends Field {
|
|||
* @return the FieldElement at the given screen location.
|
||||
*/
|
||||
public FieldElement getFieldElement(int screenRow, int screenColumn);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,27 +15,22 @@
|
|||
*/
|
||||
package docking.widgets.fieldpanel.field;
|
||||
|
||||
|
||||
public final class TextFieldElement extends AbstractTextFieldElement {
|
||||
public class TextFieldElement extends AbstractTextFieldElement {
|
||||
|
||||
public TextFieldElement(AttributedString attributedString, int row, int column) {
|
||||
super(attributedString, row, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see docking.widgets.fieldpanel.field.FieldElement#substring(int, int)
|
||||
*/
|
||||
@Override
|
||||
public FieldElement substring(int start, int end) {
|
||||
AttributedString as = attributedString.substring(start, end);
|
||||
if ( as == attributedString ) {
|
||||
if (as == attributedString) {
|
||||
return this;
|
||||
}
|
||||
return new TextFieldElement(as, row, column+start);
|
||||
return new TextFieldElement(as, row, column + start);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see docking.widgets.fieldpanel.field.FieldElement#replaceAll(char[], char)
|
||||
*/
|
||||
@Override
|
||||
public FieldElement replaceAll(char[] targets, char replacement) {
|
||||
return new TextFieldElement(attributedString.replaceAll(targets, replacement), row, column);
|
||||
}
|
||||
|
|
|
@ -16,25 +16,24 @@
|
|||
package docking.widgets.fieldpanel.field;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
||||
import docking.widgets.fieldpanel.internal.PaintContext;
|
||||
import docking.widgets.fieldpanel.support.*;
|
||||
|
||||
/**
|
||||
* This class provides a TextField implementation that takes multiple FieldElements and places
|
||||
* each on its own line within the field. It also can take a single FieldElements and
|
||||
* word wrap,creating new FieldElements (one per line).
|
||||
* each on its own line within the field.
|
||||
*/
|
||||
public class VerticalLayoutTextField implements TextField {
|
||||
|
||||
protected FieldElement[] textElements;
|
||||
protected List<Field> subFields; // list of fields for FieldElements
|
||||
protected List<TextField> subFields; // list of fields for FieldElements
|
||||
protected int startX;
|
||||
protected int width;
|
||||
protected int preferredWidth;
|
||||
|
@ -42,11 +41,34 @@ public class VerticalLayoutTextField implements TextField {
|
|||
|
||||
private int height;
|
||||
private int heightAbove;
|
||||
private int numDataRows;
|
||||
private boolean isPrimary;
|
||||
private String text;
|
||||
|
||||
// full text is all text with line separators, *but not with line delimiters*
|
||||
private String fullText;
|
||||
private List<String> lines;
|
||||
|
||||
// used in the getText() method to separate rows without adding newlines
|
||||
private String rowSeparator;
|
||||
|
||||
protected boolean isClipped;
|
||||
private String lineDelimiter; // used in the getText() method to separate lines
|
||||
|
||||
/**
|
||||
* This constructor will create a text field from an array of FieldElements, putting each
|
||||
* element on its own line.
|
||||
*
|
||||
* @param textElements the FieldElements to display
|
||||
* @param startX the x position to draw the element
|
||||
* @param width the max width allocated to this field
|
||||
* @param maxLines the max number of lines to display
|
||||
* @param hlFactory the highlight factory
|
||||
* @deprecated use the constructor that takes a list
|
||||
*/
|
||||
@Deprecated(since = "10.1", forRemoval = true)
|
||||
public VerticalLayoutTextField(FieldElement[] textElements, int startX, int width, int maxLines,
|
||||
HighlightFactory hlFactory) {
|
||||
this(Arrays.asList(textElements), startX, width, maxLines, hlFactory, " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor will create a text field from an array of FieldElements, putting each
|
||||
|
@ -58,7 +80,8 @@ public class VerticalLayoutTextField implements TextField {
|
|||
* @param maxLines the max number of lines to display
|
||||
* @param hlFactory the highlight factory
|
||||
*/
|
||||
public VerticalLayoutTextField(FieldElement[] textElements, int startX, int width, int maxLines,
|
||||
public VerticalLayoutTextField(List<FieldElement> textElements, int startX, int width,
|
||||
int maxLines,
|
||||
HighlightFactory hlFactory) {
|
||||
this(textElements, startX, width, maxLines, hlFactory, " ");
|
||||
}
|
||||
|
@ -72,25 +95,46 @@ public class VerticalLayoutTextField implements TextField {
|
|||
* @param width the max width allocated to this field
|
||||
* @param maxLines the max number of lines to display
|
||||
* @param hlFactory the highlight factory
|
||||
* @param lineDelimiter The string to space lines of text when concatenated by the
|
||||
* @param rowSeparator The string used to space lines of text when concatenated by the
|
||||
* getText() method.
|
||||
*/
|
||||
protected VerticalLayoutTextField(FieldElement[] textElements, int startX, int width,
|
||||
int maxLines, HighlightFactory hlFactory, String lineDelimiter) {
|
||||
protected VerticalLayoutTextField(List<FieldElement> textElements, int startX, int width,
|
||||
int maxLines, HighlightFactory hlFactory, String rowSeparator) {
|
||||
|
||||
this.textElements = textElements;
|
||||
this.startX = startX;
|
||||
this.width = width;
|
||||
|
||||
this.hlFactory = hlFactory;
|
||||
this.lineDelimiter = lineDelimiter;
|
||||
this.rowSeparator = rowSeparator;
|
||||
|
||||
subFields = layoutElements(maxLines);
|
||||
lines = generateLines(textElements);
|
||||
fullText = generateText(textElements, rowSeparator);
|
||||
subFields = layoutElements(textElements, maxLines);
|
||||
numDataRows = textElements.size();
|
||||
|
||||
this.preferredWidth = calculatePreferredWidth();
|
||||
preferredWidth = calculatePreferredWidth();
|
||||
calculateHeight();
|
||||
}
|
||||
|
||||
private List<String> generateLines(List<FieldElement> textElements) {
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
for (FieldElement field : textElements) {
|
||||
list.add(field.getText());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private String generateText(List<FieldElement> elements, String delimiter) {
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
int n = elements.size() - 1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
buf.append(elements.get(i).getText()).append(delimiter);
|
||||
}
|
||||
buf.append(elements.get(n).getText());
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected void calculateHeight() {
|
||||
heightAbove = (subFields.get(0)).getHeightAbove();
|
||||
for (Field field : subFields) {
|
||||
|
@ -108,15 +152,12 @@ public class VerticalLayoutTextField implements TextField {
|
|||
|
||||
@Override
|
||||
public String getText() {
|
||||
if (text == null) {
|
||||
text = generateText();
|
||||
}
|
||||
return text;
|
||||
return fullText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTextWithLineSeparators() {
|
||||
return generateText("\n");
|
||||
return StringUtils.join(lines, '\n');
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -144,6 +185,11 @@ public class VerticalLayoutTextField implements TextField {
|
|||
return startX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumDataRows() {
|
||||
return numDataRows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumRows() {
|
||||
return subFields.size();
|
||||
|
@ -157,11 +203,11 @@ public class VerticalLayoutTextField implements TextField {
|
|||
|
||||
@Override
|
||||
public int getRow(int y) {
|
||||
if (y < -heightAbove) {
|
||||
if (y < 0) {
|
||||
return 0;
|
||||
}
|
||||
int heightSoFar = -heightAbove;
|
||||
|
||||
int heightSoFar = 0;
|
||||
int n = subFields.size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
Field f = subFields.get(i);
|
||||
|
@ -247,7 +293,7 @@ public class VerticalLayoutTextField implements TextField {
|
|||
|
||||
int startY = myStartY;
|
||||
int translatedY = 0;
|
||||
|
||||
int extraSpace = rowSeparator.length();
|
||||
for (int i = 0; i < n; i++) {
|
||||
ClippingTextField subField = (ClippingTextField) subFields.get(i);
|
||||
int subFieldHeight = subField.getHeight();
|
||||
|
@ -276,7 +322,7 @@ public class VerticalLayoutTextField implements TextField {
|
|||
startY += subFieldHeight;
|
||||
g.translate(0, subFieldHeight);
|
||||
translatedY += subFieldHeight;
|
||||
columns += subField.getText().length() + lineDelimiter.length();
|
||||
columns += subField.getText().length() + extraSpace;
|
||||
}
|
||||
|
||||
// restore the graphics to where it was when we started.
|
||||
|
@ -355,6 +401,7 @@ public class VerticalLayoutTextField implements TextField {
|
|||
|
||||
/**
|
||||
* Returns the list of subfields in this field.
|
||||
* @return the list of subfields in this field.
|
||||
*/
|
||||
public List<Field> getSubfields() {
|
||||
return Collections.unmodifiableList(subFields);
|
||||
|
@ -372,27 +419,29 @@ public class VerticalLayoutTextField implements TextField {
|
|||
|
||||
@Override
|
||||
public void rowHeightChanged(int heightAbove1, int heightBelow) {
|
||||
// most fields don't care
|
||||
// most fields don't care
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldElement getFieldElement(int screenRow, int screenColumn) {
|
||||
|
||||
FieldElement clickedField = textElements[screenRow];
|
||||
return clickedField.getFieldElement(screenColumn);
|
||||
TextField f = subFields.get(screenRow);
|
||||
|
||||
int fieldRow = 0; // each field is on a single row
|
||||
return f.getFieldElement(fieldRow, screenColumn);
|
||||
}
|
||||
|
||||
protected List<Field> layoutElements(int maxLines) {
|
||||
List<Field> newSubFields = new ArrayList<>();
|
||||
protected List<TextField> layoutElements(List<FieldElement> textElements, int maxLines) {
|
||||
List<TextField> newSubFields = new ArrayList<>();
|
||||
|
||||
boolean tooManyLines = textElements.length > maxLines;
|
||||
boolean tooManyLines = textElements.size() > maxLines;
|
||||
|
||||
for (int i = 0; i < textElements.length && i < maxLines; i++) {
|
||||
FieldElement element = textElements[i];
|
||||
for (int i = 0; i < textElements.size() && i < maxLines; i++) {
|
||||
FieldElement element = textElements.get(i);
|
||||
if (tooManyLines && (i == maxLines - 1)) {
|
||||
FieldElement[] elements = new FieldElement[2];
|
||||
elements[0] = element;
|
||||
elements[1] = new EmptyFieldElement(500);
|
||||
elements[1] = new StrutFieldElement(500);
|
||||
element = new CompositeFieldElement(elements);
|
||||
}
|
||||
TextField field = new ClippingTextField(startX, width, element, hlFactory);
|
||||
|
@ -406,83 +455,70 @@ public class VerticalLayoutTextField implements TextField {
|
|||
}
|
||||
|
||||
/**
|
||||
* Translates the row and column to a String index and character offset into
|
||||
* Translates the row and column to a String index and character offset into
|
||||
* that string.
|
||||
* @param screenRow the row containing the location.
|
||||
* @param screenColumn the character position in the row of the location
|
||||
* @return a MultiStringLocation containing the string index and position
|
||||
* @return a MultiStringLocation containing the string index and position
|
||||
* within that string.
|
||||
*/
|
||||
@Override
|
||||
public RowColLocation screenToDataLocation(int screenRow, int screenColumn) {
|
||||
|
||||
screenRow = Math.min(screenRow, textElements.length - 1);
|
||||
screenRow = Math.min(screenRow, subFields.size() - 1);
|
||||
screenRow = Math.max(screenRow, 0);
|
||||
|
||||
screenColumn = Math.min(screenColumn, textElements[screenRow].length());
|
||||
TextField field = subFields.get(screenRow);
|
||||
screenColumn = Math.min(screenColumn, field.getText().length());
|
||||
screenColumn = Math.max(screenColumn, 0);
|
||||
|
||||
return textElements[screenRow].getDataLocationForCharacterIndex(screenColumn);
|
||||
int fieldRow = 0; // each field is on a single row
|
||||
return field.screenToDataLocation(fieldRow, screenColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the corresponding row, column for string index, and offset
|
||||
* @param dataRow index into the string array
|
||||
* @param dataColumn offset into the indexed string.
|
||||
*/
|
||||
@Override
|
||||
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
||||
for (int screenRow = textElements.length - 1; screenRow >= 0; screenRow--) {
|
||||
FieldElement element = textElements[screenRow];
|
||||
int screenColumn = element.getCharacterIndexForDataLocation(dataRow, dataColumn);
|
||||
if (screenColumn >= 0) {
|
||||
return new RowColLocation(screenRow, screenColumn);
|
||||
}
|
||||
|
||||
if (dataRow >= getNumRows()) {
|
||||
TextField lastField = subFields.get(subFields.size());
|
||||
return new DefaultRowColLocation(lastField.getText().length(), subFields.size() - 1);
|
||||
}
|
||||
|
||||
return new RowColLocation(0, 0); // give up
|
||||
}
|
||||
|
||||
protected String generateText() {
|
||||
return generateText(lineDelimiter);
|
||||
}
|
||||
|
||||
protected String generateText(String delimiter) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
int n = textElements.length - 1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
buf.append(textElements[i].getText()).append(delimiter);
|
||||
}
|
||||
buf.append(textElements[n].getText());
|
||||
return buf.toString();
|
||||
TextField field = subFields.get(dataRow);
|
||||
RowColLocation location = field.dataToScreenLocation(dataRow, dataColumn);
|
||||
return location.withRow(dataRow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int screenLocationToTextOffset(int row, int col) {
|
||||
if (row >= textElements.length) {
|
||||
if (row >= subFields.size()) {
|
||||
return getText().length();
|
||||
}
|
||||
int extraSpace = lineDelimiter.length();
|
||||
int extraSpace = rowSeparator.length();
|
||||
int len = 0;
|
||||
for (int i = 0; i < row; i++) {
|
||||
len += textElements[i].getText().length() + extraSpace;
|
||||
len += lines.get(i).length() + extraSpace;
|
||||
}
|
||||
len += Math.min(col, textElements[row].getText().length());
|
||||
len += Math.min(col, lines.get(row).length());
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||
int extraSpace = lineDelimiter.length();
|
||||
int n = textElements.length;
|
||||
int absoluteOffset = textOffset;
|
||||
int extraSpace = rowSeparator.length();
|
||||
int n = subFields.size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
int len = textElements[i].getText().length();
|
||||
if (textOffset < len + extraSpace) {
|
||||
return new RowColLocation(i, textOffset);
|
||||
int len = lines.get(i).length();
|
||||
if (absoluteOffset < len + extraSpace) {
|
||||
return new RowColLocation(i, absoluteOffset);
|
||||
}
|
||||
textOffset -= len + extraSpace;
|
||||
absoluteOffset -= len + extraSpace;
|
||||
}
|
||||
return new RowColLocation(n - 1, textElements[n - 1].getText().length());
|
||||
|
||||
int lastRow = n - 1;
|
||||
int lastColumn = subFields.get(lastRow).getText().length();
|
||||
return new DefaultRowColLocation(lastRow, lastColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,13 +17,16 @@ package docking.widgets.fieldpanel.field;
|
|||
|
||||
import docking.widgets.fieldpanel.support.*;
|
||||
|
||||
/**
|
||||
* A text field meant to take a string of text and wrap as needed.
|
||||
*/
|
||||
public class WrappingVerticalLayoutTextField extends VerticalLayoutTextField {
|
||||
|
||||
/**
|
||||
* This constructor will create a text field from an single AttributedString. The string will
|
||||
* This constructor will create a text field from an single AttributedString. The string will
|
||||
* be word wrapped.
|
||||
*
|
||||
* @param textElement the AttributedString to display
|
||||
* @param textElement the element to display
|
||||
* @param startX the x position to draw the string
|
||||
* @param width the max width allocated to this field
|
||||
* @param maxLines the max number of lines to display
|
||||
|
@ -31,12 +34,13 @@ public class WrappingVerticalLayoutTextField extends VerticalLayoutTextField {
|
|||
*/
|
||||
public WrappingVerticalLayoutTextField(FieldElement textElement, int startX, int width,
|
||||
int maxLines, HighlightFactory hlFactory) {
|
||||
|
||||
super(FieldUtils.wrap(textElement, width), startX, width, maxLines, hlFactory, "");
|
||||
super(FieldUtils.wrap(textElement, width), startX, width, maxLines, hlFactory, " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a text field from a single FieldElement. The text is wrapped, either an words or simply
|
||||
* This constructor will create a text field from an single AttributedString. The string will
|
||||
* be word wrapped.
|
||||
*
|
||||
* @param textElement is the element to display
|
||||
* @param startX is the position to draw the string
|
||||
* @param width is the max width allocated to this field
|
||||
|
@ -47,16 +51,12 @@ public class WrappingVerticalLayoutTextField extends VerticalLayoutTextField {
|
|||
public WrappingVerticalLayoutTextField(FieldElement textElement, int startX, int width,
|
||||
int maxLines, HighlightFactory hlFactory, boolean breakOnWhiteSpace) {
|
||||
super(FieldUtils.wrap(textElement, width, breakOnWhiteSpace), startX, width, maxLines,
|
||||
hlFactory, "");
|
||||
hlFactory, " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the corresponding row, column for string index, and offset
|
||||
* @param index index into the string array
|
||||
* @param offset offset into the indexed string.
|
||||
*/
|
||||
@Override
|
||||
public RowColLocation dataToScreenLocation(int index, int offset) {
|
||||
return textOffsetToScreenLocation(offset);
|
||||
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
||||
// we represent one data row that may be split into multiple screen rows
|
||||
return textOffsetToScreenLocation(dataColumn);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.widgets.fieldpanel.support;
|
||||
|
||||
/**
|
||||
* A location used to represent a an edge case where not suitable location can be found and the
|
||||
* client does not wish to return null.
|
||||
*/
|
||||
public class DefaultRowColLocation extends RowColLocation {
|
||||
public DefaultRowColLocation() {
|
||||
super(0, 0);
|
||||
}
|
||||
|
||||
public DefaultRowColLocation(int row, int col) {
|
||||
super(row, col);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowColLocation withCol(int newColumn) {
|
||||
return new DefaultRowColLocation(row, newColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowColLocation withRow(int newRow) {
|
||||
return new DefaultRowColLocation(newRow, col);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -35,9 +34,12 @@ public class FieldSelectionHelper {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Gets the selected text that pertains to an individual field. Null is returned if the
|
||||
* given selection spans more than one field.
|
||||
* @param selection the selection
|
||||
* @param panel the field panel
|
||||
* @return the text
|
||||
*/
|
||||
public static String getFieldSelectionText(FieldSelection selection, FieldPanel panel) {
|
||||
if (!isStringSelection(selection)) {
|
||||
|
@ -46,9 +48,14 @@ public class FieldSelectionHelper {
|
|||
return getTextForField(selection.getFieldRange(0), panel);
|
||||
}
|
||||
|
||||
/** Returns the text within the given selection. */
|
||||
/**
|
||||
* Returns the text within the given selection.
|
||||
* @param selection the selection
|
||||
* @param panel the field panel
|
||||
* @return the text
|
||||
*/
|
||||
public static String getAllSelectedText(FieldSelection selection, FieldPanel panel) {
|
||||
StringBuffer buffy = new StringBuffer();
|
||||
StringBuilder buffy = new StringBuilder();
|
||||
int numRanges = selection.getNumRanges();
|
||||
for (int i = 0; i < numRanges; i++) {
|
||||
FieldRange fieldRange = selection.getFieldRange(i);
|
||||
|
@ -99,7 +106,7 @@ public class FieldSelectionHelper {
|
|||
int startFieldNumber = startLoc.fieldNum;
|
||||
BigInteger endIndex = endLoc.getIndex();
|
||||
|
||||
StringBuffer buffy = new StringBuffer();
|
||||
StringBuilder buffy = new StringBuilder();
|
||||
for (BigInteger i = startIndex; i.compareTo(endIndex) <= 0; i = i.add(BigInteger.ONE)) {
|
||||
Layout layout = panel.getLayoutModel().getLayout(i);
|
||||
String text = null;
|
||||
|
@ -133,7 +140,7 @@ public class FieldSelectionHelper {
|
|||
|
||||
private static String getTextForFieldsInLayout(Layout layout, FieldRange fieldRange,
|
||||
int startFieldNumber, int endFieldNumber) {
|
||||
StringBuffer buffy = new StringBuffer();
|
||||
StringBuilder buffy = new StringBuilder();
|
||||
for (int i = startFieldNumber; i < endFieldNumber; i++) {
|
||||
Field field = layout.getField(i);
|
||||
buffy.append(field.getTextWithLineSeparators());
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package docking.widgets.fieldpanel.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import docking.widgets.fieldpanel.field.FieldElement;
|
||||
|
||||
|
@ -42,14 +41,14 @@ public class FieldUtils {
|
|||
* Splits the given FieldElement into sub-elements by wrapping the element on whitespace.
|
||||
*
|
||||
* @param fieldElement The element to wrap
|
||||
* @param width The maximum width to allow before wrapping
|
||||
* @param width The maximum width to allow before wrapping
|
||||
* @return The wrapped elements
|
||||
*/
|
||||
public static FieldElement[] wrap(FieldElement fieldElement, int width) {
|
||||
public static List<FieldElement> wrap(FieldElement fieldElement, int width) {
|
||||
|
||||
FieldElement originalFieldElement = fieldElement.replaceAll(WHITE_SPACE, ' ');
|
||||
if (originalFieldElement.getStringWidth() <= width) {
|
||||
return new FieldElement[] { originalFieldElement };
|
||||
return Arrays.asList(originalFieldElement);
|
||||
}
|
||||
|
||||
List<FieldElement> lines = new ArrayList<>();
|
||||
|
@ -63,7 +62,7 @@ public class FieldUtils {
|
|||
wordWrapPos = findWordWrapPosition(originalFieldElement, width);
|
||||
}
|
||||
lines.add(originalFieldElement);
|
||||
return lines.toArray(new FieldElement[lines.size()]);
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,14 +74,14 @@ public class FieldUtils {
|
|||
* @param breakOnWhiteSpace determines whether line breaks should happen at white space chars
|
||||
* @return the wrapped elements
|
||||
*/
|
||||
public static FieldElement[] wrap(FieldElement fieldElement, int width,
|
||||
public static List<FieldElement> wrap(FieldElement fieldElement, int width,
|
||||
boolean breakOnWhiteSpace) {
|
||||
if (breakOnWhiteSpace) {
|
||||
return wrap(fieldElement, width);
|
||||
}
|
||||
FieldElement originalFieldElement = fieldElement.replaceAll(WHITE_SPACE, ' ');
|
||||
if (originalFieldElement.getStringWidth() <= width) {
|
||||
return new FieldElement[] { originalFieldElement };
|
||||
return Arrays.asList(originalFieldElement);
|
||||
}
|
||||
|
||||
List<FieldElement> lines = new ArrayList<>();
|
||||
|
@ -99,14 +98,14 @@ public class FieldUtils {
|
|||
}
|
||||
}
|
||||
lines.add(originalFieldElement);
|
||||
return lines.toArray(new FieldElement[lines.size()]);
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the given FieldElement into sub-elements by wrapping the element on whitespace.
|
||||
*
|
||||
* @param fieldElement The element to wrap
|
||||
* @param width The maximum width to allow before wrapping
|
||||
* @param width The maximum width to allow before wrapping
|
||||
* @return The wrapped elements
|
||||
*/
|
||||
public static List<FieldElement> wordWrapList(FieldElement fieldElement, int width) {
|
||||
|
@ -133,10 +132,11 @@ public class FieldUtils {
|
|||
|
||||
/**
|
||||
* Finds the position within the given element at which to split the line for word wrapping.
|
||||
* This method only breaks on whitespace characters. It finds the last whitespace character
|
||||
* that completely fits within the given width. If there is no whitespace character before
|
||||
* the width break point, it finds the first whitespace character after the width. If the
|
||||
* element cannot be split at all, it returns 0.
|
||||
* This method finds the last whitespace character that completely fits within the given width.
|
||||
* If there is no whitespace character before the width break point, it finds the first
|
||||
* whitespace character after the width. If no whitespace can be found, then the text will
|
||||
* be split at a non-whitespace character.
|
||||
*
|
||||
* @param element the element to split
|
||||
* @param width the max width to allow before looking for a word wrap positions
|
||||
* @return 0 if the element cannot be split, else the character position of the string
|
||||
|
@ -156,30 +156,19 @@ public class FieldUtils {
|
|||
}
|
||||
|
||||
return wrapPosition;
|
||||
// The following code was replace with the return just above. This has the effect
|
||||
// of splitting contiguous words at the field width instead of at the next white
|
||||
// space beyond.
|
||||
// whiteSpacePosition = text.indexOf(" ", wrapPosition);
|
||||
// if (whiteSpacePosition >= 0) {
|
||||
// if (whiteSpacePosition + 1 >= element.length()) { // if whitespace at end, no split
|
||||
// return 0;
|
||||
// }
|
||||
// return whiteSpacePosition;
|
||||
// }
|
||||
// return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims "goofy" characters off of the given label, like spaces, '[',']', etc.
|
||||
* Trims unwanted characters off of the given label, like spaces, '[',']', etc.
|
||||
* @param string The string to be trimmed
|
||||
* @return The trimmed string.
|
||||
*/
|
||||
public static String trimString(String string) {
|
||||
// short-circuit case where the given string starts normally, but contains invalid
|
||||
// characters (e.g., param_1[EAX])
|
||||
StringBuffer buffer = new StringBuffer(string);
|
||||
StringBuilder buffer = new StringBuilder(string);
|
||||
if (Character.isJavaIdentifierPart(buffer.charAt(0))) {
|
||||
// in this case just take all valid characters and then exit
|
||||
// in this case just take all valid characters and then exit
|
||||
for (int index = 1; index < buffer.length(); index++) {
|
||||
int charAt = buffer.charAt(index);
|
||||
if (!Character.isJavaIdentifierPart(charAt)) {
|
||||
|
@ -189,7 +178,7 @@ public class FieldUtils {
|
|||
return buffer.toString();
|
||||
}
|
||||
|
||||
// the following case is when the given string is surrounded by "goofy" characters
|
||||
// the following case is when the given string is surrounded by "goofy" characters
|
||||
int index = 0;
|
||||
int charAt = buffer.charAt(index);
|
||||
while (!Character.isJavaIdentifierPart(charAt) && buffer.length() > 0) {
|
||||
|
|
|
@ -19,8 +19,9 @@ package docking.widgets.fieldpanel.support;
|
|||
* Simple class to return a row, column location.
|
||||
*/
|
||||
public class RowColLocation {
|
||||
private int row;
|
||||
private int col;
|
||||
protected int row;
|
||||
protected int col;
|
||||
|
||||
/**
|
||||
* Constructs a new RowColLocation with the given row and column.
|
||||
* @param row the row location
|
||||
|
@ -30,36 +31,48 @@ public class RowColLocation {
|
|||
this.row = row;
|
||||
this.col = col;
|
||||
}
|
||||
/**
|
||||
* Returns the row.
|
||||
*/
|
||||
|
||||
public int row() {
|
||||
return row;
|
||||
}
|
||||
/**
|
||||
* Returns the column.
|
||||
*/
|
||||
|
||||
public int col() {
|
||||
return col;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RowColLocation("+row+","+col+")";
|
||||
}
|
||||
|
||||
|
||||
public RowColLocation withCol(int newColumn) {
|
||||
return new RowColLocation(row, newColumn);
|
||||
}
|
||||
|
||||
public RowColLocation withRow(int newRow) {
|
||||
return new RowColLocation(newRow, col);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals( Object object ) {
|
||||
public String toString() {
|
||||
return row + "," + col;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + col;
|
||||
result = prime * result + row;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (object == null) {
|
||||
return false;
|
||||
}
|
||||
if ( object.getClass() == RowColLocation.class ) {
|
||||
RowColLocation loc = (RowColLocation) object;
|
||||
return (row == loc.row) && (col == loc.col);
|
||||
|
||||
if (!getClass().equals(object.getClass())) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
RowColLocation loc = (RowColLocation) object;
|
||||
return (row == loc.row) && (col == loc.col);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ public class RowLayout implements Layout {
|
|||
// Can only compress the last field, as the rest are potentially part of a grid surrounded
|
||||
// by other layouts
|
||||
//
|
||||
// Notes: we have to account for any offset for fields that are disabled and are in
|
||||
// Notes: we have to account for any offset for fields that are disabled and are in
|
||||
// the beginning of the row.
|
||||
//
|
||||
int startX = fields[0].getStartX();
|
||||
|
@ -180,8 +180,9 @@ public class RowLayout implements Layout {
|
|||
gapIndex = fields.length;
|
||||
}
|
||||
int startX =
|
||||
gapIndex == 0 ? rect.x : fields[gapIndex - 1].getStartX() +
|
||||
fields[gapIndex - 1].getWidth();
|
||||
gapIndex == 0 ? rect.x
|
||||
: fields[gapIndex - 1].getStartX() +
|
||||
fields[gapIndex - 1].getWidth();
|
||||
int endX = gapIndex >= fields.length ? rect.x + rect.width : fields[gapIndex].getStartX();
|
||||
|
||||
if (startX < endX) {
|
||||
|
@ -201,7 +202,7 @@ public class RowLayout implements Layout {
|
|||
Field field = fields[index];
|
||||
|
||||
cursorLoc.fieldNum = index;
|
||||
cursorLoc.row = field.getRow(y - heightAbove);
|
||||
cursorLoc.row = field.getRow(y);
|
||||
cursorLoc.col = field.getCol(cursorLoc.row, x);
|
||||
return field.getX(cursorLoc.row, cursorLoc.col);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ package docking.widgets.fieldpanel;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -32,10 +34,6 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest {
|
|||
|
||||
private FlowLayoutTextField textField;
|
||||
|
||||
public FlowLayoutTextFieldTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // we mean to use getFontMetrics
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
@ -47,156 +45,18 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest {
|
|||
Font font = new Font("Times New Roman", 0, 14);
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
FontMetrics fm = tk.getFontMetrics(font);
|
||||
FieldElement[] elements = new FieldElement[4];
|
||||
elements[0] = new TextFieldElement(new AttributedString("Hello ", Color.BLUE, fm), 0, 0);
|
||||
elements[1] = new TextFieldElement(
|
||||
new AttributedString("World ", Color.RED, fm, true, Color.BLUE), 1, 0);
|
||||
elements[2] =
|
||||
new TextFieldElement(new AttributedString(CLIPPED_STRING, Color.GREEN, fm), 2, 0);
|
||||
elements[3] = new TextFieldElement(new AttributedString("Wow! ", Color.GRAY, fm), 3, 0);
|
||||
List<FieldElement> elements = new ArrayList<>();
|
||||
|
||||
elements.add(new TextFieldElement(new AttributedString("Hello ", Color.BLUE, fm), 0, 0));
|
||||
elements.add(new TextFieldElement(
|
||||
new AttributedString("World ", Color.RED, fm, true, Color.BLUE), 1, 0));
|
||||
elements.add(
|
||||
new TextFieldElement(new AttributedString(CLIPPED_STRING, Color.GREEN, fm), 2, 0));
|
||||
elements.add(new TextFieldElement(new AttributedString("Wow! ", Color.GRAY, fm), 3, 0));
|
||||
|
||||
textField = new FlowLayoutTextField(elements, 100, 100, 3, factory);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getWidth()'
|
||||
*/
|
||||
@Test
|
||||
public void testGetWidth() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getHeight()'
|
||||
*/
|
||||
@Test
|
||||
public void testGetHeight() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getStartX()'
|
||||
*/
|
||||
@Test
|
||||
public void testGetStartX() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getNumRows()'
|
||||
*/
|
||||
@Test
|
||||
public void testGetNumRows() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getNumCols(int)'
|
||||
*/
|
||||
@Test
|
||||
public void testGetNumCols() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getRow(int)'
|
||||
*/
|
||||
@Test
|
||||
public void testGetRow() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getCol(int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testGetCol() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getY(int)'
|
||||
*/
|
||||
@Test
|
||||
public void testGetY() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getX(int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testGetX() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.isValid(int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testIsValid() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.paint(Graphics, PaintContext, boolean)'
|
||||
*/
|
||||
@Test
|
||||
public void testPaint() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.paintCursor(Graphics, PaintContext, boolean, int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testPaintCursor() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getCursorBounds(int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testGetCursorBounds() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.contains(int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testContains() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getScrollableUnitIncrement(int, int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testGetScrollableUnitIncrement() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.isPrimary()'
|
||||
*/
|
||||
@Test
|
||||
public void testIsPrimary() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.setPrimary(boolean)'
|
||||
*/
|
||||
@Test
|
||||
public void testSetPrimary() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getStringLocation(int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testScreenToDataLocation() {
|
||||
assertEquals(new RowColLocation(0, 0), textField.screenToDataLocation(0, 0));
|
||||
|
@ -222,9 +82,6 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest {
|
|||
assertEquals(new RowColLocation(3, 5), textField.screenToDataLocation(50, 75));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getWrappedLocation(int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testDataToScreenLocation() {
|
||||
assertEquals(new RowColLocation(0, 0), textField.dataToScreenLocation(0, 0));
|
||||
|
@ -247,9 +104,6 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest {
|
|||
assertEquals(new RowColLocation(0, 0), textField.dataToScreenLocation(0, 75));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getRowColumn(int)'
|
||||
*/
|
||||
@Test
|
||||
public void testGetRowColumn() {
|
||||
assertEquals(new RowColLocation(0, 0), textField.textOffsetToScreenLocation(0));
|
||||
|
@ -264,55 +118,5 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest {
|
|||
assertEquals(new RowColLocation(1, 18), textField.textOffsetToScreenLocation(30));
|
||||
|
||||
assertEquals(new RowColLocation(2, 5), textField.textOffsetToScreenLocation(1000));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getSubfields()'
|
||||
*/
|
||||
@Test
|
||||
public void testGetSubfields() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getHeightAbove()'
|
||||
*/
|
||||
@Test
|
||||
public void testGetHeightAbove() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getHeightBelow()'
|
||||
*/
|
||||
@Test
|
||||
public void testGetHeightBelow() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.rowHeightChanged(int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testRowHeightChanged() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getText()'
|
||||
*/
|
||||
@Test
|
||||
public void testGetText() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getTextOffset(int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testGetTextOffset() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ package docking.widgets.fieldpanel;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -32,10 +34,6 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest {
|
|||
|
||||
private VerticalLayoutTextField textField;
|
||||
|
||||
public VerticalLayoutTextFieldTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // we mean to use getFontMetrics
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
@ -47,20 +45,19 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest {
|
|||
Font font = new Font("Times New Roman", 0, 14);
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
FontMetrics fm = tk.getFontMetrics(font);
|
||||
FieldElement[] elements = new FieldElement[4];
|
||||
elements[0] = new TextFieldElement(new AttributedString("Hello", Color.BLUE, fm), 0, 0);
|
||||
elements[1] = new TextFieldElement(
|
||||
new AttributedString("World", Color.RED, fm, true, Color.BLUE), 1, 0);
|
||||
elements[2] =
|
||||
new TextFieldElement(new AttributedString(CLIPPED_STRING, Color.GREEN, fm), 2, 0);
|
||||
elements[3] = new TextFieldElement(new AttributedString("Wow!", Color.GRAY, fm), 3, 0);
|
||||
|
||||
List<FieldElement> elements = new ArrayList<>();
|
||||
|
||||
elements.add(new TextFieldElement(new AttributedString("Hello", Color.BLUE, fm), 0, 0));
|
||||
elements.add(new TextFieldElement(
|
||||
new AttributedString("World", Color.RED, fm, true, Color.BLUE), 1, 0));
|
||||
elements.add(
|
||||
new TextFieldElement(new AttributedString(CLIPPED_STRING, Color.GREEN, fm), 2, 0));
|
||||
elements.add(new TextFieldElement(new AttributedString("Wow!", Color.GRAY, fm), 3, 0));
|
||||
|
||||
textField = new VerticalLayoutTextField(elements, 100, 100, 5, factory);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getStringLocation(int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testScreenToDataLocation() {
|
||||
assertEquals(new RowColLocation(0, 0), textField.screenToDataLocation(0, 0));
|
||||
|
@ -81,11 +78,8 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest {
|
|||
assertEquals(new RowColLocation(3, 4), textField.screenToDataLocation(50, 75));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getWrappedLocation(int, int)'
|
||||
*/
|
||||
@Test
|
||||
public void testGetWrappedLocation() {
|
||||
public void testDataToScreenLocation() {
|
||||
assertEquals(new RowColLocation(0, 0), textField.dataToScreenLocation(0, 0));
|
||||
assertEquals(new RowColLocation(0, 2), textField.dataToScreenLocation(0, 2));
|
||||
assertEquals(new RowColLocation(0, 5), textField.dataToScreenLocation(0, 5));
|
||||
|
@ -96,26 +90,26 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest {
|
|||
|
||||
assertEquals(new RowColLocation(2, 0), textField.dataToScreenLocation(2, 0));
|
||||
assertEquals(new RowColLocation(2, 4), textField.dataToScreenLocation(2, 4));
|
||||
assertEquals(new RowColLocation(2, 15), textField.dataToScreenLocation(2, 15));
|
||||
assertEquals(new RowColLocation(2, 12), textField.dataToScreenLocation(2, 12));
|
||||
assertEquals(new DefaultRowColLocation(2, 12), textField.dataToScreenLocation(2, 15));
|
||||
|
||||
assertEquals(new RowColLocation(3, 0), textField.dataToScreenLocation(3, 0));
|
||||
assertEquals(new RowColLocation(3, 4), textField.dataToScreenLocation(3, 4));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getRowColumn(int)'
|
||||
*/
|
||||
@Test
|
||||
public void testGetRowColumn() {
|
||||
public void testTextOffsetToScreenLocation() {
|
||||
assertEquals(new RowColLocation(0, 0), textField.textOffsetToScreenLocation(0));
|
||||
assertEquals(new RowColLocation(0, 5), textField.textOffsetToScreenLocation(5));
|
||||
|
||||
assertEquals(new RowColLocation(1, 0), textField.textOffsetToScreenLocation(6));
|
||||
assertEquals(new RowColLocation(1, 4), textField.textOffsetToScreenLocation(10));
|
||||
assertEquals(new RowColLocation(1, 5), textField.textOffsetToScreenLocation(11));
|
||||
|
||||
assertEquals(new RowColLocation(2, 0), textField.textOffsetToScreenLocation(12));
|
||||
|
||||
assertEquals(new RowColLocation(1, 4), textField.textOffsetToScreenLocation(10));
|
||||
|
||||
assertEquals(new RowColLocation(3, 4), textField.textOffsetToScreenLocation(1000));
|
||||
assertEquals(new DefaultRowColLocation(3, 4), textField.textOffsetToScreenLocation(1000));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,586 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.widgets.fieldpanel.field;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import docking.widgets.fieldpanel.support.*;
|
||||
import generic.test.AbstractGenericTest;
|
||||
|
||||
public class CompositeVerticalLayoutTextFieldTest extends AbstractGenericTest {
|
||||
|
||||
private static final String LONG_STRING = "Supercalifragilisticexpialidocious";
|
||||
private FontMetrics fontMetrics;
|
||||
|
||||
private CompositeVerticalLayoutTextField field;
|
||||
private List<String> rows;
|
||||
|
||||
// some default field values
|
||||
int startX = 100; // arbitrary
|
||||
int width = 100; // used to trigger horizontal clipping
|
||||
int maxLines = 5; // used to trigger vertical clipping
|
||||
|
||||
private HighlightFactory hlFactory = (hlField, text, cursorTextOffset) -> {
|
||||
return new Highlight[] {};
|
||||
};
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
Font font = new Font("Times New Roman", 0, 14);
|
||||
fontMetrics = getFontMetrics(font);
|
||||
|
||||
field = createField(maxLines, List.of(
|
||||
"Hello",
|
||||
"World",
|
||||
LONG_STRING,
|
||||
"Wow!"));
|
||||
}
|
||||
|
||||
private CompositeVerticalLayoutTextField createField(int lineLimit, List<String> lines) {
|
||||
|
||||
rows = lines;
|
||||
|
||||
List<FieldElement> elements = new ArrayList<>();
|
||||
int row = 0;
|
||||
for (String line : lines) {
|
||||
elements.add(createRow(row++, line, Color.BLUE));
|
||||
}
|
||||
|
||||
List<TextField> fields = new ArrayList<>();
|
||||
for (FieldElement element : elements) {
|
||||
fields.add(new ClippingTextField(startX, width, element, hlFactory));
|
||||
}
|
||||
|
||||
return new CompositeVerticalLayoutTextField(fields, startX, width, lineLimit, hlFactory);
|
||||
}
|
||||
|
||||
private CompositeVerticalLayoutTextField createBasicWrappingField(List<String> lines) {
|
||||
|
||||
rows = lines;
|
||||
|
||||
List<FieldElement> elements = new ArrayList<>();
|
||||
int row = 0;
|
||||
for (String line : lines) {
|
||||
elements.add(createRow(row++, line, Color.BLUE));
|
||||
}
|
||||
|
||||
List<TextField> fields = new ArrayList<>();
|
||||
for (FieldElement element : elements) {
|
||||
fields.add(new WrappingVerticalLayoutTextField(element, startX, width, maxLines,
|
||||
hlFactory));
|
||||
}
|
||||
|
||||
return new CompositeVerticalLayoutTextField(fields, startX, width, maxLines, hlFactory);
|
||||
}
|
||||
|
||||
private CompositeVerticalLayoutTextField createMixedWrappingField(List<String> lines) {
|
||||
|
||||
rows = lines;
|
||||
|
||||
int row = 0;
|
||||
List<TextField> fields = new ArrayList<>();
|
||||
fields.add(wrappedField(row++, lines.get(0)));
|
||||
fields.add(clippedField(row++, lines.get(1)));
|
||||
fields.add(wrappedField(row++, lines.get(2)));
|
||||
|
||||
return new CompositeVerticalLayoutTextField(fields, startX, width, maxLines, hlFactory);
|
||||
}
|
||||
|
||||
private CompositeVerticalLayoutTextField createMixedWrappingField(TextField... fields) {
|
||||
return new CompositeVerticalLayoutTextField(Arrays.asList(fields), startX, width, maxLines,
|
||||
hlFactory);
|
||||
}
|
||||
|
||||
private TextField wrappedField(int row, String text) {
|
||||
FieldElement element = createRow(row, text, Color.BLUE);
|
||||
return new WrappingVerticalLayoutTextField(element, startX, width, maxLines, hlFactory);
|
||||
}
|
||||
|
||||
private TextField clippedField(int row, String text) {
|
||||
FieldElement element = createRow(row, text, Color.BLUE);
|
||||
return new ClippingTextField(startX, width, element, hlFactory);
|
||||
}
|
||||
|
||||
private FieldElement createRow(int row, String text, Color color) {
|
||||
return new TextFieldElement(new AttributedString(text, color, fontMetrics), row, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScreenToDataLocation() {
|
||||
|
||||
assertRowCol(0, 0, field.screenToDataLocation(0, 0));
|
||||
assertRowCol(0, 2, field.screenToDataLocation(0, 2));
|
||||
assertRowCol(0, 5, field.screenToDataLocation(0, 5));
|
||||
assertRowCol(0, 5, field.screenToDataLocation(0, 6)); // past end
|
||||
assertRowCol(0, 5, field.screenToDataLocation(0, 75));
|
||||
|
||||
assertRowCol(1, 0, field.screenToDataLocation(1, 0));
|
||||
assertRowCol(1, 5, field.screenToDataLocation(1, 6));
|
||||
assertRowCol(1, 5, field.screenToDataLocation(1, 16));
|
||||
|
||||
assertRowCol(2, 0, field.screenToDataLocation(2, 0));
|
||||
assertRowCol(2, 4, field.screenToDataLocation(2, 4));
|
||||
assertRowCol(2, 34, field.screenToDataLocation(2, 75));
|
||||
|
||||
assertRowCol(3, 0, field.screenToDataLocation(3, 0));
|
||||
assertRowCol(3, 4, field.screenToDataLocation(50, 75));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataToScreenLocation() {
|
||||
assertRowCol(0, 0, field.dataToScreenLocation(0, 0));
|
||||
assertRowCol(0, 2, field.dataToScreenLocation(0, 2));
|
||||
assertRowCol(0, 5, field.dataToScreenLocation(0, 5));
|
||||
|
||||
assertRowCol(1, 0, field.dataToScreenLocation(1, 0));
|
||||
assertRowCol(1, 4, field.dataToScreenLocation(1, 4));
|
||||
assertRowCol(1, 5, field.dataToScreenLocation(1, 5));
|
||||
|
||||
assertRowCol(2, 0, field.dataToScreenLocation(2, 0));
|
||||
assertRowCol(2, 4, field.dataToScreenLocation(2, 4));
|
||||
assertRowCol(2, 12, field.dataToScreenLocation(2, 12));
|
||||
assertRowCol(2, 12, field.dataToScreenLocation(2, 15));
|
||||
|
||||
assertRowCol(3, 0, field.dataToScreenLocation(3, 0));
|
||||
assertRowCol(3, 4, field.dataToScreenLocation(3, 4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTextOffsetToScreenLocation() {
|
||||
|
||||
//
|
||||
// Each row of text has text.lenghth() + 1 possible positions: before and after each
|
||||
// character. For example, in the text "hi", these are the possible cursor positions:
|
||||
//
|
||||
// |hi
|
||||
// h|i
|
||||
// hi|
|
||||
//
|
||||
|
||||
// each line may have a line separator
|
||||
int separator = field.getRowSeparator().length();
|
||||
|
||||
// dumpFieldOffsets();
|
||||
|
||||
// the end is after the last character
|
||||
String row1 = rows.get(0);
|
||||
int row1End = row1.length();
|
||||
assertRowCol(0, 0, field.textOffsetToScreenLocation(0));
|
||||
assertRowCol(0, row1End - 1, field.textOffsetToScreenLocation(row1End - 1));
|
||||
assertRowCol(0, row1End, field.textOffsetToScreenLocation(row1End));
|
||||
|
||||
int row2Start = row1End + separator;
|
||||
String row2 = rows.get(1);
|
||||
int row2End = row2Start + row2.length();
|
||||
int relativeEnd = row2End - row2Start;
|
||||
assertRowCol(1, 0, field.textOffsetToScreenLocation(row2Start));
|
||||
assertRowCol(1, relativeEnd - 1, field.textOffsetToScreenLocation(row2End - 1));
|
||||
assertRowCol(1, relativeEnd, field.textOffsetToScreenLocation(row2End));
|
||||
|
||||
String row3 = rows.get(2);
|
||||
int row3Start = row2End + separator;
|
||||
assertRowCol(2, 0, field.textOffsetToScreenLocation(row3Start));
|
||||
|
||||
int row3End = row3Start + row3.length();
|
||||
int row4Start = row3End + 1;
|
||||
assertRowCol(3, 0, field.textOffsetToScreenLocation(row4Start));
|
||||
|
||||
// far past the end will put the cursor at the end
|
||||
String row4 = rows.get(3);
|
||||
assertRowCol(3, row4.length(), field.textOffsetToScreenLocation(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScreenLocationToTextOffset() {
|
||||
|
||||
// each line may have a line separator
|
||||
int separator = field.getRowSeparator().length();
|
||||
|
||||
String row1 = rows.get(0);
|
||||
int row1End = row1.length();
|
||||
assertEquals(0, field.screenLocationToTextOffset(0, 0));
|
||||
assertEquals(row1End - 1, field.screenLocationToTextOffset(0, row1End - 1));
|
||||
assertEquals(row1End, field.screenLocationToTextOffset(0, row1End));
|
||||
|
||||
int row2Start = row1End + separator;
|
||||
String row2 = rows.get(1);
|
||||
int row2End = row2Start + row2.length();
|
||||
int relativeEnd = row2End - row2Start;
|
||||
assertEquals(row2Start, field.screenLocationToTextOffset(1, 0));
|
||||
assertEquals(row2End - 1, field.screenLocationToTextOffset(1, relativeEnd - 1));
|
||||
assertEquals(row2End, field.screenLocationToTextOffset(1, relativeEnd));
|
||||
|
||||
String row3 = rows.get(2);
|
||||
int row3Start = row2End + separator;
|
||||
assertEquals(row3Start, field.screenLocationToTextOffset(2, 0));
|
||||
|
||||
int row3End = row3Start + row3.length();
|
||||
int row4Start = row3End + 1;
|
||||
assertEquals(row4Start, field.screenLocationToTextOffset(3, 0));
|
||||
assertRowCol(3, 0, field.textOffsetToScreenLocation(row4Start));
|
||||
|
||||
// far past the end will put the cursor at the end
|
||||
String row4 = rows.get(3);
|
||||
int row4End = row4Start + row4.length();
|
||||
assertEquals(row4End, field.screenLocationToTextOffset(3, 1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFieldElement() {
|
||||
|
||||
String row1 = rows.get(0);
|
||||
assertEquals(row1, field.getFieldElement(0, 0).toString());
|
||||
assertEquals(row1, field.getFieldElement(0, 1).toString());
|
||||
assertEquals(row1, field.getFieldElement(0, row1.length()).toString());
|
||||
assertEquals(row1, field.getFieldElement(0, row1.length() + 1).toString());
|
||||
assertEquals(row1, field.getFieldElement(0, 100).toString());
|
||||
|
||||
String row2 = rows.get(1);
|
||||
assertEquals(row2, field.getFieldElement(1, 0).toString());
|
||||
assertEquals(row2, field.getFieldElement(1, 1).toString());
|
||||
assertEquals(row2, field.getFieldElement(1, row2.length()).toString());
|
||||
assertEquals(row2, field.getFieldElement(1, row2.length() + 1).toString());
|
||||
assertEquals(row2, field.getFieldElement(1, 100).toString());
|
||||
|
||||
String row3 = rows.get(2);
|
||||
assertEquals(row3, field.getFieldElement(2, 0).toString());
|
||||
assertEquals(row3, field.getFieldElement(2, 1).toString());
|
||||
assertEquals(row3, field.getFieldElement(2, row3.length()).toString());
|
||||
assertEquals(row3, field.getFieldElement(2, row3.length() + 1).toString());
|
||||
assertEquals(row3, field.getFieldElement(2, 100).toString());
|
||||
|
||||
String row4 = rows.get(3);
|
||||
assertEquals(row4, field.getFieldElement(3, 0).toString());
|
||||
assertEquals(row4, field.getFieldElement(3, 1).toString());
|
||||
assertEquals(row4, field.getFieldElement(3, row4.length()).toString());
|
||||
assertEquals(row4, field.getFieldElement(3, row4.length() + 1).toString());
|
||||
assertEquals(row4, field.getFieldElement(3, 100).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNumColumns() {
|
||||
|
||||
int separator = field.getRowSeparator().length();
|
||||
|
||||
String row1 = rows.get(0);
|
||||
int row1Columns = row1.length() + separator;
|
||||
assertEquals(row1Columns, field.getNumCols(0));
|
||||
|
||||
String row2 = rows.get(1);
|
||||
int row2Columns = row2.length() + separator;
|
||||
assertEquals(row2Columns, field.getNumCols(1));
|
||||
|
||||
// note: the number of columns is the clipped text length, which is 12, plus 1 extra
|
||||
// column to allow for placing the cursor after the text
|
||||
int clippedLength = 13; // not sure how to get this from the field
|
||||
assertEquals(clippedLength, field.getNumCols(2));
|
||||
|
||||
String row4 = rows.get(3);
|
||||
int row4Columns = row4.length() + separator;
|
||||
assertEquals(row4Columns, field.getNumCols(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClippingWithTooManyRows() {
|
||||
|
||||
int lineLimit = 2;
|
||||
field = createField(lineLimit, List.of(
|
||||
"Hello",
|
||||
"Wolrd",
|
||||
LONG_STRING,
|
||||
"Wow!"));
|
||||
|
||||
assertEquals(2, field.getNumRows());
|
||||
assertEquals(4, field.getNumDataRows());
|
||||
|
||||
assertRowCol(0, 0, field.dataToScreenLocation(0, 0));
|
||||
assertRowCol(0, 2, field.dataToScreenLocation(0, 2));
|
||||
assertRowCol(0, 5, field.dataToScreenLocation(0, 5));
|
||||
|
||||
assertRowCol(1, 0, field.dataToScreenLocation(1, 0));
|
||||
assertRowCol(1, 4, field.dataToScreenLocation(1, 4));
|
||||
assertRowCol(1, 5, field.dataToScreenLocation(1, 5));
|
||||
|
||||
// try accessing clipped rows
|
||||
assertRowCol(1, 0, field.dataToScreenLocation(2, 0));
|
||||
assertRowCol(1, 5, field.dataToScreenLocation(2, 5));
|
||||
assertRowCol(1, 5, field.dataToScreenLocation(20, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsClipped_NoClipping() {
|
||||
field = createField(maxLines, List.of("Hello", "Wolrd"));
|
||||
assertFalse(field.isClipped());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsClipped_HorizontalClipping() {
|
||||
field = createField(maxLines, List.of(LONG_STRING));
|
||||
assertTrue(field.isClipped());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsClipped_VerticalClipping() {
|
||||
int lineLimit = 2;
|
||||
field = createField(lineLimit, List.of(
|
||||
"Hello",
|
||||
"Wolrd",
|
||||
"Wow!"));
|
||||
assertTrue(field.isClipped());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsClipped_HorizontalAndVerticalClipping() {
|
||||
int lineLimit = 2;
|
||||
field = createField(lineLimit, List.of(
|
||||
"Hello",
|
||||
"Wolrd",
|
||||
LONG_STRING,
|
||||
"Wow!"));
|
||||
assertTrue(field.isClipped());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getGetAllRows() {
|
||||
|
||||
String row1 = rows.get(0);
|
||||
List<TextField> allRows = field.getAllRowsUpTo(0);
|
||||
assertEquals(1, allRows.size());
|
||||
assertEquals(row1, allRows.get(0).toString());
|
||||
|
||||
String row2 = rows.get(1);
|
||||
allRows = field.getAllRowsUpTo(1);
|
||||
assertEquals(2, allRows.size());
|
||||
assertEquals(row1, allRows.get(0).toString());
|
||||
assertEquals(row2, allRows.get(1).toString());
|
||||
|
||||
String row3 = rows.get(2);
|
||||
allRows = field.getAllRowsUpTo(2);
|
||||
assertEquals(3, allRows.size());
|
||||
assertEquals(row1, allRows.get(0).toString());
|
||||
assertEquals(row2, allRows.get(1).toString());
|
||||
assertEquals(row3, allRows.get(2).toString());
|
||||
|
||||
String row4 = rows.get(3);
|
||||
allRows = field.getAllRowsUpTo(3);
|
||||
assertEquals(4, allRows.size());
|
||||
assertEquals(row1, allRows.get(0).toString());
|
||||
assertEquals(row2, allRows.get(1).toString());
|
||||
assertEquals(row3, allRows.get(2).toString());
|
||||
assertEquals(row4, allRows.get(3).toString());
|
||||
|
||||
allRows = field.getAllRowsUpTo(10);
|
||||
assertEquals(4, allRows.size());
|
||||
|
||||
allRows = field.getAllRowsUpTo(-1);
|
||||
assertEquals(0, allRows.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetText() {
|
||||
assertEquals("Hello World Supercalifragilisticexpialidocious Wow! ", field.getText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTextWithLineSeparators() {
|
||||
assertEquals("Hello\nWorld\nSupercalifragilisticexpialidocious\nWow!",
|
||||
field.getTextWithLineSeparators());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetY_And_GetRow() {
|
||||
|
||||
int y = field.getY(0);
|
||||
int row = field.getRow(y);
|
||||
assertEquals("Wrong row for y value: " + y, 0, row);
|
||||
|
||||
y = field.getY(1);
|
||||
row = field.getRow(y);
|
||||
assertEquals("Wrong row for y value: " + y, 1, row);
|
||||
|
||||
y = field.getY(2);
|
||||
row = field.getRow(y);
|
||||
assertEquals("Wrong row for y value: " + y, 2, row);
|
||||
|
||||
y = field.getY(3);
|
||||
row = field.getRow(y);
|
||||
assertEquals("Wrong row for y value: " + y, 3, row);
|
||||
|
||||
// try values past the end
|
||||
int yForRowTooBig = field.getY(10);
|
||||
assertEquals(y, yForRowTooBig);
|
||||
int rowForYTooBig = field.getRow(1000);
|
||||
assertEquals(3, rowForYTooBig);
|
||||
|
||||
// try values before the beginning
|
||||
int yForRowTooSmall = field.getY(-1);
|
||||
int expectedY = -field.getHeightAbove();
|
||||
assertEquals(expectedY, yForRowTooSmall);
|
||||
int rowForYTooSmall = field.getRow(-1000);
|
||||
assertEquals(0, rowForYTooSmall);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetX_And_GetCol() {
|
||||
|
||||
String row1 = rows.get(0);
|
||||
int x = field.getX(0, 0);
|
||||
int column = field.getCol(0, x);
|
||||
assertEquals(0, column);
|
||||
|
||||
x = field.getX(0, row1.length());
|
||||
column = field.getCol(0, x);
|
||||
assertEquals(row1.length(), column);
|
||||
|
||||
String row2 = rows.get(1);
|
||||
x = field.getX(1, 0);
|
||||
column = field.getCol(1, x);
|
||||
assertEquals(0, column);
|
||||
|
||||
x = field.getX(1, row2.length());
|
||||
column = field.getCol(1, x);
|
||||
assertEquals(row2.length(), column);
|
||||
|
||||
String row3 = rows.get(2);
|
||||
x = field.getX(2, 0);
|
||||
column = field.getCol(2, x);
|
||||
assertEquals(0, column);
|
||||
|
||||
x = field.getX(2, row3.length());
|
||||
column = field.getCol(2, x);
|
||||
int clippedLength = 12; // not sure how to get this from the field
|
||||
assertEquals(clippedLength, column);
|
||||
|
||||
x = field.getX(2, row3.length() + 1);
|
||||
column = field.getCol(2, x);
|
||||
assertEquals(clippedLength, column);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLayoutWithWrapping_OneWrappedRow() {
|
||||
|
||||
//
|
||||
// Test the composite field when one of the internal fields will wrap into multiple rows
|
||||
// when too long.
|
||||
//
|
||||
|
||||
field =
|
||||
createBasicWrappingField(List.of("This is a line with multiple words for wrapping"));
|
||||
|
||||
assertEquals(4, field.getNumRows());
|
||||
|
||||
assertEquals("This is a line", field.getFieldElement(0, 0).getText());
|
||||
assertEquals("with multiple", field.getFieldElement(1, 0).getText());
|
||||
assertEquals("words for", field.getFieldElement(2, 0).getText());
|
||||
assertEquals("wrapping", field.getFieldElement(3, 0).getText());
|
||||
|
||||
// note: the final 'data' row becomes 4 'screen' rows
|
||||
assertEquals(15, field.getNumCols(0));
|
||||
assertEquals(14, field.getNumCols(1));
|
||||
assertEquals(10, field.getNumCols(2));
|
||||
assertEquals(9, field.getNumCols(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLayoutWrapping_TwoWrappedRow() {
|
||||
|
||||
field = createBasicWrappingField(List.of("This is line one", "This is line two"));
|
||||
|
||||
assertEquals(4, field.getNumRows());
|
||||
|
||||
assertEquals("This is line", field.getFieldElement(0, 0).getText());
|
||||
assertEquals("one", field.getFieldElement(1, 0).getText());
|
||||
assertEquals("This is line", field.getFieldElement(2, 0).getText());
|
||||
assertEquals("two", field.getFieldElement(3, 0).getText());
|
||||
|
||||
// note: the final 'data' row becomes 4 'screen' rows
|
||||
assertEquals(13, field.getNumCols(0));
|
||||
assertEquals(4, field.getNumCols(1));
|
||||
assertEquals(13, field.getNumCols(2));
|
||||
assertEquals(4, field.getNumCols(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLayoutWrapping_MixedRows() {
|
||||
|
||||
//
|
||||
// Test that we can mix wrapping and non-wrapping rows
|
||||
//
|
||||
|
||||
field = createMixedWrappingField(
|
||||
List.of("This is line one", "This line does not wrap", "This is line two"));
|
||||
|
||||
assertEquals(5, field.getNumRows());
|
||||
|
||||
assertEquals("This is line", field.getFieldElement(0, 0).getText());
|
||||
assertEquals("one", field.getFieldElement(1, 0).getText());
|
||||
assertEquals("This line does not wrap", field.getFieldElement(2, 0).getText());
|
||||
assertEquals("This is line", field.getFieldElement(3, 0).getText());
|
||||
assertEquals("two", field.getFieldElement(4, 0).getText());
|
||||
|
||||
// note: the final 'data' row becomes 5 'screen' rows
|
||||
assertEquals(13, field.getNumCols(0));
|
||||
assertEquals(4, field.getNumCols(1));
|
||||
assertEquals(14, field.getNumCols(2));
|
||||
assertEquals(13, field.getNumCols(3));
|
||||
assertEquals(4, field.getNumCols(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLayoutWrapping_MixedRows_TrailingWrappingRow() {
|
||||
|
||||
String row1 = "1: clipped row: This will be clipped horizonally";
|
||||
String row2 = "2: clipped row: This will be clipped horizonally";
|
||||
String row3 = "3: wrapped row: This field will wrap";
|
||||
TextField field1 = clippedField(0, row1);
|
||||
TextField field2 = clippedField(1, row2);
|
||||
TextField field3 = wrappedField(2, row3);
|
||||
|
||||
field = createMixedWrappingField(field1, field2, field3);
|
||||
|
||||
assertEquals(5, field.getNumRows());
|
||||
|
||||
assertEquals(row1, field.getFieldElement(0, 0).getText());
|
||||
assertEquals(row2, field.getFieldElement(1, 0).getText());
|
||||
assertEquals("3: wrapped", field.getFieldElement(2, 0).getText());
|
||||
assertEquals("row: This field", field.getFieldElement(3, 0).getText());
|
||||
assertEquals("will wrap", field.getFieldElement(4, 0).getText());
|
||||
|
||||
// not sure how to get this from the field
|
||||
int clippedLength = 14;
|
||||
assertEquals(clippedLength, field.getNumCols(0));
|
||||
assertEquals(clippedLength, field.getNumCols(1));
|
||||
|
||||
// note: the final 'data' row becomes 3 'screen' rows
|
||||
assertEquals(11, field.getNumCols(2));
|
||||
assertEquals(16, field.getNumCols(3));
|
||||
assertEquals(10, field.getNumCols(4));
|
||||
}
|
||||
|
||||
private void assertRowCol(int expectedRow, int expectedColumn, RowColLocation actualLocation) {
|
||||
assertEquals("Wrong row", expectedRow, actualLocation.row());
|
||||
assertEquals("Wrong column", expectedColumn, actualLocation.col());
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue