001: /*
002: * The contents of this file are subject to the
003: * Mozilla Public License Version 1.1 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
009: * See the License for the specific language governing rights and
010: * limitations under the License.
011: *
012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
014: *
015: * All Rights Reserved.
016: *
017: * Contributor(s):
018: */
019: package org.openharmonise.him.swing.resourcetree;
020:
021: import java.awt.*;
022: import java.awt.dnd.*;
023: import java.util.*;
024: import java.util.List;
025:
026: import javax.swing.*;
027: import javax.swing.event.*;
028: import javax.swing.tree.*;
029:
030: import org.openharmonise.him.dnd.*;
031: import org.openharmonise.vfs.*;
032:
033: /**
034: * Tree view over a set of collections of resources.
035: *
036: * @author Matthew Large
037: * @version $Revision: 1.2 $
038: *
039: */
040: public class ResourceTree extends JPanel implements
041: TreeSelectionListener {
042:
043: /**
044: * JTree that will be used to display the resources.
045: */
046: protected JTree m_tree = null;
047:
048: /**
049: * List of {@link TreeViewListener} listeners.
050: */
051: private ArrayList m_listeners = new ArrayList(1);
052:
053: /**
054: * Listener on the JTree.
055: */
056: private TreeListener m_treeListener = null;
057:
058: /**
059: * List of full paths to the root collections.
060: */
061: protected List m_rootPaths = new ArrayList();
062:
063: /**
064: * Virtual File system this tree is viewing.
065: */
066: protected AbstractVirtualFileSystem m_vfs = null;
067:
068: /**
069: * Resources filter to use.
070: */
071: private AbstractResourceFilter m_resourceFilter = null;
072:
073: /**
074: * True if the tree is to be enclosed in a scrollpane.
075: */
076: private boolean m_bUseScrollPane = true;
077:
078: /**
079: * Constructs a new resource tree.
080: *
081: */
082: public ResourceTree() {
083: super ();
084: this .setup();
085: }
086:
087: /**
088: * Constructs a new resource tree.
089: *
090: * @param bUserScrollPane true if the tree is to be enclosed in a scrollpane.
091: */
092: public ResourceTree(boolean bUserScrollPane) {
093: super ();
094: this .m_bUseScrollPane = bUserScrollPane;
095: this .setup();
096: }
097:
098: /**
099: * Checks if the tree is enclosed in a scroll pane.
100: *
101: * @return true if the tree is enclosed in a scroll pane.
102: */
103: public boolean isUsingScrollPane() {
104: return this .m_bUseScrollPane;
105: }
106:
107: /**
108: * Gets the underlying JTree.
109: *
110: * @return the underlying JTree.
111: */
112: public JTree getTree() {
113: return this .m_tree;
114: }
115:
116: /**
117: * Initialises this component.
118: */
119: protected void setup() {
120: this .m_resourceFilter = new BasicResourceFilter();
121:
122: this .setLayout(new BorderLayout());
123:
124: DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(
125: "root");
126: TreeModel treeModel = new TreeModel(rootNode);
127:
128: this .m_tree = new JTree(treeModel);
129: m_tree.getSelectionModel().setSelectionMode(
130: TreeSelectionModel.SINGLE_TREE_SELECTION);
131: this .m_tree.setRootVisible(false);
132: TreeDragSource dragSource = new TreeDragSource(this ,
133: this .m_tree, DnDConstants.ACTION_COPY_OR_MOVE);
134:
135: this .m_tree.setShowsRootHandles(true);
136: this .m_tree.setLargeModel(true);
137:
138: this .m_tree.setCellRenderer(new TreeCellRenderer(this ));
139: m_treeListener = new TreeListener();
140: this .m_tree.addTreeSelectionListener(m_treeListener);
141: this .m_tree.addTreeSelectionListener(this );
142: this .m_tree.addTreeWillExpandListener(m_treeListener);
143: this .m_tree.setVisible(true);
144:
145: if (this .m_bUseScrollPane) {
146: JScrollPane treePane = new JScrollPane(this .m_tree,
147: JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
148: JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
149:
150: treePane.setBorder(BorderFactory.createEmptyBorder());
151: this .add(treePane);
152: } else {
153: this .add(m_tree);
154: }
155:
156: this .doLayout();
157: }
158:
159: /**
160: * Sets the resource fiter to be used.
161: *
162: * @param resourceFilter resource filter to be used.
163: */
164: public void setResourceFilter(AbstractResourceFilter resourceFilter) {
165: this .m_resourceFilter = resourceFilter;
166: }
167:
168: /**
169: * Clears any selected resources.
170: *
171: */
172: public void clearSelection() {
173: m_tree.clearSelection();
174: }
175:
176: /**
177: * Adds a selection listener.
178: *
179: * @param listener listener to add.
180: */
181: public void addListener(TreeViewListener listener) {
182: this .m_listeners.add(listener);
183: }
184:
185: /**
186: * Removes a selection listener.
187: *
188: * @param listener listener to remove.
189: */
190: public void removeListener(TreeViewListener listener) {
191: this .m_listeners.remove(listener);
192: }
193:
194: /**
195: * Fires a tree selection event to all the selection lisenter.
196: *
197: * @param vfs virtual file system this tree is using.
198: * @param sPath full path to the selected resource.
199: */
200: public void fireTreeSelectionEvent(AbstractVirtualFileSystem vfs,
201: String sPath) {
202: Iterator itor = this .m_listeners.iterator();
203: while (itor.hasNext()) {
204: TreeViewListener listener = (TreeViewListener) itor.next();
205: listener.virtualFileSelected(vfs, sPath);
206: }
207: }
208:
209: /**
210: * Adds a root collection to this tree.
211: *
212: * @param vfFile collection to add.
213: */
214: public void addCollection(VirtualFile vfFile) {
215: if(vfFile!=null) {
216: m_vfs = vfFile.getVFS();
217: String sFullPath = vfFile.getFullPath();
218: m_rootPaths.add(sFullPath);
219:
220: boolean bFoundHigher = false;
221: boolean bFoundLower = false;
222: boolean bFoundSame = false;
223: Iterator itor = this .m_rootPaths.iterator();
224: while (itor.hasNext()) {
225: String sRootPath = (String) itor.next();
226: if(sRootPath.startsWith(sFullPath)) {
227: bFoundLower = true;
228: } else if(sFullPath.startsWith(sRootPath) && sFullPath.lastIndexOf("/")>sRootPath.lastIndexOf("/")) {
229: bFoundHigher = true;
230: } else if(sFullPath.equals(sRootPath)) {
231: bFoundSame = true;
232: }
233: }
234:
235: if(bFoundHigher || bFoundSame) {
236: // NO-OP
237: } else if(bFoundLower) {
238: Enumeration enum = ((DefaultMutableTreeNode)this .m_tree.getModel().getRoot()).children();
239: TreeNode foundNode = null;
240: while(enum.hasMoreElements()) {
241: TreeNode tempNode = (TreeNode) enum.nextElement();
242: if(tempNode.getFilePath().startsWith(sFullPath)) {
243: foundNode = tempNode;
244: }
245: }
246: if(foundNode!=null) {
247: ((DefaultMutableTreeNode)this .m_tree.getModel().getRoot()).remove(foundNode);
248: }
249: TreeNode node = new TreeNode(m_vfs,sFullPath, this .m_tree, this .m_resourceFilter);
250: ((DefaultMutableTreeNode)this .m_tree.getModel().getRoot()).add(node);
251: if(((DefaultMutableTreeNode)this .m_tree.getModel().getRoot()).getChildCount()==1) {
252: this .m_tree.expandPath( new TreePath( node.getPath()) );
253: }
254: ((TreeModel)this .m_tree.getModel()).fireTreeStructureChanged(node, ((DefaultMutableTreeNode)this .m_tree.getModel().getRoot()).getPath(), null,null);
255: this .m_tree.repaint();
256: } else {
257: TreeNode node = new TreeNode(m_vfs,sFullPath, this .m_tree, this .m_resourceFilter);
258: ((DefaultMutableTreeNode)this .m_tree.getModel().getRoot()).add(node);
259: if(((DefaultMutableTreeNode)this .m_tree.getModel().getRoot()).getChildCount()==1) {
260: this .m_tree.expandPath( new TreePath( node.getPath()) );
261: }
262: ((TreeModel)this .m_tree.getModel()).fireTreeStructureChanged(node, ((DefaultMutableTreeNode)this .m_tree.getModel().getRoot()).getPath(), null,null);
263: this .m_tree.repaint();
264: }
265: }
266: }
267:
268: /**
269: * Checks if this tree is showing the leaf nodes.
270: *
271: * @return true if this tree is showing leaf nodes.
272: */
273: public boolean isShowLeafNodes() {
274: return !m_resourceFilter.isShowCollectionsOnly();
275: }
276:
277: /**
278: * Sets whether this tree is to show leaf nodes.
279: *
280: * @param b true to set this tree to show leaf nodes.
281: */
282: public void setShowLeafNodes(boolean b) {
283: this .m_resourceFilter.setShowCollectionsOnly(!b);
284: }
285:
286: /**
287: * Checks if this tree is showing approved resources only.
288: *
289: * @return true if this tree is showing approved resources only.
290: */
291: public boolean isShowApprovedOnly() {
292: return this .m_resourceFilter.isShowLiveResourcesOnly();
293: }
294:
295: /**
296: * Sets whether this tree is to show approved resources only.
297: *
298: * @param b true to set this tree to show approves resources only.
299: */
300: public void setShowApprovedOnly(boolean b) {
301: this .m_resourceFilter.setShowLiveResourcesOnly(b);
302: }
303:
304: /**
305: * Gets the currently selected resource.
306: *
307: * @return selected resource.
308: */
309: public VirtualFile getSelectedResource() {
310: VirtualFile vFile = null;
311:
312: TreePath tPath = m_tree.getSelectionPath();
313: if (tPath != null) {
314: Object obj = tPath.getLastPathComponent();
315: if (obj instanceof TreeNode) {
316: vFile = ((TreeNode) obj).getVFS().getVirtualFile(
317: ((TreeNode) obj).getFilePath()).getResource();
318: }
319: }
320:
321: return vFile;
322: }
323:
324: /* (non-Javadoc)
325: * @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event.TreeSelectionEvent)
326: */
327: public void valueChanged(TreeSelectionEvent e) {
328: TreePath path = e.getNewLeadSelectionPath();
329: if (path != null) {
330: Object obj = path.getLastPathComponent();
331: if (obj instanceof TreeNode) {
332: String filepath = ((TreeNode) obj).getFilePath();
333: AbstractVirtualFileSystem vfs = ((TreeNode) obj)
334: .getVFS();
335: this .fireTreeSelectionEvent(vfs, filepath);
336: }
337: }
338: }
339:
340: /**
341: * Sets which resources are to be selected.
342: *
343: * @param paths full paths to resources to be selected.
344: */
345: public void setSelectionPaths(List paths) {
346: if (m_tree != null && paths != null) {
347: TreeModel tModel = (TreeModel) m_tree.getModel();
348: Iterator iter = paths.iterator();
349:
350: while (iter.hasNext()) {
351: String sPath = (String) iter.next();
352:
353: TreePath tPath = tModel.getTreePath(sPath);
354:
355: m_tree.addSelectionPath(tPath);
356: }
357: }
358: }
359:
360: /**
361: * Sets which resource is to be selected.
362: *
363: * @param sPath full path to the resource to be selected.
364: */
365: public void setSelectionPath(String sPath) {
366: if (m_tree != null && sPath != null) {
367: TreeModel tModel = (TreeModel) m_tree.getModel();
368:
369: TreePath tPath = tModel.getTreePath(sPath);
370:
371: m_tree.setSelectionPath(tPath);
372: }
373: }
374:
375: /**
376: * Gets the paths of the selected resources.
377: *
378: * @return full paths to the selected resources.
379: */
380: public List getSelectionPaths() {
381: List paths = new ArrayList();
382:
383: TreePath[] tpaths = m_tree.getSelectionPaths();
384:
385: for (int i = 0; i < tpaths.length; i++) {
386: String sPath = ((TreeNode) tpaths[i].getLastPathComponent())
387: .getFilePath();
388: if (sPath != null && sPath.length() > 0) {
389: paths.add(sPath);
390: }
391: }
392:
393: return paths;
394: }
395:
396: /**
397: * Sets the selection mode.
398: *
399: * @param nMode selection mode.
400: */
401: public void setSelectionMode(int nMode) {
402: m_tree.getSelectionModel().setSelectionMode(nMode);
403: }
404:
405: /**
406: * Opens a specified path in the tree.
407: *
408: * @param sPath Full path to open
409: */
410: public void openPath(String sPath) {
411: DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode) this .m_tree
412: .getModel().getRoot();
413:
414: DefaultMutableTreeNode node = this .getNode(rootNode, sPath);
415: if (node != null) {
416: TreePath treePath = new TreePath(node.getPath());
417: this .m_tree.setSelectionPath(treePath);
418: }
419: }
420:
421: /**
422: * Returns a node, which is a descendant of a given node, for a
423: * specified path.
424: *
425: * @param node Ancestor node
426: * @param sPath Full path
427: * @return Node
428: */
429: public DefaultMutableTreeNode getNode(DefaultMutableTreeNode node,
430: String sPath) {
431: DefaultMutableTreeNode retnNode = null;
432: if (node instanceof TreeNode) {
433: ((TreeNode) node).populateChildren();
434: }
435: for (int i = 0; i < node.getChildCount(); i++) {
436: DefaultMutableTreeNode tempNode = (DefaultMutableTreeNode) node
437: .getChildAt(i);
438: if (tempNode instanceof TreeNode) {
439: String sTempPath = ((TreeNode) tempNode).getFilePath();
440: if (!sPath.equals(sTempPath)
441: && sPath.startsWith(sTempPath)
442: && sPath.length() > sTempPath.length()
443: && sPath.substring(sTempPath.length(),
444: sPath.length() - 1).startsWith("/")) {
445: retnNode = this .getNode(tempNode, sPath);
446: break;
447: } else if (sPath.equals(sTempPath)) {
448: retnNode = tempNode;
449: break;
450: }
451: }
452: }
453:
454: return retnNode;
455: }
456:
457: protected AbstractVirtualFileSystem getVFS() {
458: return this .m_vfs;
459: }
460:
461: /* (non-Javadoc)
462: * @see java.awt.Component#setEnabled(boolean)
463: */
464: public void setEnabled(boolean bEnabled) {
465: for (int i = 0; i < this .getComponentCount(); i++) {
466: Component comp = this.getComponent(i);
467: comp.setEnabled(bEnabled);
468: }
469: super.setEnabled(bEnabled);
470: }
471: }
|