1
14 package gate.swing;
15
16 import java.awt.*;
17 import java.awt.event.MouseAdapter;
18 import java.awt.event.MouseEvent;
19 import java.beans.PropertyChangeEvent;
20 import java.beans.PropertyChangeListener;
21
22 import javax.swing.*;
23 import javax.swing.event.*;
24 import javax.swing.table.*;
25 import javax.swing.tree.*;
26
27
28
32 public class JTreeTable extends XJTable {
33
34
35 protected CustomJTree tree;
36
37
38 protected TreeTableModel treeTableModel;
39
40
43 public JTreeTable(TreeTableModel model) {
44 super();
45 this.treeTableModel = model;
46
47 initLocalData();
48 initGuiComponents();
49 initListeners();
50
51 super.setSortable(false);
52 }
53
54 protected void initLocalData(){
55 }
56
57 protected void initGuiComponents(){
58 tree = new CustomJTree();
61 tree.setModel(treeTableModel);
62 tree.setEditable(false);
63
64 super.setModel(new TreeTableModelAdapter(treeTableModel));
66
67 tree.setSelectionModel(new DefaultTreeSelectionModel() {
69 {
71 setSelectionModel(listSelectionModel);
72 }
73 });
74
75 setAutoCreateColumnsFromModel(false);
76 getColumnModel().getColumn(0).setCellRenderer(new TreeTableCellRenderer());
78 getColumnModel().getColumn(0).setCellEditor(new TreeTableCellEditor());
79
80 setShowGrid(false);
81 }
82
83 protected void initListeners(){
84 addMouseListener(new MouseHandler());
86
87 getColumnModel().getColumn(0).addPropertyChangeListener(new PropertyChangeListener() {
88 public void propertyChange(PropertyChangeEvent e) {
89 if(e.getPropertyName().equals("width")){
90 int width = ((Number)e.getNewValue()).intValue();
91 int height = tree.getSize().height;
92 tree.setSize(width, height);
93 }
94 }
95 });
96 }
97
98
103 public void setSortable(boolean b){
104 throw new UnsupportedOperationException(
105 "A JTreeTable component cannot be sortable!\n" +
106 "The rows order is defined by the tree structure.");
107 }
108
109 public JTree getTree(){
110 return tree;
111 }
112
113 public void expandPath(TreePath path){
114 tree.expandPath(path);
115 }
116
117 public void expandRow(int row){
118 tree.expandRow(row);
119 }
120
121
125 public class TreeTableCellRenderer extends DefaultTableCellRenderer {
126 public Component getTableCellRendererComponent(JTable table,
127 Object value,
128 boolean isSelected,
129 boolean hasFocus,
130 int row, int column) {
131 tree.setVisibleRow(row);
132 return tree;
133 }
134 }
136
140 class TreeTableCellEditor extends DefaultCellEditor
141 implements TableCellEditor {
142 TreeTableCellEditor(){
143 super(new JTextField());
144 editor = tree.getCellEditor();
146 setClickCountToStart(0);
147 }
148
149 public Component getTableCellEditorComponent(JTable table,
150 Object value,
151 boolean isSelected,
152 int row,
153 int column) {
154
155 editor = tree.getCellEditor();
156
157 editor.addCellEditorListener(new CellEditorListener() {
158 public void editingStopped(ChangeEvent e) {
159 fireEditingStopped();
160 }
161
162 public void editingCanceled(ChangeEvent e) {
163 fireEditingCanceled();
164 }
165 });
166
167 editorComponent = editor.getTreeCellEditorComponent(
168 tree, tree.getPathForRow(row).getLastPathComponent(),
169 isSelected, tree.isExpanded(row),
170 tree.getModel().isLeaf(
171 tree.getPathForRow(row).getLastPathComponent()
172 ),
173 row);
174 Box box = Box.createHorizontalBox();
175 box.add(Box.createHorizontalStrut(tree.getRowBounds(row).x));
176 box.add(editorComponent);
177 return box;
178 }
180
181 public Object getCellEditorValue() {
182 return editor == null ? null : editor.getCellEditorValue();
183 }
184
185 public boolean stopCellEditing(){
186 return editor == null ? true : editor.stopCellEditing();
187 }
188
189 public void cancelCellEditing(){
190 if(editor != null) editor.cancelCellEditing();
191 }
192
193 TreeCellEditor editor;
194 Component editorComponent;
195 }
196
197
202 class MouseHandler extends MouseAdapter {
203 public void mousePressed(MouseEvent e) {
204 if(columnAtPoint(e.getPoint()) == 0){
205 tree.dispatchEvent(convertEvent(e));
206 }
207 }
208
209 public void mouseReleased(MouseEvent e) {
210 if(columnAtPoint(e.getPoint()) == 0){
211 tree.dispatchEvent(convertEvent(e));
212 }
213 }
214
215 public void mouseClicked(MouseEvent e) {
216 if(columnAtPoint(e.getPoint()) == 0){
217 tree.dispatchEvent(convertEvent(e));
218 }
219 }
220
221
222 public void mouseEntered(MouseEvent e) {
223 if(columnAtPoint(e.getPoint()) == 0){
224 tree.dispatchEvent(convertEvent(e));
225 }
226 }
227
228 public void mouseExited(MouseEvent e) {
229 if(columnAtPoint(e.getPoint()) == 0){
230 tree.dispatchEvent(convertEvent(e));
231 }
232 }
233
234 protected MouseEvent convertEvent(MouseEvent e){
235 int column = 0;
236 int row = rowAtPoint(e.getPoint());
237
238 Rectangle tableCellRect = getCellRect(row, column, false);
240 Rectangle treeCellRect = tree.getRowBounds(row);
241 int dx = 0;
242 if(tableCellRect != null) dx = -tableCellRect.x;
243 int dy = 0;
244 if(tableCellRect !=null && treeCellRect != null)
245 dy = treeCellRect.y -tableCellRect.y;
246 e.translatePoint(dx, dy);
247
248
249 return new MouseEvent(
250 tree, e.getID(), e.getWhen(), e.getModifiers(),
251 e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger()
252 );
253 }
254 }
255
256
259 class TreeTableModelAdapter extends AbstractTableModel{
260 public TreeTableModelAdapter(TreeTableModel treeTableModel) {
261 tree.addTreeExpansionListener(new TreeExpansionListener() {
262 public void treeExpanded(TreeExpansionEvent event) {
265 fireTableDataChanged();
266 }
267 public void treeCollapsed(TreeExpansionEvent event) {
268 fireTableDataChanged();
269 }
270 });
271 tree.getModel().addTreeModelListener(new TreeModelListener() {
272 public void treeNodesChanged(TreeModelEvent e) {
273 fireTableDataChanged();
274 }
275 public void treeNodesInserted(TreeModelEvent e) {
276 fireTableDataChanged();
277 }
278 public void treeNodesRemoved(TreeModelEvent e) {
279 fireTableDataChanged();
280 }
281 public void treeStructureChanged(TreeModelEvent e) {
282 fireTableDataChanged();
283 }
284 });
285 }
286
287
288
289 public int getColumnCount() {
291 return treeTableModel.getColumnCount();
292 }
293
294 public String getColumnName(int column) {
295 return treeTableModel.getColumnName(column);
296 }
297
298 public Class getColumnClass(int column) {
299 if(column == 0) return TreeTableModel.class;
300 else return treeTableModel.getColumnClass(column);
301 }
302
303 public int getRowCount() {
304 return tree.getRowCount();
305 }
306
307 protected Object nodeForRow(int row) {
308 TreePath treePath = tree.getPathForRow(row);
309 return treePath.getLastPathComponent();
310 }
311
312 public Object getValueAt(int row, int column) {
313 if(column == 0) return treeTableModel;
314 else return treeTableModel.getValueAt(nodeForRow(row), column);
315 }
316
317 public boolean isCellEditable(int row, int column) {
318 return treeTableModel.isCellEditable(nodeForRow(row), column);
319 }
320
321 public void setValueAt(Object value, int row, int column) {
322 Object node = nodeForRow(row);
323 treeTableModel.setValueAt(value, node, column);
324 }
325 }
327
330 class CustomJTree extends JTree {
331
332 public void updateUI(){
333 super.updateUI();
334 setRowHeight(0);
335 }
336
337
338 public void setVisibleRow(int row){
339 visibleRow = row;
340 }
341
342
345 public void paint(Graphics g){
346 Rectangle rect = getRowBounds(visibleRow);
347 Rectangle bounds = g.getClipBounds();
348 g.translate(0, -rect.y);
349 g.setClip(bounds.x, rect.y, bounds.width, rect.height);
350 super.paint(g);
351 }
352
353
354 public Dimension getPreferredSize(){
355 return new Dimension(super.getPreferredSize().width,
356 getRowBounds(visibleRow).height);
357 }
358
359
360 public void validate(){}
361 public void revalidate(){}
362 public void repaint(long tm, int x, int y, int width, int height){}
363 public void repaint(Rectangle r){}
364
365 protected int visibleRow;
366 }
367
368
401 }