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 @ 45197

History | View | Annotate | Download (12.2 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.FeatureCellRenderer;
50
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FeatureTableModel;
51
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FormattedCellEditor;
52
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.FormattedCellRenderer;
53
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.GeometryWKTCellEditor;
54
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.GeometryWKTCellRenderer;
55
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.JToggleButtonHeaderCellRenderer;
56
import org.gvsig.fmap.mapcontrol.dal.feature.swing.table.notification.ColumnHeaderSelectionChangeNotification;
57
import org.gvsig.tools.observer.Observable;
58
import org.gvsig.tools.observer.Observer;
59
import org.gvsig.tools.swing.api.ToolsSwingLocator;
60
import org.slf4j.Logger;
61
import org.slf4j.LoggerFactory;
62

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

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

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

    
87
        private static final int COLUMN_HEADER_MARGIN = 8;
88

    
89
        private static final int COLUMN_HEADER_MIN_WIDTH = 50;
90

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

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

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

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

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

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

    
167
        return descriptors;
168
    }
169

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

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

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

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

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

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

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

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

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

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

    
242
      headerCellRenderer = new JToggleButtonHeaderCellRenderer(this);
243
      getTableHeader().setDefaultRenderer(headerCellRenderer);
244

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

    
300

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

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

    
319
        super.tableChanged(e);
320
    }
321

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

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

    
342

    
343
}