📄 jreepadview.java
字号:
/* Jreepad - personal information manager. Copyright (C) 2004 Dan StowellThis program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.The full license can be read online here: http://www.gnu.org/copyleft/gpl.html*/package jreepad;import javax.swing.*;import javax.swing.tree.*;import javax.swing.table.*;import javax.swing.event.*;import javax.swing.undo.*;import javax.swing.text.BadLocationException;import javax.swing.text.*;import java.awt.*;import java.awt.event.*;import java.util.Enumeration;import java.util.Vector;import java.io.*;import java.awt.print.*;public class JreepadView extends Box implements TableModelListener{ // Code to ensure that the article word-wraps follows // - contributed by Michael Labhard based on code found on the web... static class JPEditorKit extends StyledEditorKit { public ViewFactory getViewFactory() { return new JPRTFViewFactory(); } } static class JPRTFViewFactory implements ViewFactory { public View create(Element elem) { String kind = elem.getName(); if(kind != null) if (kind.equals(AbstractDocument.ContentElementName)) { return new LabelView(elem); } else if (kind.equals(AbstractDocument.ParagraphElementName)) { return new JPParagraphView(elem); } else if (kind.equals(AbstractDocument.SectionElementName)) { return new BoxView(elem, View.Y_AXIS); } else if (kind.equals(StyleConstants.ComponentElementName)) { return new ComponentView(elem); } else if (kind.equals(StyleConstants.IconElementName)) { return new IconView(elem); } // default to text display return new LabelView(elem); } } private static short paraRightMargin = 0; static class JPParagraphView extends javax.swing.text.ParagraphView { public JPParagraphView(Element e) { super(e); this.setInsets((short)0, (short)0, (short)0, paraRightMargin); } } // Code to ensure that the article word-wraps ends here // - contributed by Michael Labhard private static JreepadPrefs prefs; private JreepadNode root; private JreepadNode currentNode; private JreepadNode currentDragDropNode; private TreeNode topNode; private JreepadTreeModel treeModel; private JTree tree; private JScrollPane treeView; private JScrollPane articleView; // editorPane is supposed to represent the pane currently displayed/edited - so it's the one // to refer to when you're doing GUI-related stuff // It will be equal to one of the content-type-specific panes. Need to set the content of BOTH of these...// private JEditorPane editorPane; private JEditorPane editorPanePlainText; private JEditorPane editorPaneHtml; private JTable editorPaneCsv; // Undo features// protected UndoManager undoMgr; private JSplitPane splitPane; private JreepadSearcher searcher; // The following boolean should be FALSE while we're changing from node to node, and true otherwise private boolean copyEditorPaneContentToNodeContent = true; private boolean warnAboutUnsaved = false; // Things concerned with the "undo" function //OLD ATTEMPT private JreepadNode oldRootForUndo, oldCurrentNodeForUndo; //OLD ATTEMPT private TreePath[] oldExpandedPaths; //OLD ATTEMPT private TreePath oldSelectedPath; public JreepadView() { this(new JreepadNode("<Untitled node>", "", null)); } public JreepadView(JreepadNode root) { super(BoxLayout.X_AXIS); treeView = new JScrollPane(); splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); splitPane.setResizeWeight(0.5); if(getPrefs().dividerLocation > 0) { splitPane.setDividerLocation(getPrefs().dividerLocation); } splitPane.addPropertyChangeListener("lastDividerLocation", new java.beans.PropertyChangeListener() { public void propertyChange(java.beans.PropertyChangeEvent evt) { // System.out.println(evt.getPropertyName()); getPrefs().dividerLocation = splitPane.getDividerLocation(); // System.out.println("New divider location = " + getPrefs().dividerLocation); } } ); this.root = root; treeModel = new JreepadTreeModel(root); treeModel.addTreeModelListener(new JreepadTreeModelListener()); tree = new JTree(treeModel){ public void cancelEditing() { super.cancelEditing(); // if we can override this perhaps we can prevent blank nodes...? JreepadNode lastEditedNode = (JreepadNode)(tree.getSelectionPath().getLastPathComponent()); if(lastEditedNode.getTitle().equals("")) lastEditedNode.setTitle("<Untitled node>"); } }; tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); tree.setExpandsSelectedPaths(true); tree.setInvokesStopCellEditing(true); tree.setEditable(true); tree.setModel(treeModel); DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); renderer.setOpenIcon(null); renderer.setClosedIcon(null); renderer.setLeafIcon(null); tree.setCellRenderer(renderer); searcher = new JreepadSearcher(root);// undoMgr = new UndoManager(); //Listen for when the selection changes. tree.addTreeSelectionListener(new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) { JreepadNode node = (JreepadNode) tree.getLastSelectedPathComponent(); if (node == null) return; // UNDO DEVELOPMENT:// System.out.println("TreeSelectionListener:valueChanged");// undoMgr.discardAllEdits(); setCurrentNode(node); } }); // Fiddle with the cell editor - to ensure that when editing a new node, you shouldn't be able to leave a blank title tree.getCellEditor().addCellEditorListener(new CellEditorListener() { public void editingCanceled(ChangeEvent e) { ensureNodeTitleIsNotEmpty(e); } public void editingStopped(ChangeEvent e) { ensureNodeTitleIsNotEmpty(e); } }); // Add mouse listener - this will be used to implement drag-and-drop, context menu (?), etc MouseListener ml = new MouseAdapter() { public void mousePressed(MouseEvent e) { TreePath selPath = tree.getPathForLocation(e.getX(), e.getY()); if(selPath != null) { currentDragDropNode = (JreepadNode)selPath.getLastPathComponent(); setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } } public void mouseReleased(MouseEvent e) { TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());// System.out.println("Mouse released: path = " + selPath); if(selPath != null) { if(currentDragDropNode != null && currentDragDropNode.getParentNode() != null && currentDragDropNode.getParentNode() != (JreepadNode)selPath.getLastPathComponent() && currentDragDropNode != (JreepadNode)selPath.getLastPathComponent()) { // Then we need to perform a drag-and-drop operation! moveNode(currentDragDropNode, (JreepadNode)selPath.getLastPathComponent()); // Ensure that the destination node is open tree.setSelectionPath(selPath.pathByAddingChild(currentDragDropNode)); } } setCursor(Cursor.getDefaultCursor()); currentDragDropNode = null; } public void mouseClicked(MouseEvent e) { TreePath selPath = tree.getPathForLocation(e.getX(), e.getY()); if(selPath != null) { if(e.isPopupTrigger()) { // Now we can implement the pop-up content menu System.out.println("Context menu would be launched here!"); } } } }; tree.addMouseListener(ml); tree.addKeyListener(new KeyAdapter(){public void keyPressed(KeyEvent kee) { int key = kee.getKeyCode(); switch(key) { case KeyEvent.VK_ENTER: addNodeBelow(); break; case KeyEvent.VK_F2: editNodeTitleAction(); break; } // System.out.println("Tree detected a keypress: " + kee.getKeyText(kee.getKeyCode()) + " (key code "+ kee.getKeyCode()+")"); }}); treeView.setViewportView(tree); editorPanePlainText = new JEditorPanePlus("text/plain", root.getContent()); editorPanePlainText.setEditable(true); editorPaneHtml = new JEditorPanePlus("text/html", root.getContent()); editorPaneHtml.setEditable(false); editorPaneCsv = new JTable(new ArticleTableModel()); editorPaneCsv.getModel().addTableModelListener(this); setEditorPaneKit(); // Add a listener to make sure the editorpane's content is always stored when it changes editorPanePlainText.addCaretListener(new CaretListener() { public void caretUpdate(CaretEvent e) { if(!copyEditorPaneContentToNodeContent) return; // i.e. we are deactivated while changing from node to node if(currentNode.getArticleMode() != JreepadNode.ARTICLEMODE_ORDINARY) return; // i.e. we are only relevant when in plain-text mode if(!editorPanePlainText.getText().equals(currentNode.getContent())) { // System.out.println("UPDATE - I'd now overwrite node content with editorpane content"); currentNode.setContent(editorPanePlainText.getText()); setWarnAboutUnsaved(true); } else { // System.out.println(" No need to update content."); } }}); articleView = new JScrollPane(getEditorPaneComponent(), JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); articleView.addComponentListener(new ComponentListener() { public void componentResized(ComponentEvent e) { editorPanePlainText.setMaximumSize(new Dimension(articleView.getViewport().getWidth(), Integer.MAX_VALUE)); editorPanePlainText.setSize(articleView.getViewport().getViewSize()); editorPaneHtml.setMaximumSize(new Dimension(articleView.getViewport().getWidth(), Integer.MAX_VALUE)); editorPaneHtml.setSize(articleView.getViewport().getViewSize()); } public void componentMoved(ComponentEvent e){} public void componentHidden(ComponentEvent e){} public void componentShown(ComponentEvent e){} } ); articleView.getViewport().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { editorPanePlainText.setPreferredSize(articleView.getViewport().getExtentSize()); editorPanePlainText.setMaximumSize(new Dimension(articleView.getViewport().getWidth(), Integer.MAX_VALUE)); editorPanePlainText.setSize(articleView.getViewport().getViewSize()); editorPaneHtml.setPreferredSize(articleView.getViewport().getExtentSize()); editorPaneHtml.setMaximumSize(new Dimension(articleView.getViewport().getWidth(), Integer.MAX_VALUE)); editorPaneHtml.setSize(articleView.getViewport().getViewSize()); } } ); setCurrentNode(root); setViewBoth(); tree.setSelectionRow(0); editorPanePlainText.getDocument().addUndoableEditListener(new JreepadUndoableEditListener()); } public void setEditorPaneKit() { if(getPrefs().wrapToWindow) editorPanePlainText.setEditorKit(new JPEditorKit()); // else // editorPane.setEditorKit(new javax.swing.text.StyledEditorKit()); } public void setViewMode(int mode) {// System.out.println("-------------------------------------------------------------");// System.out.println("editorPane size: " + editorPane.getSize());// System.out.println("articleView size: " + articleView.getSize());// System.out.println("articleView viewport size: " + articleView.getViewport().getSize());// System.out.println(); switch(mode) { case JreepadPrefs.VIEW_BOTH: setViewBoth(); break; case JreepadPrefs.VIEW_TREE: setViewTreeOnly(); break; case JreepadPrefs.VIEW_ARTICLE: setViewArticleOnly(); break; default: System.err.println("Invalid argument to JreepadView.setViewMode()!"); return; } setSize(getSize()); editorPanePlainText.setPreferredSize(articleView.getViewport().getExtentSize()); editorPanePlainText.setSize(articleView.getViewport().getExtentSize()); editorPaneHtml.setPreferredSize(articleView.getViewport().getExtentSize()); editorPaneHtml.setSize(articleView.getViewport().getExtentSize()); validate(); repaint();// System.out.println("editorPane size: " + editorPane.getSize());// System.out.println("articleView size: " + articleView.getSize());// System.out.println("articleView viewport size: " + articleView.getViewport().getSize());// System.out.println();// System.out.println(); } private void setViewBoth() { ensureCorrectArticleRenderMode(); splitPane.setLeftComponent(treeView); splitPane.setRightComponent(articleView); this.add(splitPane);// editorPane.setSize(articleView.getSize());// editorPane.setSize(articleView.getViewport().getViewSize()); } private void setViewTreeOnly() { this.remove(splitPane); this.remove(articleView); this.add(treeView); treeView.setSize(getSize()); } private void setViewArticleOnly() { this.remove(splitPane); this.remove(treeView); ensureCorrectArticleRenderMode(); this.add(articleView); articleView.setSize(getSize()); } /* private void setCurrentNode(DefaultMutableTreeNode node)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -