0

I am currently writing a program that accepts styled text in a JTextPane and also displays the same styled text in a non-editable JTextPane. The problem is that I actually want to parse the documents between inputting and displaying. Basically I want to be able to split a DefaultStyledDocument into two documents while maintaining formatting. How can I do this?

SSCE illustrating point:

import java.awt.Color;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;


public class SSCCE extends javax.swing.JFrame {


    public SSCCE() {
        initComponents();
        try {
        DefaultStyledDocument doc = new DefaultStyledDocument();
        SimpleAttributeSet attr = new SimpleAttributeSet();
        StyleConstants.setBold(attr, true);
        doc.insertString(0, "This is bold.\n\n", attr);
        StyleConstants.setItalic(attr, true);
        doc.insertString(doc.getLength() - 1, "This is bold and italicized.\n", attr);
        doc.insertString(doc.getLength() - 1, "--\n", null); //This is a delimeter, for splitting the doucment
        StyleConstants.setBold(attr, false);
        StyleConstants.setForeground(attr, Color.red);
        doc.insertString(doc.getLength() - 1, "This is italicized and red.\n", attr);
        StyleConstants.setBold(attr, true);
        StyleConstants.setItalic(attr, false);
        doc.insertString(doc.getLength() -1 , "This is bold and red.\n", attr);
        txpInput.setDocument(doc); //txpInput is a JTextPane
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @SuppressWarnings("unchecked")                      
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        jPanel1 = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        txpInput = new javax.swing.JTextPane();
        jScrollPane3 = new javax.swing.JScrollPane();
        txpOutput1 = new javax.swing.JTextPane();
        jLabel1 = new javax.swing.JLabel();
        btnOutput = new javax.swing.JButton();
        jScrollPane4 = new javax.swing.JScrollPane();
        txpOutput2 = new javax.swing.JTextPane();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jScrollPane2.setViewportView(txpInput);

        txpOutput1.setEditable(false);
        jScrollPane3.setViewportView(txpOutput1);

        jLabel1.setText("Output:");

        btnOutput.setText("Output");
        btnOutput.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnOutputActionPerformed(evt);
            }
        });

        txpOutput2.setEditable(false);
        jScrollPane4.setViewportView(txpOutput2);

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane3, javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jScrollPane2)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(btnOutput, javax.swing.GroupLayout.PREFERRED_SIZE, 174, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(0, 462, Short.MAX_VALUE))
                    .addComponent(jScrollPane4))
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 105, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(btnOutput)
                .addGap(9, 9, 9)
                .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 135, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane4, javax.swing.GroupLayout.PREFERRED_SIZE, 135, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(79, Short.MAX_VALUE))
        );

        jScrollPane1.setViewportView(jPanel1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1)
        );

        pack();
    }                        

    private void btnOutputActionPerformed(java.awt.event.ActionEvent evt) {                                          
        //Comment out the body of this method to get code to run
        //This needs to parse the text and output it to the two output JTextPanes
        DefaultStyledDocument inputDoc = (DefaultStyledDocument) txpInput.getDocument();
        DefaultStyledDocument[] output = inputDoc.split("--"); //Invalid, is there an equivalent
        txpOutput1.setDocument(ouput[0]);
        txpOutput2.setDocument(ouput[1]);
        this.validate();
        this.repaint();
    }                                         

    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(SSCCE.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(SSCCE.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(SSCCE.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(SSCCE.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }    
        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new SSCCE().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JButton btnOutput;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JTextPane txpInput;
    private javax.swing.JTextPane txpOutput1;
    private javax.swing.JTextPane txpOutput2;
    // End of variables declaration                   
}

Note: I use the Netbeans GUI builder, hence the long generated code.

Basically, in the example I input some formatted text to the input JTextPane. I want to then be able to split that formatted text into the two output panes, without losing formatting. In the SCCE, when the user presses the button "Output" then the data should copy, being split by the -- line. In the example I used a non-existant split() method, but I think it gets the point across.

This is the expected input (for this particular example): enter image description here

And this is the expected output: enter image description here

I originally thought this question had a possible answer. But I tried it and found it doesn't work. So finally, how can I split a styled document while maintaining the styling.

Community
  • 1
  • 1
DonyorM
  • 1,760
  • 1
  • 20
  • 34

1 Answers1

0

Create 2 copies of the StyledDocument from the same content source.

Find the document separator.

In the first document remove all content before the separator.

In the second document remove all content after the separator.

UPDATE: You can use the code for merging documents but have 2 destination documents and redirect inserts of the source document to desired instance according to your filter rules.

StanislavL
  • 56,971
  • 9
  • 68
  • 98
  • How do I get two documents? I'm getting the document from a JTextPane. It's only going to pass me a reference to _one_ document. – DonyorM Dec 10 '14 at 04:45
  • You can just create it - new EditorKitDependentDocument or textPane.getEditorKit().createDefaultDocument() – StanislavL Dec 10 '14 at 05:33