Articles Projects Tips Downloads Contacts About

Pagination in the JEditorPane/JTextPane. Part IV (Page Breaks.)
By Stanislav Lapitsky

An additional feature of paginated editor often necessary for end user is page breaks. They allow user to move non breakable content on next page. The article explains how to add them in previously written paginated editor.

Page Breaks definition.

Technically page break is a usual paragraph without content but with special attribute. When the attribute is set layout must break current page and move all the content after break paragraph to the next page. So we define an additional attribute
public static String PAGE_BREAK_ATTR_NAME="page_break_attribute";
And insert a new paragraph with the attribute set to true.

    /**
     * inserts page break element in current caret location
     */
    public void insertPageBreak(final JEditorPane editor) {
        int caretPos=editor.getCaretPosition();
        final SimpleAttributeSet breakAttrs=new SimpleAttributeSet();
        breakAttrs.addAttribute(PAGE_BREAK_ATTR_NAME, Boolean.TRUE);
        DefaultStyledDocument doc=(DefaultStyledDocument)editor.getDocument();
        try {
            isPageBreakInsertion=true;
            char ch=doc.getText(caretPos,1).charAt(0);
            if (ch!='\n') {
                doc.insertString(caretPos, "\n", breakAttrs);
                caretPos++;
            }
            else {
                Element par=doc.getParagraphElement(caretPos);
                caretPos=par.getEndOffset()-1;
            }
            final int pos=caretPos;
            ( (StyledDocument) editor.getDocument()).setCharacterAttributes(pos, 1, breakAttrs, false);
            isPageBreakInsertion=false;
        }
        catch (BadLocationException ex) {
            //do nothing
        }
    }

inserted paragraph’s element (it’s only one) has the attribute specified. But we should keep the attribute in this paragraph and prevent moving the attribute. During usual typing all text attributes is moved to newly typed content we prevent this by removing PAGE_BREAK_ATTR_NAME from inputAttributes of our editor kit.

        editor.addCaretListener(new CaretListener() {
            public void caretUpdate(CaretEvent e) {
                if (!isPageBreakInsertion ) {
                    ( (StyledEditorKit) editor.getEditorKit()).getInputAttributes().removeAttribute(PAGE_BREAK_ATTR_NAME);
                }
            }
        });

Thus the first step – model definitions is done. To complete feature we have to modify our layout.

Pagination layout with page breaks.

The layoutMajorAxis method goes through all views measuring them. For each child view (paragraph) we should check whether the view is page break. A special method for this is:

        protected boolean isPageBreak(View v) {
            AttributeSet attrs=v.getElement().getElement(v.getElement().getElementCount()-1).getAttributes();
            Boolean pb=(Boolean)attrs.getAttribute(PAGE_BREAK_ATTR_NAME);
            if (pb==null) {
                return false;
            }
            else {
                return pb.booleanValue();
            }
        }

We obtain attributes of last child element of paragraph. The we check whether the attribute is defined. If yes the paragraph is page break.
In the mail layout loop we check whether current view I page break and move content on next page if it is. Like this.

                View v = getView(i);
                if (isPageBreak(v)) {
                    offsets[i] = pageNumber * pageHeight+headerHeight;
                    pageNumber++;
                }

Then continue usual layout procedure to layout the rest of content.

The insertPageBreak method can be called by usual menu or button.

Appendix

Here is the full source code of the page breaks example.

Back to Table of Content