event underline with many Text element itext7 - java

I need extends TextRenderer for custom underline, but in one element Text i have one letter.
I have Large text and do this:
String s = "d < like to filter > RENDER_TEXT events as they are <written> to an output file. I have a <PDF that has some text in it> that I want filtered out. I've found that I can walk the document once and determine the characteristics of the render events that I want to filter. Now I'd like to copy the pages of the source document and skip over some RENDER_TEXT events so that the text does not appear in the destination document. I have an IEventFilter that will accept the correct events. I just need to know how to put this filter on the document writer.";
String[] words = s.split("");
Paragraph paragraph = new Paragraph();
Text text = null;
boolean isUnderStart = false;
boolean isUnderEnd = false;
int i = 1;
for (String word : words) {
if (word.equals("<")) {
isUnderStart = true;
}
if (word.equals(">")) {
isUnderEnd = true;
}
text = new Text(word);
text.setNextRenderer(new Word25TextRenderer(text, isUnderStart,isUnderEnd));
isUnderStart = false;
isUnderEnd = false;
paragraph.add(text);
i++;
}
doc.add(paragraph);
doc.close();
"<" и ">" i do for test (In a real program, I do to use Jsoup)
With help this symbols i find out coordinate axes for first simbol and end simbol. This is needed to draw the canvas element(line, curveTo). Also i add boolean to draw two times, the coordinates for the first letter and for the second.
Everything word for one line, if I want to draw underline for two line it does not break. In this part: <PDF that has some text in it>
static class Word25TextRenderer extends TextRenderer {
private boolean isUnderStart;
private boolean isUnderEnd;
public Word25TextRenderer(Text textElement, boolean isUnderStart, boolean isUnderEnd) {
super(textElement);
this.isUnderStart = isUnderStart;
this.isUnderEnd = isUnderEnd;
}
#Override
public IRenderer getNextRenderer() {
return new Word25TextRenderer((Text) modelElement, isUnderStart, isUnderEnd);
}
#Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
Rectangle textRect = getOccupiedAreaBBox();
int pageNumber = getOccupiedArea().getPageNumber();
PdfCanvas canvas = drawContext.getCanvas();
if (isUnderStart) {
canvas
.saveState()
.setStrokeColor(DeviceRgb.RED)
.moveTo(textRect.getRight(), textRect.getBottom());
}
if (isUnderEnd) {
canvas.curveTo(textRect.getRight(), textRect.getBottom() + textRect.getHeight() / 2,
textRect.getRight(), textRect.getBottom(),
textRect.getRight(), textRect.getBottom())
.stroke()
.restoreState();
}
}
}
Maybe you know other way?
Here's what happened in the end
p.s:I add one element to the text, because then I change the elements individually (font, fontSize etc) It's necessary!

Instead of doing the underlining at the Text element / renderer level, it's much handier to do it at the level of the Paragraph, where all the information about line split is known, since you have to underline parts of a same Text that are placed on different lines.
We will create a CustomText class to store information about whether we want to underline that piece of text still (although we could have used setProperty on a regular Text element):
static class CustomText extends Text {
private boolean isUnderStart;
private boolean isUnderEnd;
public CustomText(String text, boolean isUnderStart, boolean isUnderEnd) {
super(text);
this.isUnderStart = isUnderStart;
this.isUnderEnd = isUnderEnd;
}
public boolean isUnderStart() {
return isUnderStart;
}
public boolean isUnderEnd() {
return isUnderEnd;
}
}
The meaty part is our custom ParagraphRenderer - we go over the lines, remember the last "open bracket", or the text chunk start defines the start of the text to be underlined, and then once we face the "closing bracket", or the text chunk that defines the end of the text we do the actual drawing for the whole region. Additionally, we take care of the splits by underlining the remaining part of the line if by the time we finished line inspection we still have our "open bracket". Here id the code:
static class CustomParagraphRenderer extends ParagraphRenderer {
public CustomParagraphRenderer(Paragraph modelElement) {
super(modelElement);
}
#Override
public IRenderer getNextRenderer() {
return new CustomParagraphRenderer((Paragraph) modelElement);
}
#Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
Rectangle lastRectStart = null;
for (int i = 0; i < lines.size(); i++) {
LineRenderer lineRenderer = lines.get(i);
boolean anyEventsThisLine = false;
for (IRenderer renderer : lineRenderer.getChildRenderers()) {
if (renderer.getModelElement() instanceof CustomText &&
(((CustomText) renderer.getModelElement()).isUnderEnd()
|| ((CustomText) renderer.getModelElement()).isUnderStart())) {
anyEventsThisLine = true;
if ((((CustomText) renderer.getModelElement()).isUnderEnd())) {
Rectangle endRect = renderer.getOccupiedArea().getBBox();
PdfCanvas canvas = drawContext.getCanvas();
canvas.saveState().setStrokeColor(ColorConstants.RED)
.moveTo(lastRectStart.getRight(), lastRectStart.getBottom())
.curveTo(endRect.getRight(), endRect.getBottom() + endRect.getHeight() / 2,
endRect.getRight(), endRect.getBottom(),
endRect.getRight(), endRect.getBottom())
.stroke().restoreState();
lastRectStart = null;
} else {
lastRectStart = renderer.getOccupiedArea().getBBox();
}
}
}
if (lastRectStart != null && !anyEventsThisLine) {
// Underline the whole line
PdfCanvas canvas = drawContext.getCanvas();
Rectangle lineRect = lineRenderer.getOccupiedArea().getBBox();
canvas.saveState().setStrokeColor(ColorConstants.RED)
.moveTo(lineRect.getLeft(), lineRect.getBottom())
.curveTo(lineRect.getRight(), lineRect.getBottom() + lineRect.getHeight() / 2,
lineRect.getRight(), lineRect.getBottom(),
lineRect.getRight(), lineRect.getBottom())
.stroke().restoreState();
}
if (lastRectStart != null) {
// Draw till end of line
Rectangle endRect = lineRenderer.getChildRenderers().get(lineRenderer.getChildRenderers().size() - 1)
.getOccupiedArea().getBBox();
PdfCanvas canvas = drawContext.getCanvas();
canvas.saveState().setStrokeColor(ColorConstants.RED)
.moveTo(lastRectStart.getRight(), lastRectStart.getBottom())
.curveTo(endRect.getRight(), endRect.getBottom() + endRect.getHeight() / 2,
endRect.getRight(), endRect.getBottom(),
endRect.getRight(), endRect.getBottom())
.stroke().restoreState();
if (i + 1 < lines.size()) {
lastRectStart = lines.get(i + 1).getChildRenderers().get(0).getOccupiedArea().getBBox();
} else {
lastRectStart = null;
}
}
}
}
}
The main entry point code only has slight changes:
PdfDocument pdfDocument = new PdfDocument(new PdfWriter("C:/path/to.pdf"));
Document doc = new Document(pdfDocument);
String s = "d < like to filter > RENDER_TEXT events as they are <written> to an output file. I have a <PDF that has some text in it> that I want filtered out. I've found that I can walk the document once and determine the characteristics of the render events that I want to filter. Now I'd like to copy the pages of the source document and skip over some RENDER_TEXT events so that the text does not appear in the destination document. I have an IEventFilter that will accept the correct events. I just need to know how to put this filter on the document writer.";
String[] words = s.split("");
Paragraph paragraph = new Paragraph();
paragraph.setNextRenderer(new CustomParagraphRenderer(paragraph));
Text text = null;
boolean isUnderStart = false;
boolean isUnderEnd = false;
int i = 1;
for (String word : words) {
if (word.equals("<")) {
isUnderStart = true;
}
if (word.equals(">")) {
isUnderEnd = true;
}
text = new CustomText(word, isUnderStart, isUnderEnd);
isUnderStart = false;
isUnderEnd = false;
paragraph.add(text);
i++;
}
doc.add(paragraph);
doc.close();

Related

Remove Leading from the first Paragraph on every page itext 7 java

I need to remove Leading property in first Paragrapg on every page(FixedLeading)?
PdfDocument pdf = new PdfDocument(new PdfWriter(DEST));
Document document = new Document(pdf);
setGridForFirstPage(pdf);
document.setMargins(0, 25, 25, 25);
String line = "Hello! Welcome to iTextPdf";
Paragraph el = new Paragraph(line);
Div div = new Div();
for (int i = 0; i < 30; i++) {
Paragraph element = new Paragraph();
element.add(line + " " + i);
element.setFixedLeading(130);
div.add(element);
}
LayoutResult result = div.createRendererSubTree().setParent(document.getRenderer()).layout(new LayoutContext(new LayoutArea(0, document.getPdfDocument().getDefaultPageSize())));
LayoutResult savePageResult = null;
deleteProperties(result);
savePageResult = div.createRendererSubTree().setParent(document.getRenderer()).layout(new LayoutContext(new LayoutArea(0, document.getPdfDocument().getDefaultPageSize())));
LayoutResult nextPageResult = savePageResult.getOverflowRenderer().layout(new LayoutContext(new LayoutArea(3, document.getPdfDocument().getDefaultPageSize())));
deleteProperties(nextPageResult);
document.add(div);
document.close();
}
private static void deleteProperties(LayoutResult childRendererListParagraph) {
List<IRenderer> childRenderers = childRendererListParagraph.getSplitRenderer().getChildRenderers();
for (int j = 0; j < childRenderers.size(); j++) {
IRenderer iRendererList = childRenderers.get(j);
if (j == 0) {
if (iRendererList != null && iRendererList.getModelElement().hasProperty(33)) {
iRendererList.getModelElement().deleteOwnProperty(33);
}
}
}
}
Its works only two page, i try using a loop, but it didn't work out
Your approach seems plausible: I imagine it could be improved by looping through all the overflow renderers (perhaphs, I will try it out and update the answer someday).
However, there is quite a different approach, which for me seems to be more convenient and accurate: why not to override ParagraphRenderer, so that leading is reset each time the corresponding Paragraph can not fit a page (and hence will be moved to the next page).
This is how such an extension class may look:
class CustomParagraphRenderer extends ParagraphRenderer {
public CustomParagraphRenderer(Paragraph modelElement) {
super(modelElement);
}
#Override
public LayoutResult layout(LayoutContext layoutContext) {
LayoutResult result = super.layout(layoutContext);
if (result.getStatus() != LayoutResult.FULL) {
if (null != result.getOverflowRenderer()) {
result.getOverflowRenderer().setProperty(
Property.LEADING,
result.getOverflowRenderer().getModelElement().getDefaultProperty(Property.LEADING));
} else {
// if overflow renderer is null, that could mean that the whole renderer will overflow
setProperty(
Property.LEADING,
result.getOverflowRenderer().getModelElement().getDefaultProperty(Property.LEADING));
}
}
return result;
}
#Override
// If not overriden, the default renderer will be used for the overflown part of the corresponding paragraph
public IRenderer getNextRenderer() {
return new CustomParagraphRenderer((Paragraph) this.getModelElement());
}
}
Some points which I want to emphasize:
one should always override getNextRenderer in such cases, otherwise the default renderer will be used for the overflown part
it is better not to update the properties of the model element as you do, since in case you want to reuse the pararaph the initial properties will have been already gone. On the contrary, one should update the properties of the renderer itself (its properties have priority over the model element's, i.e. the paragraph's, ones)
And this is how you can use such a class. The only differences from your code are that:
setNextRenderer is called, so that your paragraph gets asociated with a custom renderer
leading for the first element is not set
doc.setMargins(0, 25, 25, 25);
String line = "Hello! Welcome to iTextPdf";
Div div = new Div();
for (int i = 0; i < 30; i++) {
Paragraph element = new Paragraph();
element.setNextRenderer(new CustomParagraphRenderer(element));
element.add(line + " " + i);
if (0 != i) {
element.setFixedLeading(130);
}
div.add(element);
}
And this is how the resultant PDF looks:

ClickableSpan in the EditText to the end of text calls click() to the end of line

I have an EditText and the TextWatcher, in which I check for patterns to determine where to create ClickableSpans.
private void checkSpans(){
Matcher matcher = Pattern.compile("(^|[ \\t\\n])#\\w+").matcher(text);
while (matcher.find()) {
BlueClickableSpan[] spans = getText().getSpans(matcher.start(), matcher.end(), BlueClickableSpan.class);
for (BlueClickableSpan span : spans) {
text.removeSpan(span);
}
text.setSpan(new BlueClickableSpan(),
matcher.start(),
matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
Here is my custom Span class.
private class BlueClickableSpan extends ClickableSpan {
#Override
public void onClick(View view) {
Spanned s = getText();
int start = s.getSpanStart(this);
int end = s.getSpanEnd(this);
String clickedString = s.subSequence(start, end).toString().trim();
if (onSpanClick != null)
onSpanClick.onClick(clickedString);
}
#Override
public void updateDrawState(TextPaint ds) {
ds.setColor(ContextCompat.getColor(IdeaFlowApp.getAppContext(), R.color.main_blue));
}
}
The problem is, when I end my text with a span and there is no characters after it and I tap AFTER it, it still counts as a click to span and onClick is called. Because of that I cant place cursor right after the span to continue editing. But if I print any symbol, even whitespace after the span, I can easily place the cursor after the span and everything works fine. Is there any way to fix the clicks in edittext after the clickable span if there are no symbols beyond?
I found a solution to my problem in dor506s answer here.
But there were some problems with multi-line text with spans, so I made some tweaks:
public class MovementMethod extends LinkMovementMethod {
#Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
int lineLength = line;
String[] lines = getText().toString().split("\n");
for (int i = 0; i <= line; i++) {
lineLength += lines[i].length();
}
if (off >= lineLength) {
// Return true so click won't be triggered in the leftover empty space
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
}
Maybe not the most beautiful multi-line solution, but it worked for me.

Processing Java: Cursor position of text box off

I am nearing completing the text box for my text editor besides selection and a few bugs with the text cursor. I have to implement it from scratch, because the other libraries do not suit the design needs for my editor. Every time the user completes a line and starts backspacing on the next line, the cursor and the text are not positioned properly when the user starts typing (the cursor is not on the right line). The gap becomes even more significant when the user keeps does this over and over again.
You can clearly see that the cursor (light blue) and the text are not aligned properly. I have attached the code only relevant to this problem. Sorry if the text box is not in optimal positioning, as I have transferred the code from my text editor to a degraded version for this problem.
What I think the culprit is: After a couple of hours, I found that the cursor position is dependent upon the line and column (as indicated on the labels) - I have not attached the labels to the example in this problem. The line shows 2, but it is supposed to be 1. When the column is 1 and the user backspaces, the line is supposed to decrease by 1 and the column set to the length of the previous line.
If you have any questions, I'd be more than happy to answer them. Because the code was complicated to transfer, a lot of it won't work properly (having the cursor move horizontally as the user types) but I think's it is good enough to solve the problem.
How to reach the problem:
Type some text in the first line
Hit enter
Try backspacing
Here is the text box code in Processing Java:
// Content
String content = "";
String[] adjustedLines = {
};
// Current position
int row = 1;
int line = 1;
int column = 1;
// Cursor length
float cursorLength = 12;
// Whether line has been subtracted and readjustment to text has been completed
boolean lineSubtracted = false;
// Positions of scrollbar
float cursorX = width/5 + 55;
float cursorY = 55;
void setup()
{
// Background and size
background(0);
size(1500, 700);
}
// Create set of line numbers given starting number and number of lines
void createLineNumbers(int startingNumber, int numberOfLines)
{
textAlign(LEFT);
String lineText = "";
textLeading(22);
for (int i = startingNumber; i <= startingNumber + numberOfLines; i++)
{
lineText += (str(i) + "\n");
}
fill(200);
text(lineText, width/5 + 12.5, 75);
textAlign(CENTER);
}
void draw()
{
background(0);
// Update cursor position
cursorX = width/5 + 55;
cursorY = 55;
textAlign(CENTER);
// Text Box
fill(80);
rect(width/5, 55, width*4/5, height-55);
textAlign(LEFT);
textLeading(22);
fill(255);
String[] contentLines = content.split("\n");
String display = "";
int lineDifference = 0;
display = content;
text(display, width/5+55, 75);
// Line Numbers
textAlign(CENTER);
fill(240);
createLineNumbers(1 + lineDifference, line + lineDifference);
cursorY = 55 + 22 * line;
textAlign(RIGHT);
// Cursor
stroke(149, 203, 250);
strokeWeight(4);
line(cursorX, cursorY, cursorX - cursorLength, cursorY);
noStroke();
textAlign(CENTER);
}
// Updates content and locations from user typing
void keyPressed()
{
String[] allLines = content.split("(?<=\n)");
boolean willPrint = false;
if (key == BACKSPACE)
{
if (column <= 1)
{
if (line > 1)
{
line--;
lineSubtracted = true;
finished = false;
}
column = 2;
if (lineSubtracted == true && allLines[allLines.length - 1].length() > 1 && allLines.length > 1)
{
column = allLines[allLines.length - 2].length();
}
}
if (content.length() > 0)
{
content = content.substring(0, content.length() - 1);
}
column--;
} else if (key == TAB)
{
column += 4;
content += " ";
} else
{
if (key == ENTER)
{
line++;
column = 0;
} else if (lineSubtracted == true && finished == false && line > 1)
{
if (line == allLines.length)
{
content = content.substring(0, content.length() - 1);
}
finished = true;
}
content += key;
column++;
}
column = allLines[allLines.length - 1].length();
}
For what it's worth, you're jumping through a lot of hoops just to display some editable text. Here is a simplified example that makes Processing do the work for you:
String text = "";
String cursor = "_";
boolean blink = true;
void setup() {
size(500, 500);
}
void draw() {
if(frameCount % 30 == 0){
blink = !blink;
}
background(0);
if(blink){
text(text, 100, 100, 200, 200);
}
else{
text(text+cursor, 100, 100, 200, 200);
}
}
void keyPressed()
{
if (key == BACKSPACE)
{
if (text.length() > 0) {
text = text.substring(0, text.length()-1);
}
} else {
text += key;
}
}

Java SWT show Line numbers for StyledText

I was wondering if there is a straightforward way to display line numbers with StyledText text field - even if lines are wrapped. I'm using it in my application and if content gets to big, some line numbers would be nice.
Thank you.
The key is org.eclipse.swt.custom.Bullet. It's basically a symbol (or in our case a number) you can add to the beginning of a line.
//text is your StyledText
text.addLineStyleListener(new LineStyleListener()
{
public void lineGetStyle(LineStyleEvent e)
{
//Set the line number
e.bulletIndex = text.getLineAtOffset(e.lineOffset);
//Set the style, 12 pixles wide for each digit
StyleRange style = new StyleRange();
style.metrics = new GlyphMetrics(0, 0, Integer.toString(text.getLineCount()+1).length()*12);
//Create and set the bullet
e.bullet = new Bullet(ST.BULLET_NUMBER,style);
}
});
This is my working implementation.
styledText.addLineStyleListener(new LineStyleListener() {
#Override
public void lineGetStyle(LineStyleEvent event) {
// Using ST.BULLET_NUMBER sometimes results in weird alignment.
//event.bulletIndex = styledText.getLineAtOffset(event.lineOffset);
StyleRange styleRange = new StyleRange();
styleRange.foreground = Display.getCurrent().getSystemColor(SWT.COLOR_GRAY);
int maxLine = styledText.getLineCount();
int bulletLength = Integer.toString(maxLine).length();
// Width of number character is half the height in monospaced font, add 1 character width for right padding.
int bulletWidth = (bulletLength + 1) * styledText.getLineHeight() / 2;
styleRange.metrics = new GlyphMetrics(0, 0, bulletWidth);
event.bullet = new Bullet(ST.BULLET_TEXT, styleRange);
// getLineAtOffset() returns a zero-based line index.
int bulletLine = styledText.getLineAtOffset(event.lineOffset) + 1;
event.bullet.text = String.format("%" + bulletLength + "s", bulletLine);
}
});
styledText.addModifyListener(new ModifyListener() {
#Override
public void modifyText(ModifyEvent e) {
// For line number redrawing.
styledText.redraw();
}
});
Note that the possible overhead of syntax highlighting recalculation when calling redraw() is likely to be acceptable, because lineGetStyle() are only called with lines currently on screen.
I believe that using a LineStyleListener should work. Something along the lines of:
styledText.addLineStyleListener(
new LineStyleListener() {
#Override
public void lineGetStyle(LineStyleEvent event) {
String line = event.lineText;
int lineNumber = event.lineOffset;
// Do stuff to add line numbers
}
}
);
This is a way to use bullets that updates the numbers when the content changes:
text.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent event) {
int maxLine = text.getLineCount();
int lineCountWidth = Math.max(String.valueOf(maxLine).length(), 3);
StyleRange style = new StyleRange();
style.metrics = new GlyphMetrics(0, 0, lineCountWidth * 8 + 5);
Bullet bullet = new Bullet(ST.BULLET_NUMBER, style);
text.setLineBullet(0, text.getLineCount(), null);
text.setLineBullet(0, text.getLineCount(), bullet);
}
});
As a side-note for colouring the line numbers:
Device device = Display.getCurrent();
style.background = new Color(device, LINE_NUMBER_BG);
style.foreground = new Color(device, LINE_NUMBER_FG);
where LINE_NUMBER_BG and LINE_NUMBER_FG might be a RGB object such as:
final RGB LINE_NUMBER_BG = new RBG(160, 80, 0); // brown
final RGB LINE_NUMBER_FG = new RGB(255, 255, 255); // white

In Java/Swing, is there a way to legally "attempt to mutate in notification"?

I was wondering if there is some sort of magic I can use to get around an IllegalStateException and allow a JTextField to "attempt to mutate in notification", or in other words to set its own text if its listener is triggered.
For your information, I am trying to program an auto-complete function which returns the most likely match in a range of 12 enums in response to a user's input in the JTextField.
Here is the code sample. You'll have to pardon my clumsy algorithm which creaks out enum results. I've highlighted the code which produces the exception with a comment:
jtfElement1.addCaretListener(new CaretListener() {
#Override
public void caretUpdate(CaretEvent e) {
String s = jtfElement1.getText();
int[] attributes = new int[13];
// iterate through each enum
for (BaseEnumAttributes b: BaseEnumAttributes.values()) {
// iterate through the length of the current text in jtfElement1
for (int i = 0; i < s.length(); i++) {
if (s.length() <= b.toString().length()) {
if (b.toString().charAt(i) == s.charAt(i)) {
// increase the number of "hits" noted for that enum
attributes[b.ordinal()] = attributes[b.ordinal()] + 1;
}
}
}
}
int priorC = 0;
int rightC = 0;
// iterate through the "array" of enums to find the highest score
for (int j = 0; j < attributes.length; j++) {
if (attributes[j] > priorC) {
priorC = attributes[j];
rightC = j;
}
}
if (!s.equals("")) {
// assign to b the Enum corresponding to the "array" with highest score
BaseEnumAttributes b = BaseEnumAttributes.values()[rightC];
iController.updateInputElement1String(b.toString());
// THIS TRIGGERS EXCEPTION
jtfElement1.setText(b.toString());
}
}
});
You are probably better off using a document filter or a custom document.
What are other listeners expected to see if the document doesn't stay the same during event dispatch?
Use SwingUtilities.invokeLater() placing all the modifications there
Maybe you can delay the setText() with a Thread to run after caretUpdate() has terminated.
i'm found on the same problem but i found an easy solution:
lock the caretUpdate() by a boolean if(false) while u'r setting the text to the jTextField than unlock it after . . something like this:
boolean caret = true;
private void listValueChanged(javax.swing.event.ListSelectionEvent evt) {
caret = false;
name.setText((String)list.getSelectedValue());
caret = true;
}
private void nameCaretUpdate(javax.swing.event.CaretEvent evt) {
if(caret){
model = new DefaultListModel();
this.fillList(name.getText());
list.setModel(model);
}
}
Create a custom Document and override insertString( )
filenameText = new JTextField(new FilenameDocument(), "", 0);
...
/**
* document which adds .xml extension if not specified
*
*/
private class FilenameDocument extends PlainDocument {
#Override
public void insertString(int offset, String insertedText, AttributeSet set)
throws BadLocationException {
if (offset == 0) {
insertedText = insertedText.trim( );
}
super.insertString(offset, insertedText, set);
if (filenameText != null) {
final int caretPos = filenameText.getCaretPosition();
String text = filenameText.getText().trim();
if (text.indexOf('.') == -1) {
filenameText.setText(text + ".xml");
filenameText.setCaretPosition(caretPos);
}
}
}
}
Note that calling setText will result in a recursive call to insertString( ), so make sure you have a stopping condition.
I'm surprised no one has answered this, but would'nt you have been better off implementing an editable JSpinner with a SpinnerListModel?

Categories