svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.fmap.control / src / main / java / org / gvsig / fmap / mapcontrol / dal / feature / swing / FeatureTablePanel.java @ 47421
History | View | Annotate | Download (13 KB)
1 | 40559 | jjdelcerro | /**
|
---|---|---|---|
2 | * gvSIG. Desktop Geographic Information System.
|
||
3 | 40435 | jjdelcerro | *
|
4 | 40559 | jjdelcerro | * Copyright (C) 2007-2013 gvSIG Association.
|
5 | 40435 | jjdelcerro | *
|
6 | * This program is free software; you can redistribute it and/or
|
||
7 | * modify it under the terms of the GNU General Public License
|
||
8 | 40559 | jjdelcerro | * as published by the Free Software Foundation; either version 3
|
9 | 40435 | jjdelcerro | * 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 | 41621 | jjdelcerro | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 | 40435 | jjdelcerro | * GNU General Public License for more details.
|
15 | *
|
||
16 | * You should have received a copy of the GNU General Public License
|
||
17 | * along with this program; if not, write to the Free Software
|
||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||
19 | 41621 | jjdelcerro | * MA 02110-1301, USA.
|
20 | 40435 | jjdelcerro | *
|
21 | 40559 | jjdelcerro | * For any additional information, do not hesitate to contact us
|
22 | * at info AT gvsig.com, or visit our website www.gvsig.com.
|
||
23 | 40435 | jjdelcerro | */
|
24 | /*
|
||
25 | * AUTHORS (In addition to CIT):
|
||
26 | * 2008 {DiSiD Technologies} {Create a Table component for Features}
|
||
27 | */
|
||
28 | package org.gvsig.fmap.mapcontrol.dal.feature.swing; |
||
29 | |||
30 | import java.awt.BorderLayout; |
||
31 | 41611 | jjdelcerro | import java.awt.Component; |
32 | 41621 | jjdelcerro | import java.awt.Dimension; |
33 | import java.beans.PropertyChangeEvent; |
||
34 | import java.beans.PropertyChangeListener; |
||
35 | 41611 | jjdelcerro | import javax.swing.AbstractListModel; |
36 | import javax.swing.JButton; |
||
37 | 40435 | jjdelcerro | import javax.swing.JLabel; |
38 | 41611 | jjdelcerro | import javax.swing.JList; |
39 | 40435 | jjdelcerro | import javax.swing.JPanel; |
40 | import javax.swing.JScrollPane; |
||
41 | 41611 | jjdelcerro | import javax.swing.JTable; |
42 | import javax.swing.ListCellRenderer; |
||
43 | import javax.swing.ListModel; |
||
44 | 41621 | jjdelcerro | import javax.swing.SwingUtilities; |
45 | 41611 | jjdelcerro | import javax.swing.UIManager; |
46 | 41621 | jjdelcerro | import javax.swing.event.TableModelEvent; |
47 | import javax.swing.event.TableModelListener; |
||
48 | 41611 | jjdelcerro | import javax.swing.table.JTableHeader; |
49 | 41621 | jjdelcerro | import javax.swing.table.TableModel; |
50 | 40435 | jjdelcerro | import org.gvsig.fmap.dal.DataStoreNotification; |
51 | import org.gvsig.fmap.dal.exception.DataException; |
||
52 | import org.gvsig.fmap.dal.feature.Feature; |
||
53 | import org.gvsig.fmap.dal.feature.FeatureQuery; |
||
54 | import org.gvsig.fmap.dal.feature.FeatureStore; |
||
55 | import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.ConfigurableFeatureTableModel; |
||
56 | import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FeatureTableConfigurationPanel; |
||
57 | import org.gvsig.i18n.Messages; |
||
58 | 46761 | jjdelcerro | import org.gvsig.tools.ToolsLocator; |
59 | 40435 | jjdelcerro | import org.gvsig.tools.exception.BaseException; |
60 | 46761 | jjdelcerro | import org.gvsig.tools.i18n.I18nManager; |
61 | 40435 | jjdelcerro | import org.gvsig.tools.observer.Observable; |
62 | import org.gvsig.tools.observer.Observer; |
||
63 | 41621 | jjdelcerro | import org.slf4j.Logger; |
64 | import org.slf4j.LoggerFactory; |
||
65 | 40435 | jjdelcerro | |
66 | /**
|
||
67 | * Panel to show a table of Feature data.
|
||
68 | 41621 | jjdelcerro | *
|
69 | 40435 | jjdelcerro | * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
|
70 | */
|
||
71 | public class FeatureTablePanel extends JPanel implements Observer { |
||
72 | |||
73 | 41621 | jjdelcerro | private static final Logger logger = LoggerFactory.getLogger(FeatureTablePanel.class); |
74 | |||
75 | 40435 | jjdelcerro | private static final long serialVersionUID = -9199073063283531216L; |
76 | |||
77 | private ConfigurableFeatureTableModel tableModel;
|
||
78 | |||
79 | private JScrollPane jScrollPane = null; |
||
80 | |||
81 | private FeatureTable table = null; |
||
82 | private JPanel selectionPanel; |
||
83 | private JLabel selectionLabel; |
||
84 | |||
85 | /**
|
||
86 | * Constructs a Panel to show a table with the features of a FeatureStore.
|
||
87 | 41621 | jjdelcerro | *
|
88 | 40435 | jjdelcerro | * @param featureStore
|
89 | 41621 | jjdelcerro | * to extract the features from
|
90 | 40435 | jjdelcerro | * @throws BaseException
|
91 | 41621 | jjdelcerro | * if there is an error reading data from the FeatureStore
|
92 | 40435 | jjdelcerro | */
|
93 | public FeatureTablePanel(FeatureStore featureStore) throws BaseException { |
||
94 | this(featureStore, true); |
||
95 | } |
||
96 | |||
97 | /**
|
||
98 | * Constructs a Panel to show a table with the features of a FeatureStore.
|
||
99 | 41621 | jjdelcerro | *
|
100 | 40435 | jjdelcerro | * @param featureStore
|
101 | 41621 | jjdelcerro | * to extract the features from
|
102 | 40435 | jjdelcerro | * @param isDoubleBuffered
|
103 | 41621 | jjdelcerro | * a boolean, true for double-buffering, which uses additional
|
104 | * memory space to achieve fast, flicker-free updates
|
||
105 | 40435 | jjdelcerro | * @throws BaseException
|
106 | 41621 | jjdelcerro | * if there is an error reading data from the FeatureStore
|
107 | 40435 | jjdelcerro | */
|
108 | public FeatureTablePanel(FeatureStore featureStore, boolean isDoubleBuffered) |
||
109 | 41621 | jjdelcerro | throws BaseException {
|
110 | 40435 | jjdelcerro | this(featureStore, null, isDoubleBuffered); |
111 | } |
||
112 | |||
113 | /**
|
||
114 | * @throws BaseException
|
||
115 | 41621 | jjdelcerro | *
|
116 | 40435 | jjdelcerro | */
|
117 | public FeatureTablePanel(FeatureStore featureStore,
|
||
118 | 41621 | jjdelcerro | FeatureQuery featureQuery) throws BaseException {
|
119 | 40435 | jjdelcerro | this(featureStore, featureQuery, true); |
120 | } |
||
121 | |||
122 | /**
|
||
123 | * @param isDoubleBuffered
|
||
124 | * @throws BaseException
|
||
125 | */
|
||
126 | public FeatureTablePanel(FeatureStore featureStore,
|
||
127 | 41621 | jjdelcerro | FeatureQuery featureQuery, boolean isDoubleBuffered)
|
128 | throws BaseException {
|
||
129 | 40435 | jjdelcerro | this(createModel(featureStore, featureQuery));
|
130 | } |
||
131 | |||
132 | public FeatureTablePanel(ConfigurableFeatureTableModel tableModel)
|
||
133 | 41621 | jjdelcerro | throws DataException {
|
134 | 40435 | jjdelcerro | this(tableModel, true); |
135 | } |
||
136 | |||
137 | public FeatureTablePanel(ConfigurableFeatureTableModel tableModel,
|
||
138 | 41621 | jjdelcerro | boolean isDoubleBuffered) throws DataException { |
139 | 40435 | jjdelcerro | super(isDoubleBuffered);
|
140 | this.tableModel = tableModel;
|
||
141 | this.setLayout(new BorderLayout()); |
||
142 | this.add(getJScrollPane(), BorderLayout.CENTER); |
||
143 | this.add(getSelectionPanel(), BorderLayout.SOUTH); |
||
144 | tableModel.getFeatureStore().addObserver(this);
|
||
145 | } |
||
146 | |||
147 | private JPanel getSelectionPanel() { |
||
148 | 41621 | jjdelcerro | if ( selectionPanel == null ) { |
149 | 46761 | jjdelcerro | I18nManager i18n = ToolsLocator.getI18nManager(); |
150 | 40435 | jjdelcerro | selectionLabel = new JLabel(); |
151 | selectionLabel.setText(getFeatureSelectionSize() + " / "
|
||
152 | 41621 | jjdelcerro | + getTableModel().getHelper().getTotalSize() + " "
|
153 | 46761 | jjdelcerro | + i18n.getTranslation("registros_seleccionados_total") + "."); |
154 | FeatureStore store = this.getTableModel().getFeatureStore();
|
||
155 | if( store!=null ) { |
||
156 | selectionLabel.setToolTipText( |
||
157 | "<html>" +
|
||
158 | i18n.getTranslation("_Table") + ": " + store.getName() +"<br>\n"+ |
||
159 | "( "+store.getFullName() + " )" + |
||
160 | "</html>"
|
||
161 | ); |
||
162 | } |
||
163 | 40435 | jjdelcerro | selectionPanel = new JPanel(); |
164 | selectionPanel.add(selectionLabel, BorderLayout.EAST);
|
||
165 | } |
||
166 | return selectionPanel;
|
||
167 | } |
||
168 | |||
169 | private void updateSelection() { |
||
170 | 47421 | fdiaz | selectionLabel.setText(getFeatureSelectionSize() + " / "
|
171 | 41621 | jjdelcerro | + getTableModel().getRowCount() + " "
|
172 | + Messages.getText("registros_seleccionados_total") + "."); |
||
173 | 40435 | jjdelcerro | } |
174 | |||
175 | private long getFeatureSelectionSize() { |
||
176 | try {
|
||
177 | return getFeatureStore().getFeatureSelection().getSize();
|
||
178 | } catch (DataException e) {
|
||
179 | throw new RuntimeException("Error updating selection information", |
||
180 | 41621 | jjdelcerro | e); |
181 | 40435 | jjdelcerro | } |
182 | } |
||
183 | |||
184 | public JPanel createConfigurationPanel() { |
||
185 | return new FeatureTableConfigurationPanel(tableModel); |
||
186 | } |
||
187 | |||
188 | /**
|
||
189 | * Returns the internal Table Model for the Features of the FeatureStore.
|
||
190 | 41621 | jjdelcerro | *
|
191 | 40435 | jjdelcerro | * @return the internal Table Model
|
192 | */
|
||
193 | public ConfigurableFeatureTableModel getTableModel() {
|
||
194 | return tableModel;
|
||
195 | } |
||
196 | |||
197 | /**
|
||
198 | * Returns the {@link FeatureStore} of the {@link Feature}s being shown in
|
||
199 | * the table.
|
||
200 | 41621 | jjdelcerro | *
|
201 | 40435 | jjdelcerro | * @return the store of the features
|
202 | */
|
||
203 | public FeatureStore getFeatureStore() {
|
||
204 | return getTableModel().getFeatureStore();
|
||
205 | } |
||
206 | |||
207 | /**
|
||
208 | * Returns the FeatureQuery used to get the Features.
|
||
209 | 41621 | jjdelcerro | *
|
210 | 40435 | jjdelcerro | * @return the FeatureQuery
|
211 | */
|
||
212 | public FeatureQuery getFeatureQuery() {
|
||
213 | return getTableModel().getFeatureQuery();
|
||
214 | } |
||
215 | |||
216 | /**
|
||
217 | * Sets that the selected Features to be viewed first.
|
||
218 | */
|
||
219 | public void setSelectionUp(boolean selectionUp) { |
||
220 | try {
|
||
221 | getTable().setSelectionUp(selectionUp); |
||
222 | } catch (DataException e) {
|
||
223 | throw new RuntimeException("Error setting the selection up", e); |
||
224 | } |
||
225 | } |
||
226 | |||
227 | private static ConfigurableFeatureTableModel createModel( |
||
228 | 41621 | jjdelcerro | FeatureStore featureStore, FeatureQuery featureQuery) |
229 | throws BaseException {
|
||
230 | FeatureQuery query |
||
231 | = featureQuery == null ? featureStore.createFeatureQuery()
|
||
232 | 40435 | jjdelcerro | : featureQuery; |
233 | |||
234 | return new ConfigurableFeatureTableModel(featureStore, query); |
||
235 | } |
||
236 | |||
237 | public FeatureTable getTable() throws DataException { |
||
238 | 41621 | jjdelcerro | if ( table == null ) { |
239 | 40435 | jjdelcerro | table = new FeatureTable(tableModel);
|
240 | // Change the selection model to link with the FeatureStore
|
||
241 | // selection
|
||
242 | // through the FeatureTableModel
|
||
243 | table.setRowSelectionAllowed(true);
|
||
244 | table.setColumnSelectionAllowed(false);
|
||
245 | // table.setSelectionModel(new FeatureSelectionModel(tableModel));
|
||
246 | } |
||
247 | return table;
|
||
248 | } |
||
249 | |||
250 | /**
|
||
251 | * This method initializes jScrollPane
|
||
252 | 41621 | jjdelcerro | *
|
253 | 40435 | jjdelcerro | * @return javax.swing.JScrollPane
|
254 | * @throws DataException
|
||
255 | */
|
||
256 | private JScrollPane getJScrollPane() throws DataException { |
||
257 | 41621 | jjdelcerro | if ( jScrollPane == null ) { |
258 | 41611 | jjdelcerro | FeatureTable theTable = getTable(); |
259 | 40435 | jjdelcerro | jScrollPane = new JScrollPane(); |
260 | 41611 | jjdelcerro | jScrollPane.setViewportView(theTable); |
261 | 41621 | jjdelcerro | createTheRowHeader(); |
262 | theTable.addPropertyChangeListener(new PropertyChangeListener() { |
||
263 | public void propertyChange(PropertyChangeEvent pce) { |
||
264 | if( "RowHeight".equalsIgnoreCase(pce.getPropertyName())) { |
||
265 | // No he averigado como cambiar el ancho de las lineas
|
||
266 | // ya creadas de la cabezera de lineas, asi que la
|
||
267 | // reconstruyo entera cuando algo cambia.
|
||
268 | createTheRowHeader(); |
||
269 | } |
||
270 | } |
||
271 | }); |
||
272 | TableModel model = theTable.getModel();
|
||
273 | model.addTableModelListener(new TableModelListener() { |
||
274 | public void tableChanged(TableModelEvent tme) { |
||
275 | // No he averigado como cambiar el ancho de las lineas
|
||
276 | // ya creadas de la cabezera de lineas, asi que la
|
||
277 | // reconstruyo entera cuando algo cambia.
|
||
278 | createTheRowHeader(); |
||
279 | } |
||
280 | }); |
||
281 | 40435 | jjdelcerro | } |
282 | return jScrollPane;
|
||
283 | } |
||
284 | |||
285 | 41621 | jjdelcerro | void createTheRowHeader() {
|
286 | // No se si ha sido paranoia o que, pero parece que si la recreo sin mas
|
||
287 | // a veces parece como si no la cambiase, asi que he probado a encolarlo
|
||
288 | // en la cola de eventos de swing y parece que siempre funciona.
|
||
289 | //
|
||
290 | // Cuando se estan mostrando las geometrias, que cada linea tiene un ancho
|
||
291 | // distinto, se le llama muchisimas veces;
|
||
292 | // habria que evaluar retenerlas por ejemplo durante un segundo y solo
|
||
293 | // recrearlo entonces.
|
||
294 | SwingUtilities.invokeLater(new Runnable() { |
||
295 | |||
296 | public void run() { |
||
297 | ListModel lm = new AbstractListModel() { |
||
298 | public int getSize() { |
||
299 | return table.getRowCount();
|
||
300 | } |
||
301 | |||
302 | public Object getElementAt(int index) { |
||
303 | return String.valueOf(index + 1); |
||
304 | } |
||
305 | }; |
||
306 | final JList rowHeader = new JList(lm); |
||
307 | 41707 | jjdelcerro | rowHeader.setBackground(table.getTableHeader().getBackground()); |
308 | 41830 | jjdelcerro | rowHeader.setCellRenderer(new RowHeaderRenderer(table,rowHeader));
|
309 | 41621 | jjdelcerro | jScrollPane.setRowHeaderView(rowHeader); |
310 | } |
||
311 | }); |
||
312 | } |
||
313 | |||
314 | 41611 | jjdelcerro | private static class RowHeaderRenderer extends JButton implements ListCellRenderer { |
315 | 41621 | jjdelcerro | private JTable table = null; |
316 | private final Dimension dimension = new Dimension(); |
||
317 | 41830 | jjdelcerro | private JList rowHeader; |
318 | |||
319 | RowHeaderRenderer(JTable table,JList rowHeader) { |
||
320 | 41621 | jjdelcerro | JTableHeader header = table.getTableHeader();
|
321 | setOpaque(true);
|
||
322 | setBorder(UIManager.getBorder("TableHeader.cellBorder")); |
||
323 | setHorizontalAlignment(CENTER); |
||
324 | setForeground(header.getForeground()); |
||
325 | setBackground(header.getBackground()); |
||
326 | setFont(header.getFont()); |
||
327 | this.table = table;
|
||
328 | 41830 | jjdelcerro | this.rowHeader = rowHeader;
|
329 | 41611 | jjdelcerro | } |
330 | |||
331 | public Component getListCellRendererComponent(JList list, Object value, |
||
332 | 41621 | jjdelcerro | int index, boolean isSelected, boolean cellHasFocus) { |
333 | setText((value == null) ? "" : value.toString()); |
||
334 | 41830 | jjdelcerro | this.setPreferredSize(null); // Fuerza recalcular el tama?o del boton |
335 | 41621 | jjdelcerro | this.dimension.height = this.table.getRowHeight(index); |
336 | 41830 | jjdelcerro | this.dimension.width = this.getPreferredSize().width+10; |
337 | 41621 | jjdelcerro | this.setPreferredSize(this.dimension); |
338 | return this; |
||
339 | 41611 | jjdelcerro | } |
340 | 41621 | jjdelcerro | |
341 | 41611 | jjdelcerro | } |
342 | |||
343 | 40435 | jjdelcerro | public void update(Observable observable, Object notification) { |
344 | // If selection changes from nothing selected to anything selected
|
||
345 | // or the reverse, update selection info
|
||
346 | 41621 | jjdelcerro | if ( notification instanceof DataStoreNotification ) { |
347 | 40435 | jjdelcerro | String type = ((DataStoreNotification) notification).getType();
|
348 | 41621 | jjdelcerro | if ( DataStoreNotification.SELECTION_CHANGE.equals(type) ) {
|
349 | 40435 | jjdelcerro | updateSelection(); |
350 | } |
||
351 | } |
||
352 | } |
||
353 | // public void valueChanged(ListSelectionEvent e) {
|
||
354 | // updateSelection();
|
||
355 | // updateUI();
|
||
356 | // }
|
||
357 | //
|
||
358 | // public void tableChanged(TableModelEvent e) {
|
||
359 | // updateSelection();
|
||
360 | // updateUI();
|
||
361 | // }
|
||
362 | } |