Statistics
| Revision:

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 / FeatureTable.java @ 45779

History | View | Annotate | Download (12.4 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
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
 * as published by the Free Software Foundation; either version 3
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
14
 * 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
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.mapcontrol.dal.feature.swing;
25

    
26
import java.awt.Color;
27
import java.awt.Component;
28
import java.awt.event.KeyAdapter;
29
import java.awt.event.KeyEvent;
30
import java.sql.Timestamp;
31
import java.util.Date;
32
import java.util.Objects;
33

    
34
import javax.swing.JTable;
35
import javax.swing.event.ChangeEvent;
36
import javax.swing.event.TableModelEvent;
37
import javax.swing.table.TableCellRenderer;
38
import javax.swing.table.TableColumn;
39
import javax.swing.table.TableColumnModel;
40
import javax.swing.table.TableModel;
41
import org.apache.commons.lang3.StringUtils;
42

    
43
import org.gvsig.fmap.dal.exception.DataException;
44
import org.gvsig.fmap.dal.feature.Feature;
45
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
46
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
47
import org.gvsig.fmap.geom.Geometry;
48
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.ConfigurableFeatureTableModel;
49
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FeatureAttributeCellRenderer;
50
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FeatureCellRenderer;
51
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FeatureTableModel;
52
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FormattedCellEditor;
53
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FormattedCellRenderer;
54
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.GeometryWKTCellEditor;
55
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.GeometryWKTCellRenderer;
56
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.JToggleButtonHeaderCellRenderer;
57
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.notification.ColumnHeaderSelectionChangeNotification;
58
import org.gvsig.tools.observer.Observable;
59
import org.gvsig.tools.observer.Observer;
60
import org.gvsig.tools.swing.api.ToolsSwingLocator;
61
import org.slf4j.Logger;
62
import org.slf4j.LoggerFactory;
63

    
64
/**
65
 * Table extension to show Feature values.
66
 *
67
 * It's based on the usage of a FeatureTableModel, and adds renderers for
68
 * Geometry and Feature cell values.
69
 *
70
 * Observers are notified about column header selection changes, with a
71
 * {@link ColumnHeaderSelectionChangeNotification}.
72
 *
73
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
74
 */
75
@SuppressWarnings("UseSpecificCatch")
76
public class FeatureTable extends JTable implements Observer, Observable {
77

    
78
    private static final Logger LOGGER = LoggerFactory.getLogger(FeatureTable.class);
79
    /**
80
     * Generated Serial UID
81
     */
82
    private static final long serialVersionUID = -6139395189283163964L;
83

    
84
    
85
    private final FeatureTableModel featureTableModel;
86
    private JToggleButtonHeaderCellRenderer headerCellRenderer;
87

    
88
        private static final int COLUMN_HEADER_MARGIN = 8;
89

    
90
        private static final int COLUMN_HEADER_MIN_WIDTH = 50;
91

    
92
    /**
93
     * Creates a new FeatureTable with a {@link FeatureTableModel}.
94
     *
95
     * @param featureTableModel
96
     *            the table model to get data to be shown on the table
97
     * @throws DataException
98
     *             if there is an error while loading the Features to show
99
     * @see JTable#JTable(TableModel)
100
     */
101
    public FeatureTable(FeatureTableModel featureTableModel)
102
            throws DataException {
103
        super(featureTableModel);
104
        this.featureTableModel = featureTableModel;
105
        init();
106
    }
107

    
108
    /**
109
     * Creates a new FeatureTable with a {@link FeatureTableModel}.
110
     *
111
     * @param featureTableModel
112
     *            the table model to get data to be shown on the table
113
     * @param cm
114
     *            the table column model to use
115
     * @throws DataException
116
     *             if there is an error while loading the Features to show
117
     * @see JTable#JTable(TableModel, TableColumnModel)
118
     */
119
    public FeatureTable(FeatureTableModel featureTableModel, TableColumnModel cm)
120
            throws DataException {
121
        super(featureTableModel, cm);
122
        this.featureTableModel = featureTableModel;
123
        init();
124
    }
125

    
126
    @Override
127
    public void update(Observable observable, Object notification) {
128
        if (notification instanceof FeatureStoreNotification) {
129
            FeatureStoreNotification fsNotification = (FeatureStoreNotification) notification;
130
            String type = fsNotification.getType();
131
            // If the selection has changed, repaint the table to show the new
132
            // selected rows
133
            if (FeatureStoreNotification.SELECTION_CHANGE.equals(type)) {
134
                repaint();
135
            }
136

    
137
            /*
138
             * This is necessary to let Swing know
139
             * that editing (in terms of Swing, not gvsig editing)
140
             * must be cancelled because the deleted row
141
             * is perhaps the row that was being edited
142
             */
143
            if (FeatureStoreNotification.BEFORE_DELETE.equals(type)) {
144
                if (this.isEditing()) {
145
                    ChangeEvent che = new ChangeEvent(this);
146
                    this.editingCanceled(che);
147
                }
148
            }
149
        }
150
    }
151

    
152
    /**
153
     * Returns the FeatureAttributeDescriptor related to the selected columns.
154
     *
155
     * @return an array of FeatureAttributeDescriptor
156
     *
157
     * @see org.gvsig.fmap.mapcontrol.dal.feature.swing.table.JToggleButtonHeaderCellRenderer#getSelectedColumns()
158
     */
159
    public FeatureAttributeDescriptor[] getSelectedColumnsAttributeDescriptor() {
160
        int[] columns = headerCellRenderer.getSelectedColumns();
161
        FeatureAttributeDescriptor[] descriptors = new FeatureAttributeDescriptor[columns.length];
162

    
163
        for (int i = 0; i < descriptors.length; i++) {
164
            descriptors[i] = featureTableModel
165
                    .getDescriptorForColumn(columns[i]);
166
        }
167

    
168
        return descriptors;
169
    }
170

    
171
    @Override
172
    public void addObserver(Observer observer) {
173
        headerCellRenderer.addObserver(observer);
174
    }
175

    
176
    @Override
177
    public void deleteObserver(Observer observer) {
178
        headerCellRenderer.deleteObserver(observer);
179
    }
180

    
181
    @Override
182
    public void deleteObservers() {
183
        headerCellRenderer.deleteObservers();
184
    }
185

    
186
        /**
187
         * Sets that the selected Features to be viewed first.
188
     * @param selectionUp
189
         */
190
        public void setSelectionUp(boolean selectionUp) {
191
                ((FeatureTableModel) getModel()).setSelectionUp(selectionUp);
192
                scrollRectToVisible(getCellRect(0, 0, true));
193
        }
194

    
195
    // @Override
196
    // public void tableChanged(TableModelEvent e) {
197
    // super.tableChanged(e);
198
    // if (headerCellRenderer != null) {
199
    // headerCellRenderer.deselectAll();
200
    // }
201
    // }
202

    
203
    @Override
204
    protected void initializeLocalVars() {
205
        super.initializeLocalVars();
206
        // Add a cell renderer for Geometries and Features
207
        setDefaultRenderer(Geometry.class, new GeometryWKTCellRenderer());
208
        setDefaultEditor(Geometry.class, new GeometryWKTCellEditor());
209
        setDefaultRenderer(Feature.class, new FeatureCellRenderer());
210

    
211
        if( this.getModel() instanceof ConfigurableFeatureTableModel ) {
212
            ConfigurableFeatureTableModel model = (ConfigurableFeatureTableModel)this.getModel();
213
            setDefaultRenderer(Double.class, new FormattedCellRenderer(model));
214
            setDefaultRenderer(Float.class, new FormattedCellRenderer(model));
215
            setDefaultRenderer(Integer.class, new FormattedCellRenderer(model));
216
            setDefaultRenderer(Long.class, new FormattedCellRenderer(model));
217
            setDefaultRenderer(Date.class, new FormattedCellRenderer(model));
218
            setDefaultRenderer(String.class, new FeatureAttributeCellRenderer(model));
219
            setDefaultEditor(Double.class, new FormattedCellEditor(model));
220
            setDefaultEditor(Float.class, new FormattedCellEditor(model));
221
            setDefaultEditor(Integer.class, new FormattedCellEditor(model));
222
            setDefaultEditor(Long.class, new FormattedCellEditor(model));
223
            setDefaultEditor(Date.class, new FormattedCellEditor(model));
224
        }
225

    
226
        // Set the selected row colors
227
        setSelectionForeground(Color.blue);
228
        setSelectionBackground(Color.yellow);
229
    }
230

    
231
    /**
232
     * Initializes the table GUI.
233
     */
234
    private void init() throws DataException {
235
      setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
236

    
237
      featureTableModel.getFeatureStore().addObserver(this);
238
      // Change the selection model to link with the FeatureStore selection
239
      // through the FeatureTableModel
240
      setRowSelectionAllowed(true);
241
      setColumnSelectionAllowed(false);
242
      setSelectionModel(new FeatureSelectionModel(featureTableModel));
243

    
244
      headerCellRenderer = new JToggleButtonHeaderCellRenderer(this);
245
      getTableHeader().setDefaultRenderer(headerCellRenderer);
246

    
247
      TableColumnModel tcmodel = getColumnModel();
248
      for (int i = 0; i < tcmodel.getColumnCount(); i++) {
249
        TableColumn col = tcmodel.getColumn(i);
250
        // Get width of column header
251
        TableCellRenderer renderer = col.getHeaderRenderer();
252
        if (renderer == null) {
253
          renderer = getTableHeader().getDefaultRenderer();
254
        }
255
        Component comp
256
                = renderer.getTableCellRendererComponent(this,
257
                        col.getHeaderValue(), false, false, 0, i);
258
        int width = comp.getPreferredSize().width;
259
        width
260
                = width < COLUMN_HEADER_MIN_WIDTH ? COLUMN_HEADER_MIN_WIDTH
261
                        : width;
262
        col.setPreferredWidth(width + 2 * COLUMN_HEADER_MARGIN);
263
      }
264
      try {
265
        if( !this.featureTableModel.getFeatureStore().getFeatureSelection().isAvailable() ) {
266
          this.setSelectionBackground(Color.PINK);
267
        }
268
      } catch(Exception ex) {
269
        LOGGER.warn("Can't check if selecction is available.", ex);
270
      }
271
        this.addKeyListener(new KeyAdapter() {
272
            @Override
273
            public void keyPressed(KeyEvent e) {
274
                if( e.getKeyCode()==KeyEvent.VK_F4 ) {
275
                    doShowCellInDialog();
276
                }
277
            }
278
        });
279
      
280
    }
281
    private void doShowCellInDialog() {
282
        int row = this.getSelectedRow();
283
        if( row < 0 ) {
284
            return;
285
        }
286
        int col = this.getSelectedColumn();
287
        if( col < 0 ) {
288
            return;
289
        }
290
        String s = Objects.toString(this.getValueAt(row, col),null);
291
        if( StringUtils.isBlank(s) ) {
292
            return;
293
        }
294
        ToolsSwingLocator.getToolsSwingManager().showZoomDialog(
295
            this, 
296
            this.getColumnName(col), 
297
            s,
298
            false
299
        );
300
    }
301

    
302

    
303
    /**
304
     * Returns the number of selected columns.
305
     *
306
     * @return the number of selected columns, 0 if no columns are selected
307
     */
308
    @Override
309
    public int getSelectedColumnCount() {
310
        return headerCellRenderer.getSelectedColumns().length;
311
    }
312

    
313
    @Override
314
    public void tableChanged(TableModelEvent e) {
315
        // Clear the header selection
316
        if (e != null && e.getFirstRow() == TableModelEvent.HEADER_ROW
317
            && headerCellRenderer != null) {
318
            headerCellRenderer.deselectAll();
319
        }
320

    
321
        super.tableChanged(e);
322
    }
323

    
324
    @Override
325
    public Class<?> getColumnClass(int column) {
326
        Class resp = super.getColumnClass(column);
327
        if (Timestamp.class.isAssignableFrom(resp)) {
328
            return Object.class;
329
        } else {
330
            return resp;
331
        }
332
    }
333

    
334
    @Override
335
    public int getSelectedRowCount() {
336
        try {
337
            return (int) this.featureTableModel.getFeatureStore().getFeatureSelection().getSelectedCount();
338
        } catch (DataException ex) {
339
            LOGGER.error("Can't calculate selected rows in table.", ex);
340
            return 0;
341
        }
342
    }
343

    
344

    
345
}