Mega Code Archive

 
Categories / Java / Swing JFC
 

TextPane

/* Java Swing, 2nd Edition By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole ISBN: 0-596-00408-7 Publisher: O'Reilly  */ // LiveParenMatcher.java //Like ParenMatcher but continuously colors as the user edits the document. import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.Element; import javax.swing.text.ElementIterator; import javax.swing.text.Segment; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; import javax.swing.text.StyledDocument; public class LiveParenMatcher extends ParenMatcher implements DocumentListener {   public LiveParenMatcher() {     super();     getDocument().addDocumentListener(this);   }   public void changedUpdate(DocumentEvent de) {     // no insertion or deletion, so do nothing   }   public void insertUpdate(DocumentEvent de) {     SwingUtilities.invokeLater(this); // will call run()   }   public void removeUpdate(DocumentEvent de) {     SwingUtilities.invokeLater(this); // will call run()   }   public static void main(String[] args) {     JFrame frame = new JFrame("LiveParenMatcher");     frame.setContentPane(new JScrollPane(new LiveParenMatcher()));     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     frame.setSize(300, 200);     frame.setVisible(true);   }   // ---- finished example from "The DocumentListener Interface" ----   // ---- begin example from "The DocumentEvent Interface" ----   //      (method renamed to insertUpdate_2)   public void insertUpdate_2(DocumentEvent de) {     Document doc = de.getDocument();     int offset = de.getOffset();     int length = de.getLength();     String inserted = "";     try {       inserted = doc.getText(offset, length);     } catch (BadLocationException ble) {     }     for (int j = 0; j < inserted.length(); j += 1) {       char ch = inserted.charAt(j);       if (ch == '(' || ch == '[' || ch == '{' || ch == ')' || ch == ']'           || ch == '}') {         SwingUtilities.invokeLater(this); // will call run()         return; // no need to check further       }     }   }   // ---- begin example from "The Segment Class" ----   //      (method renamed to insertUpdate_3)   public void insertUpdate_3(DocumentEvent de) {     Document doc = de.getDocument();     int offset = de.getOffset();     int length = de.getLength();     Segment seg = new Segment();     try {       doc.getText(offset, length, seg); // text placed in Segment     } catch (BadLocationException ble) {     }     // iterate through the Segment     for (char ch = seg.first(); ch != seg.DONE; ch = seg.next())       if (ch == '(' || ch == '[' || ch == '{' || ch == ')' || ch == ']'           || ch == '}') {         SwingUtilities.invokeLater(this); // will call run()         return; // no need to check further       }   }   // ---- begin example from "The ElementIterator Class" ----   //      (method renamed to removeUpdate_2)   public void removeUpdate_2(DocumentEvent de) {     // print some debugging information before matching the parens     ElementIterator iter = new ElementIterator(de.getDocument());     for (Element elem = iter.first(); elem != null; elem = iter.next()) {       DocumentEvent.ElementChange change = de.getChange(elem);       if (change != null) { // null means there was no change in elem         System.out.println("Element " + elem.getName() + " (depth "             + iter.depth() + ") changed its children: "             + change.getChildrenRemoved().length             + " children removed, "             + change.getChildrenAdded().length             + " children added.\n");       }     }     SwingUtilities.invokeLater(this); // will call run()   } } class ParenMatcher extends JTextPane implements Runnable {   public static Color[] matchColor = { Color.blue, Color.magenta, Color.green };   public static Color badColor = Color.red;   private AttributeSet[] matchAttrSet;   private AttributeSet badAttrSet;   public ParenMatcher() {     // create an array of AttributeSets from the array of Colors     StyleContext sc = StyleContext.getDefaultStyleContext();     badAttrSet = sc.addAttribute(SimpleAttributeSet.EMPTY,         StyleConstants.Foreground, badColor);     matchAttrSet = new AttributeSet[matchColor.length];     for (int j = 0; j < matchColor.length; j += 1)       matchAttrSet[j] = sc.addAttribute(SimpleAttributeSet.EMPTY,           StyleConstants.Foreground, matchColor[j]);   }   // match and color the parens/brackets/braces   public void run() {     StyledDocument doc = getStyledDocument();     String text = "";     int len = doc.getLength();     try {       text = doc.getText(0, len);     } catch (BadLocationException ble) {     }     java.util.Stack stack = new java.util.Stack();     for (int j = 0; j < text.length(); j += 1) {       char ch = text.charAt(j);       if (ch == '(' || ch == '[' || ch == '{') {         int depth = stack.size();         stack.push("" + ch + j); // push a String containg the char and         // the offset         AttributeSet aset = matchAttrSet[depth % matchAttrSet.length];         doc.setCharacterAttributes(j, 1, aset, false);       }       if (ch == ')' || ch == ']' || ch == '}') {         String peek = stack.empty() ? "." : (String) stack.peek();         if (matches(peek.charAt(0), ch)) { // does it match?           stack.pop();           int depth = stack.size();           AttributeSet aset = matchAttrSet[depth               % matchAttrSet.length];           doc.setCharacterAttributes(j, 1, aset, false);         } else { // mismatch           doc.setCharacterAttributes(j, 1, badAttrSet, false);         }       }     }     while (!stack.empty()) { // anything left in the stack is a mismatch       String pop = (String) stack.pop();       int offset = Integer.parseInt(pop.substring(1));       doc.setCharacterAttributes(offset, 1, badAttrSet, false);     }   }   // unset the foreground color (if any) whenever the user enters text   // (if not for this, text entered after a paren would catch the paren's   // color)   public void replaceSelection(String content) {     getInputAttributes().removeAttribute(StyleConstants.Foreground);     super.replaceSelection(content);   }   // return true if 'left' and 'right' are matching parens/brackets/braces   public static boolean matches(char left, char right) {     if (left == '(')       return (right == ')');     if (left == '[')       return (right == ']');     if (left == '{')       return (right == '}');     return false;   }   public static void main(String[] args) {     JFrame frame = new JFrame("ParenMatcher");     final ParenMatcher matcher = new ParenMatcher();     matcher.setText("int fact(int n) {\n" + "  if (n <= 1) return 1;\n"         + "  return(n * fact(n-1));\n" + "}\n");     frame.getContentPane().add(new JScrollPane(matcher),         BorderLayout.CENTER);     JButton matchButton = new JButton("match parens");     matchButton.addActionListener(new ActionListener() {       public void actionPerformed(ActionEvent ae) {         matcher.run();       }     });     frame.getContentPane().add(matchButton, BorderLayout.SOUTH);     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     frame.setSize(200, 150);     frame.setVisible(true);   } }