Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8180276

JTextPane inserts extra CR before CR-LF in returned text

XMLWordPrintable

      FULL PRODUCT VERSION :
      java version "1.8.0_111"
      Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
      Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [Version 10.0.10586]

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      JDK 1.8.111

      A DESCRIPTION OF THE PROBLEM :
      javax.swing.JTextPane has a method getText(), to return the text of its document. It uses StringWriter.

      If we extend this class and define an utility method to append some text by:

              public void append(String s) {
                  try {
                     Document doc = this.getDocument();
                     doc.insertString(doc.getLength(), s, null);
                  } catch(BadLocationException e) {
                      System.err.println(e);
                  }
              }

      And when adding text, we may use:

              pane.setText(pane.getText() + newText);

      or:

              pane.append(newText());

      alone and no problem. But if we use append() first and then setText(pane.getText + newText), before every \r\n another \r is added, and in output, extra blank line are added.

      But if we override the getText() method with:

              @Override
              public String getText() {
                  String string = "";
                  try {
                      string = this.getDocument().getText(0, this.getDocument().getLength());
                  } catch (BadLocationException e) {
                      e.printStackTrace();
                  }
                  return string;
              }

      The problem disappears.

      I guess it's because underneath getText() uses StringWriter.write() method, and once I have touched the attached document of a JTextPane, StringWriter behaves differently. But anyway, any side effect should be evaluated.



      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run my test case below to see the unexpected result, and uncomment the getText() methods to see the expected result.



      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Three panels should have same content.
      ACTUAL -
      The first panel has extra line breaks.

      If the overwritten getText() method is uncommented, the problem dismisses.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package com.WindThunderStudio.JTextpaneLineSpacing;

      import java.awt.BorderLayout;
      import java.io.File;

      import javax.swing.JFrame;
      import javax.swing.JTextPane;
      import javax.swing.SwingUtilities;
      import javax.swing.border.EtchedBorder;
      import javax.swing.text.BadLocationException;
      import javax.swing.text.Document;
      import javax.swing.text.MutableAttributeSet;
      import javax.swing.text.SimpleAttributeSet;
      import javax.swing.text.StyleConstants;

      import net.miginfocom.swing.MigLayout;

      public class Test1_ChangeStyleAndAppend extends JFrame {
          public class MyJTextPane extends JTextPane {
              /**
               * Append some text to this pane.
               * @param s
               */
              public void append(String s) {
                  try {
                     Document doc = this.getDocument();
                     doc.insertString(doc.getLength(), s, null);
                  } catch(BadLocationException e) {
                      System.err.println(e);
                  }
              }
              
              /**
               * Append some text and change line.
               * @param s
               */
              public void appendLine(String s) {
                  try {
                      Document doc = this.getDocument();
                      doc.insertString(doc.getLength(), s + System.lineSeparator(), null);
                  } catch(BadLocationException e) {
                      System.err.println(e);
                  }
              }
              
      // @Override
      // public String getText() {
      // String string = "";
      // try {
      // string = this.getDocument().getText(0, this.getDocument().getLength());
      // } catch (BadLocationException e) {
      // e.printStackTrace();
      // }
      // return string;
      // }
          }
          public Test1_ChangeStyleAndAppend() {
              begin();
          }

          private void begin() {
              setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              setLayout(new BorderLayout());
              MyJTextPane pane0 = new MyJTextPane();
              pane0.appendLine("MyJTextPane using append() and then calling setText()");
              pane0.appendLine("Second line. ");
              pane0.appendLine("Third line");
              pane0.setText(pane0.getText() + "At last" + System.lineSeparator());
              pane0.setBorder(new EtchedBorder(EtchedBorder.RAISED));
              add(pane0, BorderLayout.NORTH);
              
              MyJTextPane pane = new MyJTextPane();
      // changeLineSpacing(pane, 1.5f, false);
              pane.appendLine("MyJTextPane calling appendLine()");
              pane.appendLine("Second line. ");
              pane.appendLine("Third line");
              pane.appendLine("At last");
              pane.setBorder(new EtchedBorder(EtchedBorder.RAISED));
              add(pane, BorderLayout.CENTER);
              
              
              JTextPane pane2 = new JTextPane();
              pane2.setText("Normal JTextPane calling setText()");
              pane2.setText(pane2.getText() + System.lineSeparator() + "Second line. ");
              pane2.setText(pane2.getText() + System.lineSeparator() + "Third line");
              pane2.setText(pane2.getText() + System.lineSeparator() + "At last");
              pane2.setBorder(new EtchedBorder(EtchedBorder.RAISED));
              add(pane2, BorderLayout.SOUTH);
              
              pack();
              setVisible(true);
          }
          
          public static void main(String[] args) {
              SwingUtilities.invokeLater(new Runnable() {

                  @Override
                  public void run() {
                      Test1_ChangeStyleAndAppend frame = new Test1_ChangeStyleAndAppend();

                  }

              });
          }
      }


      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      1. Always stick to append() as I suggest, or setText(pane.getText() + newText()). Don't mix them.

      2. Override the getText() method in JTextPane by extending it, like I do in test case.

            tr Tejesh R
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: