View Javadoc

1   /*
2    *  Copyright (C) 2003-2005 SINTEF
3    *  Author:  Fredrik Vraalsen (fredrik dot vraalsen at sintef dot no)
4    *  Webpage: http://coras.sourceforge.net/
5    *
6    *  This program is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public License
8    *  as published by the Free Software Foundation; either version 2.1
9    *  of the License, or (at your option) any later version.
10   *
11   *  This program is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this program; if not, write to the Free
18   *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19   *  02111-1307 USA
20   */
21  package coras.table;
22  
23  import java.awt.Component;
24  import java.awt.Container;
25  import java.awt.Dimension;
26  import java.awt.Rectangle;
27  import java.awt.event.ActionEvent;
28  import java.awt.event.ComponentAdapter;
29  import java.awt.event.ComponentEvent;
30  import java.awt.event.MouseEvent;
31  import java.awt.event.MouseMotionAdapter;
32  
33  import javax.swing.AbstractAction;
34  import javax.swing.JTable;
35  import javax.swing.JViewport;
36  import javax.swing.table.DefaultTableModel;
37  import javax.swing.table.JTableHeader;
38  import javax.swing.table.TableModel;
39  
40  import no.sintef.event.Concentrator;
41  import no.sintef.util.StringUtils;
42  
43  import org.apache.log4j.Logger;
44  
45  /***
46   * @author fvr
47   *
48   * To change the template for this generated type comment go to
49   * Window - Preferences - Java - Code Generation - Code and Comments
50   */
51  public class CorasTable extends JTable {
52  
53  	public static final String NAMESPACE_URI = "http://coras.sourceforge.net/schemas/coras-table-1_0.xsd"; //$NON-NLS-1$ 
54  	public static final String PREFIX = "coras-table"; //$NON-NLS-1$ 
55  
56  	private static final Logger LOGGER = Logger.getLogger(CorasTable.class);
57  	
58  	private static final String HTML_START = "<html>"; //$NON-NLS-1$ 
59  	private static final String HTML_END = "</html>"; //$NON-NLS-1$ 
60  
61  	private TextAreaRenderer textAreaRenderer = new TextAreaRenderer();
62  	private TextAreaEditor textAreaEditor = new TextAreaEditor();
63  	private CorasTableModel tableModel = null;
64  
65  	public CorasTable() {
66  		super();
67  		initialize();
68  
69  		textAreaEditor.setNextAction(new AbstractAction() {
70  			public void actionPerformed(ActionEvent e) {
71  				editNextColumn();
72  			}
73  		});
74  		textAreaEditor.setPrevAction(new AbstractAction() {
75  			public void actionPerformed(ActionEvent e) {
76  				editPrevColumn();
77  			}
78  		});
79  		textAreaEditor.setUpAction(new AbstractAction() {
80  			public void actionPerformed(ActionEvent e) {
81  				editPrevRow();
82  			}
83  		});
84  		textAreaEditor.setDownAction(new AbstractAction() {
85  			public void actionPerformed(ActionEvent e) {
86  				editNextRow();
87  			}
88  		});
89  //		getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), nextColumnAction);
90  		
91  		getTableHeader().addMouseMotionListener(new MouseMotionAdapter() {
92  			public void mouseDragged(MouseEvent e) {
93  				updateRowHeights();
94  			}
95  		});
96  		
97  		addComponentListener(new ComponentAdapter() {
98  			public void componentResized(ComponentEvent e) {
99  				updateRowHeights();
100 			}
101 		});
102 	}
103 	
104 	/***
105 	 * 
106 	 */
107 	protected void editNextColumn() {
108 		// fireEditingStopped();
109 		int newRow = editingRow;
110 		int newColumn = editingColumn + 1;
111 		if (newColumn == getColumnCount()) {
112 			newRow++;
113 			newColumn = 0;
114 		}
115 		editCellAt(newRow, newColumn);
116 		changeSelection(newRow, newColumn, false, false);
117 		scrollToEditingCell();
118 	}
119 	
120 	protected void editPrevColumn() {
121 		int newRow = editingRow;
122 		int newColumn = editingColumn - 1;
123 		if (newColumn == -1) {
124 			newRow--;
125 			newColumn = getColumnCount() - 1;
126 		}
127 		if (newRow != -1) {
128 			editCellAt(newRow, newColumn);
129 			changeSelection(newRow, newColumn, false, false);
130 			scrollToEditingCell();
131 		}
132 	}
133 	
134 	protected void editNextRow() {
135 		int newRow = editingRow + 1;
136 		editCellAt(newRow, editingColumn);
137 		changeSelection(newRow, editingColumn, false, false);
138 		scrollToEditingCell();
139 	}
140 	
141 	protected void editPrevRow() {
142 		int newRow = editingRow - 1;
143 		if (newRow != -1) {
144 			editCellAt(newRow, editingColumn);
145 			changeSelection(newRow, editingColumn, false, false);
146 			scrollToEditingCell();
147 		}
148 	}
149 	
150 	private void scrollToEditingCell() {
151 		Component component = getEditorComponent();
152 		if (component == null) {
153             return;
154         }
155 		Rectangle bounds = component.getBounds();
156 		Container parent = getParent();
157 		JViewport viewport = (JViewport) parent;
158 		viewport.scrollRectToVisible(bounds);
159 	}
160 	
161 	public void setTableModel(CorasTableModel newModel) {
162 		tableModel = newModel;
163 		if (newModel != null) {
164 			setModel(newModel);
165 		} else {
166 			setModel(new DefaultTableModel());
167 		}
168 		updateRowHeights();
169 	}
170 	
171 	/***
172 	 * 
173 	 */
174 	public void addRow() {
175 	    textAreaEditor.stopCellEditing();
176 		tableModel.addRow(tableModel.getRowCount());
177 	}
178 
179 	public void insertRowAboveSelectedRow() {
180 	    textAreaEditor.stopCellEditing();
181 		int rowIndex = getSelectedRow();
182 		if (rowIndex == -1)
183 			rowIndex = 0; // Insert row at top
184 		tableModel.addRow(rowIndex);
185 	}
186 
187 	public void insertRowBelowSelectedRow() {
188 	    textAreaEditor.stopCellEditing();
189 		int rowIndex = getSelectedRow() + 1;
190 		if (rowIndex == 0)
191 			rowIndex = tableModel.getRowCount(); // Insert row at bottom
192 		tableModel.addRow(rowIndex);
193 	}
194 	
195 	public void deleteSelectedRow() {
196 	    textAreaEditor.cancelCellEditing();
197 		tableModel.deleteRow(getSelectedRow());
198 	}
199 
200 	private void initialize() {
201 		this.setCellSelectionEnabled(true);
202 		this.setDefaultRenderer(String.class, textAreaRenderer);
203 		this.setDefaultEditor(String.class, textAreaEditor);
204 	}
205 
206 	private Concentrator updateConcentrator = new Concentrator(100, new Runnable() {
207 		public void run() {
208 			doUpdateRowHeights();
209 		}
210 	});
211 	
212 	/***
213 	 * 
214 	 */
215 	protected void updateRowHeights() {
216 		updateConcentrator.fireEvent();
217 	}
218 	
219 	private void doUpdateRowHeights() {
220 		TableModel model = getModel();
221 		for (int i = 0; i < model.getRowCount(); i++) {
222 			updateRowHeight(i);
223 		}
224 	}
225 
226 	protected void updateRowHeight(int row) {
227 		int preferredHeight = computePreferredRowHeight(row);
228 		if (preferredHeight != getRowHeight(row)) {
229 			setRowHeight(row, preferredHeight);
230 		}
231 	}
232 
233 	/***
234 	 * @param table
235 	 * @param row
236 	 */
237 	protected int computePreferredRowHeight(int row) {
238 		int preferredHeight = 0;
239 		TableModel tableModel = getModel();
240 		int columnCount = tableModel.getColumnCount();
241 		for (int col = 0; col < columnCount; col++) {
242 			Rectangle rect = getCellRect(row, col, false);
243 			Dimension preferredSize;
244 			if (row == getEditingRow() && col == getEditingColumn()) {
245 				preferredSize = textAreaEditor.getPreferredSize();
246 			} else {
247 				Object value = getValueAt(row, col);
248 				Component c = textAreaRenderer.getTableCellRendererComponent(this, value, false, false, row, col);
249 				c.setSize(rect.width, rect.height);
250 				preferredSize = c.getPreferredSize();
251 			}
252 			if (preferredSize.height > preferredHeight)
253 				preferredHeight = preferredSize.height;
254 		}
255 		return preferredHeight + getIntercellSpacing().height;
256 	}
257 	
258     //Implement table header tool tips. 
259     protected JTableHeader createDefaultTableHeader() {
260     	return new JTableHeader(getColumnModel()) {
261     		private final int MAX_LINE_LENGTH = 80;
262     		
263             public String getToolTipText(MouseEvent e) {
264                 java.awt.Point p = e.getPoint();
265                 int index = getColumnModel().getColumnIndexAtX(p.x);
266                 int realIndex = getColumnModel().getColumn(index).getModelIndex();
267                 
268                 String tip = tableModel.getColumnDescription(realIndex);
269                 if (tip == null || tip.trim().length() == 0) {
270 					tip = ""; //$NON-NLS-1$ 
271 				} else {
272 					tip = Messages.getString("CorasTable.column_description") + ' ' + tip.trim(); //$NON-NLS-1$
273 				}
274                 if (tableModel.isFixedStructure()) {
275                 	tip = Messages.getString("CorasTable.right_click_column_header_fixed_table") + tip; //$NON-NLS-1$
276                 } else {
277                 	tip = Messages.getString("CorasTable.right_click_column_header") + tip; //$NON-NLS-1$
278                 }
279                 tip = HTML_START + StringUtils.addLinebreaks(tip, MAX_LINE_LENGTH) + HTML_END;
280                 return tip;
281             }
282             
283         };
284 
285     }
286 	
287 }