Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

word wrap in DefaultStyledDocument

Posted on 2003-11-12
7
Medium Priority
?
2,118 Views
Last Modified: 2010-08-05
Hi!
I'm using DefaultStyledDocument (new DefaultStyledDocument(new StyleContext());)
I want that the text will be word wrapped.
Can you tell me how to do it?
Thanks!
0
Comment
Question by:rzvika2
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
7 Comments
 
LVL 35

Expert Comment

by:TimYates
ID: 9730792
Assuming you're putting it in a JTextArea,

jTextArea.setWrapStyleWord( true ) ;

should do it...
0
 

Author Comment

by:rzvika2
ID: 9730825
I'm using JTextPane.
I want to insert strings with colors (that's why)
0
 
LVL 35

Expert Comment

by:TimYates
ID: 9730908
Errr....this does wordWrapping:

--------------------------------------------

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.text.* ;

public class WordWrap extends Frame
{
  BorderLayout borderLayout1 = new BorderLayout();
  JScrollPane scroll = new JScrollPane();
  JTextPane textPane = new JTextPane();
  public WordWrap()
  {
    try
    {
      jbInit();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
  }

  private void jbInit() throws Exception
  {
    this.setLayout(borderLayout1);
    textPane.setDocument( new DefaultStyledDocument( new StyleContext() ) );
    textPane.setText("This is a quick and dirty test to see if we can do word wrapping on a JTextPane");
    this.addWindowListener(new java.awt.event.WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        this_windowClosing(e);
      }
    });
    this.add(scroll, BorderLayout.CENTER);
    scroll.getViewport().add( textPane, null );
    scroll.setPreferredSize( new Dimension( 300, 300 ) );
  }

  void this_windowClosing(WindowEvent e)
  {
    System.exit( 0 ) ;
  }

  public static void main(String[] args)
  {
    WordWrap wordWrap = new WordWrap();
    wordWrap.pack() ;
    wordWrap.show();
  }
}
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:rzvika2
ID: 9730934
****.
This is the opposit that  I've wanted.
by default it is word wrapped, but I don't want it to be like this.
I'm so sorry, you will get the points.
Can you tell me how to make the word not wrapped?
Thanks!
0
 
LVL 35

Expert Comment

by:TimYates
ID: 9730979
Ahhhhh! ;-)

hehehehe

Yeah, extend JTextPane

JTextPane extends JEditorPane which implements Scrollable

So what you need to do, is override the part of the Scrollable interface that checks if the JTextPane should fix itself to the width of the ScrollPane...

Hope you see what I mean...anyway...here's the code ;-)

Tim

--------------------------

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.text.* ;
import java.util.* ;

public class WordWrap extends Frame
{
  class MyTextPane extends JTextPane
  {
    public boolean getScrollableTracksViewportWidth()
    {
      return false ;
    }
  }

  BorderLayout borderLayout1 = new BorderLayout();
  JScrollPane scroll = new JScrollPane();
  MyTextPane textPane = new MyTextPane();
  public WordWrap()
  {
    try
    {
      jbInit();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
  }

  private void jbInit() throws Exception
  {
    this.setLayout(borderLayout1);
    StyleContext sc = new StyleContext() ;
    DefaultStyledDocument dsd = new DefaultStyledDocument( sc ) ;
    textPane.setStyledDocument( dsd );
    Style s = sc.getStyle( "default" ) ;
    Enumeration e = s.getAttributeNames() ;
    while( e.hasMoreElements() )
    {
      System.out.println( e.nextElement() ) ;
    }
    textPane.setText("This is a quick and dirty test to see if we can do word wrapping on a JTextPane");
    this.addWindowListener(new java.awt.event.WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        this_windowClosing(e);
      }
    });
    this.add(scroll, BorderLayout.CENTER);
    scroll.getViewport().add( textPane, null );
    scroll.setPreferredSize( new Dimension( 300, 300 ) );
  }

  void this_windowClosing(WindowEvent e)
  {
    System.exit( 0 ) ;
  }

  public static void main(String[] args)
  {
    WordWrap wordWrap = new WordWrap();
    wordWrap.pack() ;
    wordWrap.show();
  }
}
0
 
LVL 35

Accepted Solution

by:
TimYates earned 400 total points
ID: 9730981
Whoops...


and without the debug ;-)

-----------------

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.text.* ;
import java.util.* ;

public class WordWrap extends Frame
{
  class MyTextPane extends JTextPane
  {
    public boolean getScrollableTracksViewportWidth()
    {
      return false ;
    }
  }

  BorderLayout borderLayout1 = new BorderLayout();
  JScrollPane scroll = new JScrollPane();
  MyTextPane textPane = new MyTextPane();
  public WordWrap()
  {
    try
    {
      jbInit();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
  }

  private void jbInit() throws Exception
  {
    this.setLayout(borderLayout1);
    textPane.setStyledDocument( new DefaultStyledDocument( new StyleContext() ) ) ;
    textPane.setText("This is a quick and dirty test to see if we can do word wrapping on a JTextPane");
    this.addWindowListener(new java.awt.event.WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        this_windowClosing(e);
      }
    });
    this.add(scroll, BorderLayout.CENTER);
    scroll.getViewport().add( textPane, null );
    scroll.setPreferredSize( new Dimension( 300, 300 ) );
  }

  void this_windowClosing(WindowEvent e)
  {
    System.exit( 0 ) ;
  }

  public static void main(String[] args)
  {
    WordWrap wordWrap = new WordWrap();
    wordWrap.pack() ;
    wordWrap.show();
  }
}
0
 

Expert Comment

by:anthonydavidson
ID: 9783671
Simply returning false in getScrollableTracksViewportWidth() did not work for me.  For cases where the JTextPane's preferred size is less than that of the JScrollPane's viewport, I would get only a partially filled viewport.

My getScrollableTracksViewportWidth() in my extension of JTextPane looks like this:

    public boolean getScrollableTracksViewportWidth()
    {
        if (getParent() instanceof JViewport)
        {    
            if (getParent().getWidth() > document.getLongestLineWidth())
                return true;
        }

        return false;
    }

In the above code, document is a reference to a class that extends DefaultStyledDocument and implements the method getLongestLineWidth().  My implementation of that method is below.  (It includes things that are not relevant to this issue, like the PropertyChangeListener and the modified flag.  My appologies for this.)


import java.awt.Component;
import java.awt.Font;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;

import javax.swing.JPanel;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;

import org.apache.log4j.Logger;

/**
 * This Document for the text editor's text area handles highlighting.
 * @see javax.swing.text.PlainDocument
 */
public class TextEditorDocument extends DefaultStyledDocument implements LineNumberedDocument
{
    private static final Logger logger = Logger.getLogger(TextEditorDocument.class);
    public static final String FONT_NAME = "Monospaced";
    public static final int FONT_SIZE = 12;
    public static final String MODIFIED_PROPNAME = "modified";
    public static final char NEW_LINE_CHAR = '\n';
    public static final String NEW_LINE_STRING = "\n";
    private static final Component metricsComponent = new JPanel();
    private Style regularStyle = null;
    private boolean modified = false;
    /** An array of Integer objects that correspond to the offset for the start of each line */
    protected ArrayList offsets = new ArrayList();
    private PropertyChangeSupport changeSupport = null;

    public TextEditorDocument()
    {
        Style _default = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
        StyleConstants.setFontFamily(_default, FONT_NAME);
        StyleConstants.setFontSize(_default, FONT_SIZE);
        regularStyle = this.addStyle("regular", _default);

        this.setLogicalStyle(0, regularStyle);
    }

    /**
     * Updates the offsets of each line affected and then updates the syntax
     * highlighting of those lines
     * @see javax.swing.text.Document#insertString(int, java.lang.String, javax.swing.text.AttributeSet)
     */
    public void insertString(int offs, String str, AttributeSet a) throws BadLocationException
    {
        if (str == null || str.length() == 0)
            return;
        int numLines = getNumLines();
        super.insertString(offs, str, a);
        setModified(true);

        int startLineIndex = getLineIndex(offs);
        int endLineIndex = updateOffsetsAfterInsert(offs, str);
        if (numLines != getNumLines())
            firePropertyChange(NUM_LINES_PROPNAME, new Integer(numLines), new Integer(getNumLines()));
    }

    /**
     * @see javax.swing.text.Document#remove(int, int)
     */
    public void remove(int offs, int len) throws BadLocationException
    {
        if (len <= 0)
            return;
        int numLines = getNumLines();
        String removedText = this.getText(offs, len);
        super.remove(offs, len);
        setModified(true);
        updateOffsetsAfterRemove(offs, removedText);
        if (numLines != getNumLines())
            firePropertyChange(NUM_LINES_PROPNAME, new Integer(numLines), new Integer(getNumLines()));
    }

    /**
     * Returns the index of the line in <code>lines</code> that corresponds
     * to the specified offset in the document.
     */
    protected int getLineIndex(int offset)
    {
        if (offsets.size() <= 1)
            return 0;

        int lineIndex = 0;
        for (int i = 0; i < offsets.size(); i++)
        {
            if (i == offsets.size()-1)
                return i;
            int nextLineOffset = ((Integer)offsets.get(i+1)).intValue();
            if (offset < nextLineOffset)
                return i;
        }
        throw new RuntimeException("shouldn't get here in getLineIndex(" + offset + ")");
    }

    /**
     * Gets the text of the line at the specified index
     * @param lineIndex the index of the line to return
     */
    public String getLine(int lineIndex)
    {
        if (lineIndex < 0 || lineIndex >= offsets.size())
            throw new IndexOutOfBoundsException("Index: " + lineIndex + ", Size: " + offsets.size());
        int lineOffset = ((Integer)offsets.get(lineIndex)).intValue();
        int lineLength = 0;
        if (offsets.size() == lineIndex + 1)
            lineLength = this.getLength() - lineOffset;
        else
            lineLength = ((Integer)offsets.get(lineIndex + 1)).intValue() - lineOffset;
        try
        {
            return this.getText(lineOffset, lineLength);
        }
        catch (BadLocationException e)
        {
            logger.error("lineOffset=" + lineOffset + " lineLength=" + lineLength +
                " offsets.size()=" + offsets.size() + " lineIndex=" + lineIndex, e);
            // since this method is only used internally, any error here is a
            // coding error
            throw new RuntimeException(e);
        }
    }

    /**
     * Returns the line number that corresponds to the specified offset.  This
     * is the same as the line index + 1.
     * @param offset the location in the document
     * @see #getLineIndex(int)
     */
    public int getLineNumber(int offset)
    {
        return 1 + getLineIndex(offset);
    }

    /**
     * Returns the character position relative to the line that corresponds
     * to the specified offset.
     * @param offset the location in the document
     */
    public int getCharacterPosition(int offset)
    {
        int lineIndex = getLineIndex(offset);
        int lineOffset = ((Integer)offsets.get(lineIndex)).intValue();
        return 1 + offset - lineOffset;
    }

    /**
     * Returns the number of lines of text in this document.
     */
    public int getNumLines()
    {
        return offsets.size();
    }

    /**
     * Returns the number of newline characters ('\n') that are found in the
     * specified string.
     */
    protected int countNewLines(String text)
    {
        int count = 0;
        for (int i = 0; i < text.length(); i++)
        {
            if (text.charAt(i) == NEW_LINE_CHAR)
                count++;
        }
        return count;
    }

    /**
     * Updates <code>offsets</code> after a remove.
     * @param offset the offset where the text was removed
     * @param insertedText the removed text
     */
    private void updateOffsetsAfterRemove(int offset, String removedText)
    {
        int interruptedLineIndex = getLineIndex(offset);

        // remove offsets for newlines that were deleted
        for (int i = countNewLines(removedText); i > 0; i--)
        {
            offsets.remove(interruptedLineIndex + 1);
        }

        for (int i = interruptedLineIndex + 1; i < offsets.size(); i++)
        {
            int curOffset = ((Integer)offsets.get(i)).intValue();
            offsets.set(i, new Integer(curOffset - removedText.length()));
        }
    }

    /**
     * Updates <code>offsets</code> after an insert.
     * @param offset the offset where the text was inserted
     * @param insertedText the inserted text
     * @return the index of the last line that was modified by the insert
     */
    private int updateOffsetsAfterInsert(int offset, String insertedText)
    {
        if (offsets.size() == 0)
            offsets.add(new Integer(0));

        int interruptedLineIndex = getLineIndex(offset);
        int startingOffset = ((Integer)offsets.get(interruptedLineIndex)).intValue();

        // increase the value of all the following offsets by the length
        // of the inserted text
        for (int i = interruptedLineIndex + 1; i < offsets.size(); i++)
        {
            int curOffset = ((Integer)offsets.get(i)).intValue();
            offsets.set(i, new Integer(curOffset + insertedText.length()));
        }

        // add new offsets for the inserted text
        int lineIndex = interruptedLineIndex + 1;
        for (int indexOfNewLine = -1; indexOfNewLine + 1 < insertedText.length(); lineIndex++)
        {
            indexOfNewLine = insertedText.indexOf(NEW_LINE_CHAR, indexOfNewLine+1);
            if (indexOfNewLine == -1)
                break;
            offsets.add(lineIndex, new Integer(offset + indexOfNewLine + 1));
        }
        return lineIndex - 1;
    }

    /**
     * Returns true if this document has been modified.
     * @return the <code>modified</code> flag
     */
    public boolean isModified()
    {
        return modified;
    }

    /**
     * Sets the <code>modified</code> flag to the specified value.
     */
    void setModified(boolean modified)
    {
        if (this.modified == modified)
            return;
        this.modified = modified;
        firePropertyChange(TextEditorDocument.MODIFIED_PROPNAME, new Boolean(!modified), new Boolean(modified));
    }
    /**
     * Support for reporting bound property changes for Object properties.
     * This method can be called when a bound property has changed and it will
     * send the appropriate PropertyChangeEvent to any registered
     * PropertyChangeListeners.
     *
     * @param propertyName the property whose value has changed
     * @param oldValue the property's previous value
     * @param newValue the property's new value
     */
    protected void firePropertyChange(String propertyName, Object oldValue, Object newValue)
    {
        if (changeSupport == null)
            return;
        changeSupport.firePropertyChange(propertyName, oldValue, newValue);
    }

    /**
     * Adds a PropertyChangeListener to the listener list. The listener is
     * registered for all bound properties of this class.
     * If listener is null, no exception is thrown and no action is performed.
     * @param propertyName  the name of the property to listen on
     * @param listener  the PropertyChangeListener to be added
     * @see #removePropertyChangeListener
     */
    public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
    {
        if (listener == null)
            return;
        if (changeSupport == null)
            changeSupport = new PropertyChangeSupport(this);
        changeSupport.addPropertyChangeListener(propertyName, listener);
    }
 
    /**
     * Removes a PropertyChangeListener from the listener list. This method
     * should be used to remove PropertyChangeListeners that were registered
     * for all bound properties of this class.
     * <p>
     * If listener is null, no exception is thrown and no action is performed.
     * @param propertyName  the name of the property to listen on
     * @param listener the PropertyChangeListener to be removed
     * @see #addPropertyChangeListener
     */
    public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)
    {
        if (listener == null || changeSupport == null)
            return;
        changeSupport.removePropertyChangeListener(propertyName, listener);
    }

    /**
     * @see com.realvue.tools.texteditor.LineNumberedDocument#getNumCharsInLongestLine()
     */
    public int getLongestLineWidth()
    {
        int max = 0;
        Font font = StyleContext.getDefaultStyleContext().getFont(regularStyle);
        int numLines = getNumLines();
        for (int i = 0; i < numLines; i++)
        {
            char[] line = getLine(i).toCharArray();
            int lineWidth = metricsComponent.getFontMetrics(font).charsWidth(line, 0, line.length);
            if (lineWidth > max)
                max = lineWidth;
        }
        return max;

    }

}

The implementation of getLongestLineWidth() above will not be sufficient for everyone.  I only use a single (monospaced) font of a single size.  If this is not the case for you, you will need to sum up the character width of each character on the line using the font metrics of that character's font.

I hope this helps... somebody... somewhere.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is the second of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers the basic installation and configuration of the test automation tools used by…
In this post we will learn how to make Android Gesture Tutorial and give different functionality whenever a user Touch or Scroll android screen.
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…
Video by: Michael
Viewers learn about how to reduce the potential repetitiveness of coding in main by developing methods to perform specific tasks for their program. Additionally, objects are introduced for the purpose of learning how to call methods in Java. Define …
Suggested Courses

604 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question