JTextPane Extended Paragraph Example
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Shape;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Element;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.ParagraphView;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
public class ExtendedParagraphExample {
public static void createDocumentStyles(StyleContext sc) {
Style defaultStyle = sc.getStyle(StyleContext.DEFAULT_STYLE);
// Create and add the main document style
Style mainStyle = sc.addStyle(mainStyleName, defaultStyle);
StyleConstants.setLeftIndent(mainStyle, 16);
StyleConstants.setRightIndent(mainStyle, 16);
StyleConstants.setFirstLineIndent(mainStyle, 16);
StyleConstants.setFontFamily(mainStyle, "serif");
StyleConstants.setFontSize(mainStyle, 12);
// Create and add the constant width style
Style cwStyle = sc.addStyle(charStyleName, null);
StyleConstants.setFontFamily(cwStyle, "monospaced");
StyleConstants.setForeground(cwStyle, Color.white);
// Create and add the heading style
Style heading2Style = sc.addStyle(heading2StyleName, null);
StyleConstants.setForeground(heading2Style, Color.red);
StyleConstants.setFontSize(heading2Style, 16);
StyleConstants.setFontFamily(heading2Style, "serif");
StyleConstants.setBold(heading2Style, true);
StyleConstants.setLeftIndent(heading2Style, 8);
StyleConstants.setFirstLineIndent(heading2Style, 0);
// Create and add the extended para styles
Style paraStyle = sc.addStyle(paraStyleName, null);
Color bgColor = Color.gray;
ExtendedStyleConstants.setParagraphBackground(paraStyle, bgColor);
ExtendedStyleConstants.setParagraphBorder(paraStyle, BorderFactory
.createCompoundBorder(BorderFactory.createEmptyBorder(2, 2, 2,
2), BorderFactory.createCompoundBorder(BorderFactory
.createEtchedBorder(bgColor.brighter(), bgColor
.darker()), BorderFactory.createEmptyBorder(4,
4, 4, 4))));
}
public static void addText(JTextPane pane, StyleContext sc,
Style logicalStyle, Paragraph[] content) {
// The outer loop adds paragraphs, while the
// inner loop adds character runs.
int paragraphs = content.length;
for (int i = 0; i < paragraphs; i++) {
Run[] runs = content[i].content;
for (int j = 0; j < runs.length; j++) {
pane.setCharacterAttributes(
runs[j].styleName == null ? SimpleAttributeSet.EMPTY
: sc.getStyle(runs[j].styleName), true);
pane.replaceSelection(runs[j].content);
}
// At the end of the paragraph, add the logical style and
// any overriding paragraph style and then terminate the
// paragraph with a newline.
pane.setParagraphAttributes(SimpleAttributeSet.EMPTY, true);
if (logicalStyle != null) {
pane.setLogicalStyle(logicalStyle);
}
if (content[i].styleName != null) {
pane.setParagraphAttributes(sc.getStyle(content[i].styleName),
false);
}
if (i != paragraphs - 1) {
pane.replaceSelection("\n");
}
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
JFrame f = new JFrame("Extended Paragraph Example");
// Create the StyleContext, the document and the pane
final StyleContext sc = new StyleContext();
final DefaultStyledDocument doc = new DefaultStyledDocument(sc);
final JTextPane pane = new JTextPane(doc);
pane.setEditorKit(new ExtendedStyledEditorKit());
try {
// Add the text and apply the styles
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
// Build the styles
createDocumentStyles(sc);
// Add the text
addText(pane, sc, sc.getStyle(mainStyleName), content);
}
});
} catch (Exception e) {
System.out.println("Exception when constructing document: " + e);
System.exit(1);
}
f.getContentPane().add(new JScrollPane(pane));
f.setSize(400, 300);
f.setVisible(true);
}
// Style names
public static final String mainStyleName = "MainStyle";
public static final String heading2StyleName = "Heading2";
public static final String charStyleName = "ConstantWidth";
public static final String paraStyleName = "ExtendedPara";
// Inner classes used to define paragraph structure
public static class Run {
public Run(String styleName, String content) {
this.styleName = styleName;
this.content = content;
}
public String styleName;
public String content;
}
public static class Paragraph {
public Paragraph(String styleName, Run[] content) {
this.styleName = styleName;
this.content = content;
}
public String styleName;
public Run[] content;
}
public static final Paragraph[] content = new Paragraph[] {
new Paragraph(heading2StyleName, new Run[] { new Run(null,
"Attributes, Styles and Style Contexts") }),
new Paragraph(
paraStyleName,
new Run[] {
new Run(null, "The simple "),
new Run(charStyleName, "PlainDocument"),
new Run(
null,
" class that you saw in the previous "
+ "chapter is only capable of holding text. "
+ "The more complex text components use a more "
+ "sophisticated model that implements the "),
new Run(charStyleName, "StyledDocument"),
new Run(null, " interface. "),
new Run(charStyleName, "StyledDocument"),
new Run(null, " is a sub-interface of "),
new Run(charStyleName, "Document"),
new Run(
null,
" that contains methods for manipulating attributes "
+ "that control the way in which the text in the "
+ "document is displayed. The Swing text package "
+ "contains a concrete implementation of "),
new Run(charStyleName, "StyledDocument"),
new Run(null, " called "),
new Run(charStyleName, "DefaultStyledDocument"),
new Run(null,
" that is used as the default model for "),
new Run(charStyleName, "JTextPane"),
new Run(
null,
" and is also the base class from which "
+ "more specific models, such as the "),
new Run(charStyleName, "HTMLDocument"),
new Run(
null,
" class that handles input in HTML format, can be "
+ "created. In order to make use of "),
new Run(charStyleName, "DefaultStyledDocument"),
new Run(null, " and "),
new Run(charStyleName, "JTextPane"),
new Run(null,
" you need to understand how Swing represents "
+ "and uses attributes.") }) };
}
class ExtendedStyleConstants {
public ExtendedStyleConstants(String name) {
this.name = name;
}
public String toString() {
return name;
}
/**
* The border to be used for a paragraph. Type is javax.swing.border.Border
*/
public static final Object ParagraphBorder = ExtendedParagraphConstants.ParagraphBorder;
/**
* The background to be used for a paragraph. Type is java.awt.Color
*/
public static final Object ParagraphBackground = ExtendedParagraphConstants.ParagraphBackground;
/* Adds the border attribute */
public static void setParagraphBorder(MutableAttributeSet a, Border b) {
a.addAttribute(ParagraphBorder, b);
}
/* Gets the border attribute */
public static Border getParagraphBorder(AttributeSet a) {
return (Border) a.getAttribute(ParagraphBorder);
}
/* Adds the paragraph background attribute */
public static void setParagraphBackground(MutableAttributeSet a, Color c) {
a.addAttribute(ParagraphBackground, c);
}
/* Gets the paragraph background attribute */
public static Color getParagraphBackground(AttributeSet a) {
return (Color) a.getAttribute(ParagraphBackground);
}
/* A typesafe collection of extended paragraph attributes */
public static class ExtendedParagraphConstants extends
ExtendedStyleConstants implements AttributeSet.ParagraphAttribute {
/**
* The paragraph border attribute.
*/
public static final Object ParagraphBorder = new ExtendedParagraphConstants(
"ParagraphBorder");
/**
* The paragraph background attribute.
*/
public static final Object ParagraphBackground = new ExtendedParagraphConstants(
"ParagraphBackground");
private ExtendedParagraphConstants(String name) {
super(name);
}
}
protected String name; // Name of an attribute
}
class ExtendedStyledEditorKit extends StyledEditorKit {
public Object clone() {
return new ExtendedStyledEditorKit();
}
public ViewFactory getViewFactory() {
return defaultFactory;
}
/* The extended view factory */
static class ExtendedStyledViewFactory implements ViewFactory {
public View create(Element elem) {
String elementName = elem.getName();
if (elementName != null) {
if (elementName.equals(AbstractDocument.ParagraphElementName)) {
return new ExtendedParagraphView(elem);
}
}
// Delegate others to StyledEditorKit
return styledEditorKitFactory.create(elem);
}
}
private static final ViewFactory styledEditorKitFactory = (new StyledEditorKit())
.getViewFactory();
private static final ViewFactory defaultFactory = new ExtendedStyledViewFactory();
}
class ExtendedParagraphView extends ParagraphView {
public ExtendedParagraphView(Element elem) {
super(elem);
}
// Override ParagraphView methods
protected void setPropertiesFromAttributes() {
AttributeSet attr = getAttributes();
if (attr != null) {
super.setPropertiesFromAttributes();
paraInsets = new Insets(getTopInset(), getLeftInset(),
getBottomInset(), getRightInset());
border = ExtendedStyleConstants.getParagraphBorder(attr);
bgColor = ExtendedStyleConstants.getParagraphBackground(attr);
if (bgColor != null && border == null) {
// Provide a small margin if the background
// is being filled and there is no border
border = smallBorder;
}
if (border != null) {
Insets borderInsets = border.getBorderInsets(getContainer());
setInsets((short) (paraInsets.top + borderInsets.top),
(short) (paraInsets.left + borderInsets.left),
(short) (paraInsets.bottom + borderInsets.bottom),
(short) (paraInsets.right + borderInsets.right));
}
}
}
public void paint(Graphics g, Shape a) {
Container comp = getContainer();
Rectangle alloc = new Rectangle(a.getBounds());
alloc.x += paraInsets.left;
alloc.y += paraInsets.top;
alloc.width -= paraInsets.left + paraInsets.right;
alloc.height -= paraInsets.top + paraInsets.bottom;
if (bgColor != null) {
Color origColor = g.getColor();
g.setColor(bgColor);
g.fillRect(alloc.x, alloc.y, alloc.width, alloc.height);
g.setColor(origColor);
}
if (border != null) {
// Paint the border
border.paintBorder(comp, g, alloc.x, alloc.y, alloc.width,
alloc.height);
}
super.paint(g, a); // Note: pass ORIGINAL allocation
}
// Attribute cache
protected Color bgColor; // Background color, or null for transparent.
protected Border border; // Border, or null for no border
protected Insets paraInsets; // Original paragraph insets
protected static final Border smallBorder = BorderFactory
.createEmptyBorder(2, 2, 2, 2);
}
Related examples in the same category