Question

The issue I have was hard to reproduce but I hope someone here can give me a hint on how to solve this.

I've written a ComponentProvider<JLabel> that takes a String value an creates an clickable cell decorated with a icon if the String contains a URL. If no URL is found in the String value, then no icon is set for the label and the cell shouldn't be clickable.

Here's the code:

public class ExternalLinkProvider extends ComponentProvider<JLabel> implements RolloverRenderer {

    private String url = null;

    @Override
    protected void format(CellContext context) {}

    @Override
    protected void configureState(CellContext context) {
        if (context.getValue() instanceof String) {
            String stringValue = (String) context.getValue();
            WwwLink link = new WwwLink(stringValue);

            // If this contains a valid Url, set a link icon.   
            if (link.isValid()) {
                rendererComponent.setIcon(ExternalLink.WWW_LINK_ICON);
                url = link.getUrl();
            } else {
                rendererComponent.setIcon(null);
                url = null;
            }
            rendererComponent.setText(link.getString());
        }
    }

    @Override
    protected JLabel createRendererComponent() {
        return new JRendererLabel();
    }

    @Override
    public boolean isEnabled() {
        return url != null;
    }

    @Override
    public void doClick() {
        if (url != null) {
              // Follow the url
        }
    }
}

It looks like this:

enter image description here

The first cell should be clickable to follow the link that was in the string value and has been removed from the display text. The second cell didn't contain a link in the text and therefore shouldn't be clickable.

However, in this case both cells aren't clickable and if I store the string value and print it out to the console from the isEnabled() method I see that always the text from the second cell is printed regardless if i hover over the first or the second cell.

This is the only situation I noticed this behavior. I know that the one Provider instance is reused for every cell containing this type, but for some reason the RolloverRenderer doesn't seem to reconfigure this Provider properly in this case.

Am I doing something wrong here?

Was it helpful?

Solution

After a bit of playing: you might have hit an issue here - all our examples are clickable always. Basically, it's brittle to keep cell related state in the provider, as it might be called often and for other cells.

The api of RolloverRenderer is not really rich enough: the mechanism relies on the renderer being configured just before a click happens (so that the "old" state still lingers), not good enough for your use case :-) You might consider filing a bug report in the swingx issue tracker, so we don't forget looking into it. Thanks.

Snippet to play with, basically demonstrating which methods to override in a custom provider (but not solving the problem at hand - except with a user-unfriendly kludge to have the rollover enabled always ...):

public class ExternalLinkProvider extends LabelProvider implements RolloverRenderer {

    private URL url = null;

    /**
     * Overridden to check for valid URL.
     */
    @Override
    protected void configureContent(CellContext context) {
        url = convertValueToUrl(context.getValue());
        super.configureContent(context);
    }

    private URL convertValueToUrl(Object result) {
        if (!(result instanceof String)) return null;
        URL url = null;

        try {
            url = new URL(result.toString());
        } catch (Exception e) {
            // TODO: handle exception
        }
        return url;

    }

    @Override
    protected Icon getValueAsIcon(CellContext context) {
        return url != null ? XTestUtils.loadDefaultIcon() : null;
    }

    /**
     * conditional enabled isn't reliably supported. Returning true 
     * uncondionally probably isn't option, as the cursor is changed ...
     */
    @Override
    public boolean isEnabled() {
        return true; //url != null;
    }

    @Override
    public void doClick() {
        if (url != null) {
              // Follow the url
            System.out.println("clicking");
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top