Swing text API: Override LabelView with different string length?
Asked Answered
D

1

6

I've got a StyledDocument instance that contains, among other things, strings that represent numbers. By overriding the attributes of the string's element, I'm using a custom View for them that I derived from LabelView. I want to allow the user to select the base of the displayed number, e.g. decimal or hexadecimal. This is my current solution:

public class AddressView extends LabelView {
    @Override
    public Segment getText(int p0, int p1) {
        // get string representation of the number from the model
        String stringNumber = super.getText(p0, p1).toString();

        // get base from document's attributes
        int base = getDocument().getProperty(BaseProperty);

        // convert string to desired base
        String stringNumberOverride = Integer.toString(Integer.parseInt(stringNumber), base);

        // return as segment (can have a different length, JTextPane doesn't like that)
        char[] strNum = stringNumberOverride.toCharArray();
        return new Segment(strNum, 0, strNum.length);
    }
}

There's only one problem: Selecting text doesn't work anymore because the returned string of getText doesn't have the requested length (p1 - p0). The JTextPane component is implemented to select exactly that many chars, so with the above solution the user can only select p1 - p0 characters, even though the new base could have displayed a longer string representation of the number string in the model.

So, what's the correct way to have a View that displays a String that has a different length than the one in the model? I don't want to update the Model just because the user desires a different representation of the content.

Edit: Here's a self-contained example. Try selecting the text - you can only select all chars or no chars because there's only one character in the model.

package mini;

import javax.swing.*;
import javax.swing.text.*;

public class Mini extends JFrame {
    public Mini() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        JTextPane pane = new JTextPane();
        pane.setEditorKit(new MyEditorKit());
        add(new JScrollPane(pane));
        pack();
    }

    public static void main(String[] args) {
        Mini mini = new Mini();
        mini.setVisible(true);
    }
}

class MyEditorKit extends StyledEditorKit {
    @Override
    public ViewFactory getViewFactory() {
        return new ViewFactory() {
            public View create(Element elem) {
                return new MyView(elem);
            }
        };
    }
}

class MyView extends LabelView {
    public MyView(Element elem) {
        super(elem);
    }

    @Override
    public Segment getText(int p0, int p1) {
        String line = "Displayed text that's longer than model text";
        return new Segment(line.toCharArray(), 0, line.length());
    }
}
Doradorado answered 22/11, 2013 at 18:12 Comment(6)
this question required an SSCCE with hardcoded value for Document in local variable, note there are important changes (some mistakes???) in Java7 in comparing with Java6Dachy
I think that @StanislavL is right person for question about this area, search in your posts with additional params as ViewFactory or LabelView areDachy
I am really having hard time to understand you. Could you please explain a bit further, what actually you are trying to achieve:I want to allow the user to select the base of the displayed number, e.g. decimal or hexadecimal what does it mean ?Asomatous
@Sage: Well, I've got strings containing numbers like "123" in my document. I use custom instances of Element so I can use custom View instances for them. Now I'd like to be able to display them in hexadecimal instead of decimal, e.g. "0x7B" instead of "123". I do not want to change all the strings in the model because that would be too slow. When overriding getText in the View, the user can't select the text correctly anymore because the length is different (4 chars for 0x7B vs 123). So what's the correct way to do this?Doradorado
@fpw, if you change the string upon insertion it would not make it slow. I am having hard time to reach to your point for not using Docuemnt. If i am understanding you correctly if i type: This is what your ID 123 and reach to the station. You want it as: this is what your ID 0x7B and reach to the station. I don't think using EditorKit to change data on view is going to make this faster. Because, returned label view's getText will always gets called while inserting the data and it needs to be called the complete text of the document to render the view.Asomatous
@Sage: It will become slow because I insert new data at random positions while parsing a binary file. I'm actually writing a disassembler and all the data is present in my decode tree, hence I don't need a Document if I can avoid it. I already tried changing the document on the fly, but iterating 20.000 Element nodes in the document because the user decices to view constants as hexadecimal is no fun.Doradorado
E
0

There are a few possible ways to solve.

  1. Could you define bigger Strings for the numbers adding e.g. spaces to always have equal length of text? E.g. you have numbers from 1-100 so append spaces before or after to have always 3 chars.

  2. If you need just to change rendering leaving all the reas as is. You can override

    public void paint(Graphics g, Shape a)

method and use g.drawString() to render desired text. You can set font from document's method public Font getFont(AttributeSet attr). The question is how to handle size changes and caret navigation in the number but it is also possible to overcome.

Epiphytotic answered 25/11, 2013 at 5:38 Comment(2)
Suggestion 1 would be possible, but it's like a hack and works only in this case. The numbers were just one example, I'd like to have a general solution to use LabelViews without a Document in a way that I can arrange many of them and select text that spans them. I've looked at something similar as your 2nd suggestion on your website - the hyphenation example. It suffers the same problem, try selecting text across a hyphenation (I tried mailing you about that, but your address is forwarded to a dead address)Doradorado
You can use slapitsky (a) gmail.com In general you have all the tools you need. You can check in the JTextPane whether the range is selected and change paint background/foreground.Epiphytotic

© 2022 - 2024 — McMap. All rights reserved.