001: /*
002: * DirectoryTree.java
003: *
004: * Copyright (C) 2000-2003 Peter Graves
005: * $Id: DirectoryTree.java,v 1.6 2003/07/23 15:52:14 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import java.awt.Color;
025: import java.awt.Component;
026: import java.awt.Graphics;
027: import java.awt.Point;
028: import java.awt.event.InputEvent;
029: import java.awt.event.KeyEvent;
030: import java.awt.event.KeyListener;
031: import java.awt.event.MouseEvent;
032: import java.awt.event.MouseListener;
033: import java.awt.event.MouseMotionListener;
034: import javax.swing.JTree;
035: import javax.swing.SwingUtilities;
036: import javax.swing.event.TreeExpansionEvent;
037: import javax.swing.event.TreeExpansionListener;
038: import javax.swing.event.TreeSelectionEvent;
039: import javax.swing.event.TreeSelectionListener;
040: import javax.swing.tree.DefaultMutableTreeNode;
041: import javax.swing.tree.DefaultTreeCellRenderer;
042: import javax.swing.tree.TreeModel;
043: import javax.swing.tree.TreePath;
044: import javax.swing.tree.TreeSelectionModel;
045:
046: public final class DirectoryTree extends SidebarTree implements
047: NavigationComponent, TreeSelectionListener,
048: TreeExpansionListener, MouseListener, MouseMotionListener,
049: KeyListener {
050: private Editor editor;
051: private DirectoryTreeModel treeModel;
052:
053: private DirectoryTree(Editor editor, TreeModel model) {
054: super (model);
055: this .editor = editor;
056: getSelectionModel().setSelectionMode(
057: TreeSelectionModel.SINGLE_TREE_SELECTION);
058: setScrollsOnExpand(false);
059: addTreeSelectionListener(this );
060: addTreeExpansionListener(this );
061: addMouseListener(this );
062: addMouseMotionListener(this );
063: addKeyListener(this );
064: setCellRenderer(new DirectoryTreeCellRenderer(this ));
065: }
066:
067: public static DirectoryTree getDirectoryTree(Editor editor) {
068: if (editor.getCurrentDirectory().isLocal()) {
069: if (editor.localDirectoryTree == null)
070: editor.localDirectoryTree = new DirectoryTree(editor,
071: null);
072: return editor.localDirectoryTree;
073: }
074: return new DirectoryTree(editor, null);
075: }
076:
077: public final String getLabelText() {
078: return editor.getBuffer().getFile().getName();
079: }
080:
081: public DirectoryTreeModel getTreeModel() {
082: return treeModel;
083: }
084:
085: public Editor getEditor() {
086: return editor;
087: }
088:
089: public void refresh() {
090: if (!SwingUtilities.isEventDispatchThread())
091: Debug
092: .bug("DirectoryTree.refresh() called from background thread!");
093: Runnable refreshRunnable = new Runnable() {
094: public void run() {
095: File file = editor.getBuffer().getFile();
096: if (file == null)
097: return;
098: if (treeModel == null) {
099: treeModel = DirectoryTreeModel.getTreeModel(file);
100: if (treeModel != null) {
101: final DefaultMutableTreeNode node = getNode(file);
102: Runnable completionRunnable = new Runnable() {
103: public void run() {
104: setModel(treeModel);
105: if (node != null)
106: scrollNodeToCenter(node);
107: }
108: };
109: SwingUtilities.invokeLater(completionRunnable);
110: }
111: } else {
112: DefaultMutableTreeNode selectedNode = null;
113: TreePath path = getSelectionPath();
114: if (path != null) {
115: selectedNode = (DefaultMutableTreeNode) path
116: .getLastPathComponent();
117: }
118: final DefaultMutableTreeNode node = getNode(file);
119: if (node != null && node != selectedNode) {
120: Runnable completionRunnable = new Runnable() {
121: public void run() {
122: scrollNodeToCenter(node);
123: }
124: };
125: SwingUtilities.invokeLater(completionRunnable);
126: }
127: }
128: }
129: };
130: new Thread(refreshRunnable).start();
131: }
132:
133: private void expandNode(DefaultMutableTreeNode node) {
134: DirectoryTreeElement treeElement = (DirectoryTreeElement) node
135: .getUserObject();
136: File file = treeElement.getFile();
137: expandNode(node, file);
138: }
139:
140: private void expandNode(DefaultMutableTreeNode node, File file) {
141: treeModel.expandNode(node, file);
142: }
143:
144: private DefaultMutableTreeNode getNode(File file) {
145: if (treeModel == null || file == null)
146: return null;
147: return treeModel.getNode(file);
148: }
149:
150: public void updatePosition() {
151: int limit = getRowCount();
152: int rowToBeSelected = -1;
153: String path = editor.getBuffer().getFile().canonicalPath();
154: for (int row = 0; row < limit; row++) {
155: TreePath treepath = getPathForRow(row);
156: if (treepath != null) {
157: DefaultMutableTreeNode node = (DefaultMutableTreeNode) treepath
158: .getLastPathComponent();
159: if (node != null) {
160: // On Windows the user object might be a string (host name).
161: if (node.getUserObject() instanceof DirectoryTreeElement) {
162: DirectoryTreeElement treeElement = (DirectoryTreeElement) node
163: .getUserObject();
164: if (path.equals(treeElement.getPath())) {
165: rowToBeSelected = row;
166: break;
167: }
168: }
169: }
170: }
171: }
172: if (rowToBeSelected >= 0) {
173: int[] selectedRows = getSelectionRows();
174: if (selectedRows != null && selectedRows.length == 1
175: && selectedRows[0] == rowToBeSelected)
176: ; // No change.
177: else {
178: setSelectionRow(rowToBeSelected);
179: scrollRowToCenter(rowToBeSelected);
180: }
181: } else
182: clearSelection();
183: }
184:
185: public void valueChanged(TreeSelectionEvent e) {
186: }
187:
188: public void treeCollapsed(TreeExpansionEvent e) {
189: }
190:
191: public void treeExpanded(TreeExpansionEvent e) {
192: }
193:
194: public void keyPressed(KeyEvent e) {
195: int keyCode = e.getKeyCode();
196: int modifiers = e.getModifiers();
197:
198: switch (keyCode) {
199: // Ignore modifier keystrokes.
200: case KeyEvent.VK_SHIFT:
201: case KeyEvent.VK_CONTROL:
202: case KeyEvent.VK_ALT:
203: case KeyEvent.VK_META:
204: return;
205:
206: case KeyEvent.VK_ENTER: {
207: e.consume();
208: TreePath path = getSelectionPath();
209: if (path != null) {
210: DefaultMutableTreeNode node = (DefaultMutableTreeNode) path
211: .getLastPathComponent();
212: if (node.getUserObject() instanceof DirectoryTreeElement) {
213: DirectoryTreeElement treeElement = (DirectoryTreeElement) node
214: .getUserObject();
215: File file = treeElement.getFile();
216: editor.setWaitCursor();
217: expandNode(node, file);
218: editor.setDefaultCursor();
219: if (e.getModifiers() == InputEvent.BUTTON2_MASK)
220: editor.setFocusToDisplay();
221: repaint();
222: ((Directory) editor.getBuffer())
223: .changeDirectory(file);
224: editor.updateDisplay();
225: }
226: }
227: editor.setFocusToDisplay();
228: if (modifiers == KeyEvent.ALT_MASK)
229: editor.toggleSidebar();
230: return;
231: }
232:
233: case KeyEvent.VK_TAB:
234: e.consume();
235: if (modifiers == 0) {
236: if (editor.getSidebar().getBufferList() != null)
237: editor
238: .setFocus(editor.getSidebar()
239: .getBufferList());
240: }
241: return;
242:
243: case KeyEvent.VK_ESCAPE:
244: e.consume();
245: editor.getSidebar().setBuffer();
246: editor.getSidebar().updatePosition();
247: editor.setFocusToDisplay();
248: return;
249: }
250:
251: editor.getDispatcher().setEnabled(false);
252: }
253:
254: public void keyReleased(KeyEvent e) {
255: e.consume();
256: editor.getDispatcher().setEnabled(true);
257: }
258:
259: public void keyTyped(KeyEvent e) {
260: e.consume();
261: }
262:
263: private boolean ignoreMouseClicked;
264:
265: public void mousePressed(MouseEvent e) {
266: ignoreMouseClicked = false;
267: LocationBar.cancelInput();
268: editor.ensureActive();
269: int modifiers = e.getModifiers();
270: if (modifiers == InputEvent.BUTTON1_MASK
271: || modifiers == InputEvent.BUTTON2_MASK) {
272: Point point = e.getPoint();
273: if (e.getModifiers() == InputEvent.BUTTON2_MASK) {
274: int row = getRowForLocation(point.x, point.y);
275: setSelectionRow(row);
276: }
277: editor.setFocus(this );
278: TreePath treepath = getPathForLocation(point.x, point.y);
279: if (treepath == null) {
280: ignoreMouseClicked = true;
281: e.consume();
282: }
283: } else
284: editor.setFocusToDisplay();
285: }
286:
287: public void mouseReleased(MouseEvent e) {
288: }
289:
290: public void mouseClicked(MouseEvent e) {
291: if (ignoreMouseClicked) {
292: e.consume();
293: editor.setFocusToDisplay();
294: return;
295: }
296: final int modifiers = e.getModifiers();
297: if (modifiers != InputEvent.BUTTON1_MASK
298: && modifiers != InputEvent.BUTTON2_MASK) {
299: e.consume();
300: editor.setFocusToDisplay();
301: return;
302: }
303: Point point = e.getPoint();
304: TreePath treepath = getPathForLocation(point.x, point.y);
305: if (treepath != null) {
306: DefaultMutableTreeNode node = (DefaultMutableTreeNode) treepath
307: .getLastPathComponent();
308: DirectoryTreeElement treeElement = (DirectoryTreeElement) node
309: .getUserObject();
310: File file = treeElement.getFile();
311: editor.setWaitCursor();
312: expandNode(node, file);
313: expandPath(treepath);
314: editor.setDefaultCursor();
315: if (modifiers == InputEvent.BUTTON1_MASK
316: || modifiers == InputEvent.BUTTON2_MASK)
317: editor.setFocusToDisplay();
318: repaint();
319: ((Directory) editor.getBuffer()).changeDirectory(file);
320: editor.updateDisplay();
321: }
322: }
323:
324: public void mouseMoved(MouseEvent e) {
325: }
326:
327: public void mouseEntered(MouseEvent e) {
328: }
329:
330: public void mouseExited(MouseEvent e) {
331: editor.setFocusToDisplay();
332: }
333:
334: public void mouseDragged(MouseEvent e) {
335: }
336:
337: private static class DirectoryTreeCellRenderer extends
338: DefaultTreeCellRenderer {
339: private DirectoryTree tree;
340: private Editor editor;
341:
342: private static Color noFocusSelectionBackground = new Color(
343: 208, 208, 208);
344:
345: private Color oldBackgroundSelectionColor;
346:
347: public DirectoryTreeCellRenderer(DirectoryTree tree) {
348: super ();
349: this .tree = tree;
350: editor = tree.getEditor();
351: oldBackgroundSelectionColor = getBackgroundSelectionColor();
352:
353: setOpenIcon(Utilities.getIconFromFile("dir_open.png"));
354: setClosedIcon(Utilities.getIconFromFile("dir_close.png"));
355: setLeafIcon(Utilities.getIconFromFile("dir_close.png"));
356: }
357:
358: public Component getTreeCellRendererComponent(JTree tree,
359: Object value, boolean selected, boolean expanded,
360: boolean leaf, int row, boolean hasFocus) {
361: super .getTreeCellRendererComponent(tree, value, selected,
362: expanded, leaf, row, hasFocus);
363: if (selected)
364: super .setForeground(getTextSelectionColor());
365: else
366: super .setForeground(getTextNonSelectionColor());
367: if (editor.getFocusedComponent() == tree)
368: setBackgroundSelectionColor(oldBackgroundSelectionColor);
369: else
370: setBackgroundSelectionColor(noFocusSelectionBackground);
371: return this ;
372: }
373:
374: public void paintComponent(Graphics g) {
375: Display.setRenderingHints(g);
376: super.paintComponent(g);
377: }
378: }
379: }
|