📄 elementtreepanel.java
字号:
/* * @(#)ElementTreePanel.java 1.17 05/11/17 * * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. *//* * @(#)ElementTreePanel.java 1.17 05/11/17 */import javax.swing.*;import javax.swing.event.*;import javax.swing.text.*;import javax.swing.tree.*;import javax.swing.undo.*;import java.awt.*;import java.beans.*;import java.util.*;/** * Displays a tree showing all the elements in a text Document. Selecting * a node will result in reseting the selection of the JTextComponent. * This also becomes a CaretListener to know when the selection has changed * in the text to update the selected item in the tree. * * @author Scott Violet * @version 1.17 11/17/05 */public class ElementTreePanel extends JPanel implements CaretListener, DocumentListener, PropertyChangeListener, TreeSelectionListener { /** Tree showing the documents element structure. */ protected JTree tree; /** Text component showing elemenst for. */ protected JTextComponent editor; /** Model for the tree. */ protected ElementTreeModel treeModel; /** Set to true when updatin the selection. */ protected boolean updatingSelection; public ElementTreePanel(JTextComponent editor) { this.editor = editor; Document document = editor.getDocument(); // Create the tree. treeModel = new ElementTreeModel(document); tree = new JTree(treeModel) { public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { // Should only happen for the root if(!(value instanceof Element)) return value.toString(); Element e = (Element)value; AttributeSet as = e.getAttributes().copyAttributes(); String asString; if(as != null) { StringBuffer retBuffer = new StringBuffer("["); Enumeration names = as.getAttributeNames(); while(names.hasMoreElements()) { Object nextName = names.nextElement(); if(nextName != StyleConstants.ResolveAttribute) { retBuffer.append(" "); retBuffer.append(nextName); retBuffer.append("="); retBuffer.append(as.getAttribute(nextName)); } } retBuffer.append(" ]"); asString = retBuffer.toString(); } else asString = "[ ]"; if(e.isLeaf()) return e.getName() + " [" + e.getStartOffset() + ", " + e.getEndOffset() +"] Attributes: " + asString; return e.getName() + " [" + e.getStartOffset() + ", " + e.getEndOffset() + "] Attributes: " + asString; } }; tree.addTreeSelectionListener(this); tree.setDragEnabled(true); // Don't show the root, it is fake. tree.setRootVisible(false); // Since the display value of every node after the insertion point // changes every time the text changes and we don't generate a change // event for all those nodes the display value can become off. // This can be seen as '...' instead of the complete string value. // This is a temporary workaround, increase the needed size by 15, // hoping that will be enough. tree.setCellRenderer(new DefaultTreeCellRenderer() { public Dimension getPreferredSize() { Dimension retValue = super.getPreferredSize(); if(retValue != null) retValue.width += 15; return retValue; } }); // become a listener on the document to update the tree. document.addDocumentListener(this); // become a PropertyChangeListener to know when the Document has // changed. editor.addPropertyChangeListener(this); // Become a CaretListener editor.addCaretListener(this); // configure the panel and frame containing it. setLayout(new BorderLayout()); add(new JScrollPane(tree), BorderLayout.CENTER); // Add a label above tree to describe what is being shown JLabel label = new JLabel("Elements that make up the current document", SwingConstants.CENTER); label.setFont(new Font("Dialog", Font.BOLD, 14)); add(label, BorderLayout.NORTH); setPreferredSize(new Dimension(400, 400)); } /** * Resets the JTextComponent to <code>editor</code>. This will update * the tree accordingly. */ public void setEditor(JTextComponent editor) { if (this.editor == editor) { return; } if (this.editor != null) { Document oldDoc = this.editor.getDocument(); oldDoc.removeDocumentListener(this); this.editor.removePropertyChangeListener(this); this.editor.removeCaretListener(this); } this.editor = editor; if (editor == null) { treeModel = null; tree.setModel(null); } else { Document newDoc = editor.getDocument(); newDoc.addDocumentListener(this); editor.addPropertyChangeListener(this); editor.addCaretListener(this); treeModel = new ElementTreeModel(newDoc); tree.setModel(treeModel); } } // PropertyChangeListener /** * Invoked when a property changes. We are only interested in when the * Document changes to reset the DocumentListener. */ public void propertyChange(PropertyChangeEvent e) { if (e.getSource() == getEditor() && e.getPropertyName().equals("document")) { JTextComponent editor = getEditor(); Document oldDoc = (Document)e.getOldValue(); Document newDoc = (Document)e.getNewValue(); // Reset the DocumentListener oldDoc.removeDocumentListener(this); newDoc.addDocumentListener(this); // Recreate the TreeModel. treeModel = new ElementTreeModel(newDoc); tree.setModel(treeModel); } } // DocumentListener /** * Gives notification that there was an insert into the document. The * given range bounds the freshly inserted region. * * @param e the document event */ public void insertUpdate(DocumentEvent e) { updateTree(e); } /** * Gives notification that a portion of the document has been * removed. The range is given in terms of what the view last * saw (that is, before updating sticky positions). * * @param e the document event */ public void removeUpdate(DocumentEvent e) { updateTree(e); } /** * Gives notification that an attribute or set of attributes changed. * * @param e the document event */ public void changedUpdate(DocumentEvent e) { updateTree(e); } // CaretListener /** * Messaged when the selection in the editor has changed. Will update * the selection in the tree. */ public void caretUpdate(CaretEvent e) { if(!updatingSelection) { JTextComponent editor = getEditor(); int selBegin = Math.min(e.getDot(), e.getMark()); int end = Math.max(e.getDot(), e.getMark()); Vector paths = new Vector(); TreeModel model = getTreeModel(); Object root = model.getRoot(); int rootCount = model.getChildCount(root); // Build an array of all the paths to all the character elements // in the selection. for(int counter = 0; counter < rootCount; counter++) { int start = selBegin; while(start <= end) { TreePath path = getPathForIndex(start, root, (Element)model.getChild(root, counter)); Element charElement = (Element)path. getLastPathComponent(); paths.addElement(path); if(start >= charElement.getEndOffset()) start++; else start = charElement.getEndOffset(); } } // If a path was found, select it (them). int numPaths = paths.size(); if(numPaths > 0) { TreePath[] pathArray = new TreePath[numPaths]; paths.copyInto(pathArray); updatingSelection = true; try { getTree().setSelectionPaths(pathArray); getTree().scrollPathToVisible(pathArray[0]); } finally { updatingSelection = false; } } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -