View Javadoc

1   // Copyright (C) 2004 - 2009 Philip Aston
2   // All rights reserved.
3   //
4   // This file is part of The Grinder software distribution. Refer to
5   // the file LICENSE which is part of The Grinder distribution for
6   // licensing details. The Grinder distribution is available on the
7   // Internet at http://grinder.sourceforge.net/
8   //
9   // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12  // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
13  // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
14  // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
15  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17  // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
18  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
19  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
20  // OF THE POSSIBILITY OF SUCH DAMAGE.
21  
22  package net.grinder.console.swingui;
23  
24  import java.io.File;
25  
26  import javax.swing.event.EventListenerList;
27  import javax.swing.event.TreeModelEvent;
28  import javax.swing.event.TreeModelListener;
29  import javax.swing.tree.TreeModel;
30  import javax.swing.tree.TreePath;
31  
32  import net.grinder.console.editor.Buffer;
33  import net.grinder.console.editor.EditorModel;
34  import net.grinder.util.WeakValueHashMap;
35  
36  
37  /**
38   * Simple {@link TreeModel} that lists buffers.
39   *
40   * @author Philip Aston
41   */
42  final class BufferTreeModel implements TreeModel {
43  
44    private final EditorModel m_editorModel;
45  
46    private final Object m_rootNode = new Object();
47    private final EventListenerList m_listeners = new EventListenerList();
48    private final WeakValueHashMap<Buffer, BufferNode> m_buffersToNodes =
49      new WeakValueHashMap<Buffer, BufferNode>();
50  
51    private BufferNode[] m_bufferNodes = new BufferNode[0];
52  
53    BufferTreeModel(EditorModel editorModel) {
54  
55      m_editorModel = editorModel;
56  
57      m_editorModel.addListener(new EditorModel.AbstractListener() {
58  
59          public void bufferAdded(Buffer buffer) {
60            bufferListChanged();
61          }
62  
63          public void bufferRemoved(Buffer buffer) {
64            bufferListChanged();
65          }
66        });
67  
68      bufferListChanged();
69    }
70  
71    private void bufferListChanged() {
72      final Buffer[] buffers = m_editorModel.getBuffers();
73      m_bufferNodes = new BufferNode[buffers.length];
74  
75      m_buffersToNodes.clear();
76  
77      for (int i = 0; i < buffers.length; ++i) {
78        m_bufferNodes[i] = new BufferNode(buffers[i]);
79        m_buffersToNodes.put(buffers[i], m_bufferNodes[i]);
80      }
81  
82      fireTreeStructureChanged();
83    }
84  
85    public Object getRoot() {
86      return m_rootNode;
87    }
88  
89    public Object getChild(Object parent, int index) {
90  
91      if (parent.equals(getRoot())) {
92        if (index >= 0 && index < m_bufferNodes.length) {
93          return m_bufferNodes[index];
94        }
95      }
96  
97      return null;
98    }
99  
100   public int getChildCount(Object parent) {
101 
102     if (parent.equals(getRoot())) {
103       return m_bufferNodes.length;
104     }
105 
106     return 0;
107   }
108 
109   public int getIndexOfChild(Object parent, Object child) {
110 
111     if (parent == null || child == null) {
112       // The TreeModel Javadoc says we should do this.
113       return -1;
114     }
115 
116     if (parent.equals(getRoot())) {
117       for (int i = 0; i < m_bufferNodes.length; ++i) {
118         if (child.equals(m_bufferNodes[i])) {
119           return i;
120         }
121       }
122     }
123 
124     return -1;
125   }
126 
127   public boolean isLeaf(Object node) {
128     if (node instanceof BufferNode) {
129       final BufferNode bufferNode = (BufferNode)node;
130 
131       if (bufferNode.belongsToModel(this)) {
132         return true;
133       }
134     }
135 
136     return false;
137   }
138 
139   public void addTreeModelListener(TreeModelListener listener) {
140     m_listeners.add(TreeModelListener.class, listener);
141   }
142 
143   public void removeTreeModelListener(TreeModelListener listener) {
144     m_listeners.remove(TreeModelListener.class, listener);
145   }
146 
147   private void fireTreeStructureChanged() {
148     final Object[] listeners = m_listeners.getListenerList();
149 
150     final TreeModelEvent event =
151       new TreeModelEvent(this, new Object[] { getRoot() });
152 
153     for (int i = listeners.length - 2; i >= 0; i -= 2) {
154       ((TreeModelListener)listeners[i + 1]).treeStructureChanged(event);
155     }
156   }
157 
158   private void fireTreeNodesChanged(TreePath path) {
159     final Object[] listeners = m_listeners.getListenerList();
160 
161     final TreeModelEvent event = new TreeModelEvent(this, path);
162 
163     for (int i = listeners.length - 2; i >= 0; i -= 2) {
164       ((TreeModelListener)listeners[i + 1]).treeNodesChanged(event);
165     }
166   }
167 
168   public void valueForPathChanged(TreePath path, Object newValue) {
169     fireTreeNodesChanged(path);
170   }
171 
172   public void bufferChanged(Buffer buffer) {
173 
174     final BufferTreeModel.BufferNode node = m_buffersToNodes.get(buffer);
175 
176     if (node != null) {
177       valueForPathChanged(node.getPath(), node);
178     }
179   }
180 
181   /**
182    * Node for buffers.
183    */
184   public final class BufferNode implements FileTree.Node {
185 
186     private final Buffer m_buffer;
187     private final TreePath m_path;
188 
189     protected BufferNode(Buffer buffer) {
190       m_buffer = buffer;
191       m_path = new TreePath(new Object[] { getRoot(), this });
192     }
193 
194     public String toString() {
195       return m_buffer.getDisplayName();
196     }
197 
198     public Buffer getBuffer() {
199       return m_buffer;
200     }
201 
202     public TreePath getPath() {
203       return m_path;
204     }
205 
206     public File getFile() {
207       return getBuffer().getFile();
208     }
209 
210     public boolean canOpen() {
211       return true;
212     }
213 
214     boolean belongsToModel(BufferTreeModel model) {
215       return BufferTreeModel.this == model;
216     }
217   }
218 }