views:

123

answers:

2

I am developing a simple WYSIWYG RTF editor in Java and have a small issue. I need to be able to synchronize the style selection toggle buttons (such as bold, italic, underlined) to the users text selection. For example, if the current text selection is plain, the bold, italic and underlined toggle buttons are not selected, but when the user selects some text that is bold and underlined, the bold and underlined toggle buttons are selected.

Now i am fairly sure that JTextPane.getInputAttributes() gets me the selection attributes I want but there is an issue with listening for caret update events. The issue is that caret listener attached to the JTextPane seems to be called AFTER the input attribute change occurs. So the selection is always one step behind. That is, i must select the text twice before the toggle buttons are updated!

The important code here is:

textPane.addCaretListener(new CaretListener() {

        @Override
        public void caretUpdate(CaretEvent e) {
            syncAttributesWithUI(textPane.getInputAttributes());
        }
    });

And:

private void syncAttributesWithUI(AttributeSet attributes) {
    boldButton.setSelected(StyleConstants.isBold(attributes));
    italicButton.setSelected(StyleConstants.isItalic(attributes));
    underlineButton.setSelected(StyleConstants.isUnderline(attributes));
}

Thanks in advance!

+1  A: 

The CaretListener is listening to your textPane, but the existing attributes for the selection are in your Document. You can use the CaretEvent methods to find the selected part of the Document and condition your buttons based on the styles found there. Unfortunately, the selection may be incoherent, e.g. part bold and part italic. A common practice is to assume the user wants to apply a completely new set of attributes to the entire selection.

trashgod
The method you suggest is in fact what I was originally doing. I would get each individual character element of the selection and find the attribute set intersection to determine what the UI should reflect. But then I realised that 1) The getInputAttributes() method seems to do this already, and 2) My method cannot determine what style is being applied if the caret is moved to the last position in the document until the user has triggered an input. Of course I can probably determine this by working out the character style at (end position - 1), but I was hoping there to be a cleaner way :(
S73417H
I'd expect the user to want the attributes returned by `getInputAttributes()` to remain unaltered when the caret is at the end.
trashgod
+1  A: 

You could try to postpone the sync, so the other changes could happen first:

@Override
public void caretUpdate(CaretEvent e) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            syncAttributesWithUI(textPane.getInputAttributes());
        }
    });
}

(Disclaimer: Guessing from the top of my head -- I didn't actually write a test to confirm)

netzwerg