Strange interference: JXMultiSplitPane and editorPane

View: New views
3 Messages — Rating Filter:   Alert me  

Strange interference: JXMultiSplitPane and editorPane

by jdnc-interest :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

or maybe I'm simply doing something plain wrong - pointers highly appreciated.

The story:

as posted in the one and other thread, I'm currently working on the swinglabs-demos, mainly moving to 1.6 and at the same time to use SwingX itself in the demo-framework (known as swingset3). One part of that is to use a JXMultiSplitPane for the primary demo frame: taskpane left, the demo container right top, the code viewer right bottom. Next step was to replace the actual demo container - which in the original framework is custom panel with a border responsible for painting the title bar - with a guess-what, JXTitledPanel. So far this had been working well enough, see the web demo (ignore all the other construction sites in it)

https://swinglabs-demos.dev.java.net/demos/swingxset6/swingxset.jnlp

There's a minor visual glitch that the title/panel background isn't shown up to the top/bottom border lines, but that's a side-effect of the roundedBorder, I think - please ignore.

Just to clarify (re-read the following, might not be completely clear): when I say "demoContainer" I mean the titled panel in the right upper part of the multisplit. The "description/editor" - if present - is the left of the demoContainer. The "demo" is either its complete contentPane if there is no description or the right part of the demoContainer which overlaps the title aera, if there is a description.

As mentioned in the recent thread about JXTitledPane - splashing around, in hindsight <g> - the layout of overlapping the demo with the title is ... ehem ... a dirty trick (in the original, but kept until yesterday out of lazyness) - it's done manually, side-stepping the layoutManager (if any). Naturally (nearly always in manual layout), it's not good enough - f.i. fails if the prefSize of the demo is larger than the demoContainer's size. Obviously, I couldn't resist but try to cleanup a bit: the idea was to let the borderlayout do most of the work and simply pull up the upper location of the demo to get that nice overlap effect. Completely astonished, that this didn't work at all if there's a description which is shown in the right part of the democontainer:  added to a scrollpane which is added with constraint BorderLayout.WEST it shows the text without line wraps ... effectively filling (and exceeding) all horizontal space.

Spend the most of the day trying to track that down (remembered that JEditorPane isn't the most straightforward component to use): one issue was that the editor wasn't ever validated - remember: the original layout was null, so didn't matter ;-) Took a while to re-understand how to handle that given the asynchronous content loading  from an URL. At the end of the day - no luck yet in the context of the swingxdemo - it turned out that part of the problem comes from the JXMultiSplit: even with a plain panel which contains a editor in a  scrollpane, I can't make it work as I would expect it to work. Below is a example comparing two frames with/out splitpane: one has a plain panel with borderlayout as the frame content, the other has a multiSplitPane. Editor is added by clicking on the tasks, either from a string or reading a resource. The main problem with the splitpane is that the scrollpane isn't updated. Loosing the overview of where-to/how-to spread revalidate/repaint calls ... so hoping for some kind soul looking into this (will take a constructive easy-you-idiot gracefully and thankfully :-)

Thanks
Jeanette

[code]

// the example

/**
 */
public class LoadedPanelExperiments {
    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(LoadedPanelExperiments.class.getName());
   
    private JComponent createSplitPane() {
        final JComponent demoContainer = new JXPanel(new BorderLayout());
        demoContainer.setBorder(BorderFactory.createLineBorder(Color.RED));
       
//      <snip> MultiSplit layout declaration
        String layout =
            "(ROW " +
                 "(LEAF name=selector weight=0.3)" +
                 "(COLUMN weight=0.7 " +
                     "(LEAF name= demo weight=0.7)" +
                     "(LEAF name=source weight=0.3)" +
                 ")" +
            ")";
        MultiSplitLayout multiSplitLayout = new MultiSplitLayout(MultiSplitLayout.parseModel(layout));
//        </snip>
        JXMultiSplitPane splitPane = new JXMultiSplitPane();
        splitPane.setLayout(multiSplitLayout);
        splitPane.add("selector", createButtonStack(demoContainer));
        splitPane.add("demo", demoContainer);
        return splitPane;
    }


    private JComponent createPlainContent() {
        final JComponent demoContainer = new JXPanel(new BorderLayout());
        demoContainer.setBorder(BorderFactory.createLineBorder(Color.RED));
        JComponent splitPane = new JXPanel(new BorderLayout());
        splitPane.add(createButtonStack(demoContainer), BorderLayout.WEST);
        splitPane.add(demoContainer);
        return splitPane;
    }
   

    private JComponent createButtonStack(JComponent demoContainer) {
        JComponent buttonStack = new JXTaskPaneContainer();
        JXTaskPane taskPane = new JXTaskPane();
        taskPane.setTitle("demo");
        taskPane.add(createTextAction(demoContainer));
        taskPane.add(createPageAction(demoContainer));
        buttonStack.add(taskPane);
        return buttonStack;
    }
   
    /**
     * @param demoContainer
     * @return
     */
    private Action createTextAction(final JComponent demoContainer) {
        Action action = new AbstractAction("add editor - setText") {
           
            @Override
            public void actionPerformed(ActionEvent e) {
                demoContainer.removeAll();
                demoContainer.add(new JScrollPane(createEditorSetText()));
                demoContainer.revalidate();
               
            }
        };
        return action;
    }

    /**
     * @param demoContainer
     * @return
     */
    private Action createPageAction(final JComponent demoContainer) {
        Action page = new AbstractAction("add editor - setPage") {
           
            @Override
            public void actionPerformed(ActionEvent e) {
                demoContainer.removeAll();
                demoContainer.add(new JScrollPane(createEditorSetPage()));
                demoContainer.revalidate();
               
            }
        };
        return page;
    }
    /**
     * @return
     */
    protected JComponent createEditorSetPage() {
        final JEditorPane editor = createEditor();
        URL descriptionURL = getHTMLDescription();
        try {
            editor.setPage(descriptionURL);
        } catch (IOException e) {
            System.err.println("couldn't load description from URL:" + descriptionURL);
        }
        PropertyChangeListener l = new PropertyChangeListener() {
           
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                JComponent parent = SwingXUtilities.getAncestor(JScrollPane.class, editor);
                parent.revalidate();
                parent.repaint();
            }
        };
        editor.addPropertyChangeListener("page", l);
        return editor;
    }
    /**
     * @return
     */
    protected JComponent createEditorSetText() {
        final JEditorPane editor = createEditor();
        editor.setText(dummyText);
        return editor;
    }

    /**
     * @return
     */
    private JEditorPane createEditor() {
        final JEditorPane editor = new JEditorPane();
        editor.setContentType("text/html");
        editor.setEditable(false);
        editor.setOpaque(true);
        return editor;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createFrame(new LoadedPanelExperiments().createPlainContent(), false);
                createFrame(new LoadedPanelExperiments().createSplitPane(), true);
            }

            /**
             * @param content
             * @param split
             */
            private JXFrame createFrame(JComponent content, boolean split) {
                JXFrame frame = new JXFrame("LoadedPanelExperiments" + (split ? " MultiSplitPane" : " Plain"));
                frame.add(content);
                frame.setSize(400, 200);
                if (split) {
                    frame.setLocation(frame.getLocation().x + 400, frame.getLocation().y);
                }
                frame.setVisible(true);
                return frame;
            }
        });
    }

    public URL getHTMLDescription() {
        // by default look for an html file with the same name as the demo class
        return getClass().getResource(htmlURL);    
    }

    private String htmlURL = "MultiSplitPaneDemo.html";
   
    String dummyText =
        "<html>"
    +" <head>"
    +"  <title>JXMultiSplitPane Demo</title>"
    +"</head>"
    +"<body>"
    +"JXMultiSplitPane is a container that can be split into multiple resizeable"
    +"areas. The layout is configured using MultiSplitLayout layout manager."
    +"<p>"
    +"The MultiSplitLayout layout manager recursively arranges its components in"
    +"row and column groups called Splits. Elements of the layout are"
    +"separated by gaps called Dividers. The overall layout is defined with a"
    +"simple tree model whose nodes are instances of MultiSplitLayout.Split,"
    +"MultiSplitLayout. Divider, and MultiSplitLayout.Leaf. Named Leaf nodes"
    +"represent the space allocated to a component that was added with a"
    +"constraint that matches the Leaf's name. Extra space is distributed among"
    +"row/column siblings according to their 0.0 to 1.0 weight. If no weights"
    +"are specified then the last sibling always gets all of the extra space,"
    +"or space reduction."
    +"<p>"
    +"Although MultiSplitLayout can be used with any Container, it's the default"
    +"layout manager for JXMultiSplitPane. JXMultiSplitPane supports"
    +"interactively dragging the Dividers, accessibility, and other features"
    +"associated with split panes."
    +"</body>"
    +"</html>";

}

// the text in a file (accidentally only, that it's the description of the multiplitpane)

<html>
    <head>
        <title>JXMultiSplitPane Demo</title>
    </head>
    <body>
      JXMultiSplitPane is a container that can be split into multiple resizeable
      areas. The layout is configured using MultiSplitLayout layout manager.
      <p>
      The MultiSplitLayout layout manager recursively arranges its components in
      row and column groups called "Splits". Elements of the layout are
      separated by gaps called "Dividers". The overall layout is defined with a
      simple tree model whose nodes are instances of MultiSplitLayout.Split,
      MultiSplitLayout. Divider, and MultiSplitLayout.Leaf. Named Leaf nodes
      represent the space allocated to a component that was added with a
      constraint that matches the Leaf's name. Extra space is distributed among
      row/column siblings according to their 0.0 to 1.0 weight. If no weights
      are specified then the last sibling always gets all of the extra space,
      or space reduction.
      <p>
      Although MultiSplitLayout can be used with any Container, it's the default
      layout manager for JXMultiSplitPane. JXMultiSplitPane supports
      interactively dragging the Dividers, accessibility, and other features
      associated with split panes.
    </body>
</html>
[/code]
[Message sent by forum member 'kleopatra' (fastegal@...)]

http://forums.java.net/jive/thread.jspa?messageID=368977

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@...
For additional commands, e-mail: jdnc-help@...


Re: Strange interference: JXMultiSplitPane and editorPane

by jdnc-interest :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I added:
[code]demoContainer.doLayout();
demoContainer.repaint();[/code]After the revalidate...which sort of works.  I guarantees that the scrolls are respected, but when calling doLayout manually JXMultiSplitPane does not seem to respect the bounds of its parent container.

Seems like there's a bug somewhere, I just haven't put my finger on it yet.

Karl
[Message sent by forum member 'kschaefe' (kschaefe@...)]

http://forums.java.net/jive/thread.jspa?messageID=369190

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@...
For additional commands, e-mail: jdnc-help@...


Re: Strange interference: JXMultiSplitPane and editorPane

by jdnc-interest :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

To close the story, with a basically happy ending :-)

>
> Seems like there's a bug somewhere, I just haven't
> put my finger on it yet.

thanks for trying :-) And yeah, agreed, I think there's a bug somewhere but stilll can't point to where exactly. Could make some progress with calling multisplit.layoutByWeight but only if the was added to the CENTER of the demoContainer. Base context needs it at LINESTART which results in everthing going nuts (the plain version as well) - there seems to be a problem with editor and BorderLayout ...

So I gave up entirely on BorderLayout and switched to FormLayout, good that can do that in the demos <g> The effected class in swingxset6 is LoadedXDemoPanel which extends JXTitledPanel. Nothing special to do if there is no description, simply set the demo as its contentContainer. FormLayout comes into play if we have a description:

[code]
    private void layoutWithDescription() {
        JComponent top = (JComponent) getUI().getTitleBar();
        removeAll();
        FormLayout formLayout = new FormLayout(
            "f:[100dlu, m]:g, f:d:g", // columns
            "f:d:n, f:d:g "); // rows
        PanelBuilder builder = new PanelBuilder(formLayout, this);
        CellConstraints cc = new CellConstraints();
        JScrollPane scrollPane = new JScrollPane(descriptionArea,
                JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        builder.add(scrollPane, cc.xywh(1, 2, 1, 1));
        builder.add(demoPanel, cc.xywh(2, 2, 1, 1));
        builder.add(top, cc.xywh(1, 1, 2, 1));
    }

[/code]

then we can tweak the layout a bit (overlaying the title) in doLayout, letting super do the heavy lifting:

[code]
        @Override
        public void doLayout() {
            super.doLayout();
            if (descriptionArea != null) {
                // manual tweaking of demo panel: displace slightly to overlap the
                // title
                // PENDING JW: displace so that it is below the title baseline
                Rectangle bounds = demoPanel.getBounds();
                int delta = getUI().getTitleBar().getHeight() / 2;
                bounds.y -= delta;
                bounds.height += delta /2;
                demoPanel.setBounds(bounds);
            }
        }

[/code]

with that, I don't even have to listen for text loading ready: magically, all comes out correctly.

One slight glitched: we have to call layoutWithDescription not only initially but in updateUI as well - reason being that the BasicTitlePaneUI enforces a BorderLayout and adds the titleBar NORTH. Technically, we could enhance by only enforcing the BorderLayout if of type UIResource, always add to top with constraint NORTH and expecting a custom manager to map to whatever makes sense. As I'm not sure if the current handling is overly limiting for normal use cases - after all, here it's stretched .. - won't go for it.

CU
Jeanette
[Message sent by forum member 'kleopatra' (fastegal@...)]

http://forums.java.net/jive/thread.jspa?messageID=370656

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@...
For additional commands, e-mail: jdnc-help@...