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 / FeatureTablePanel.java @ 47421

History | View | Annotate | Download (13 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
/*
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
import java.awt.Component;
32
import java.awt.Dimension;
33
import java.beans.PropertyChangeEvent;
34
import java.beans.PropertyChangeListener;
35
import javax.swing.AbstractListModel;
36
import javax.swing.JButton;
37
import javax.swing.JLabel;
38
import javax.swing.JList;
39
import javax.swing.JPanel;
40
import javax.swing.JScrollPane;
41
import javax.swing.JTable;
42
import javax.swing.ListCellRenderer;
43
import javax.swing.ListModel;
44
import javax.swing.SwingUtilities;
45
import javax.swing.UIManager;
46
import javax.swing.event.TableModelEvent;
47
import javax.swing.event.TableModelListener;
48
import javax.swing.table.JTableHeader;
49
import javax.swing.table.TableModel;
50
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
import org.gvsig.tools.ToolsLocator;
59
import org.gvsig.tools.exception.BaseException;
60
import org.gvsig.tools.i18n.I18nManager;
61
import org.gvsig.tools.observer.Observable;
62
import org.gvsig.tools.observer.Observer;
63
import org.slf4j.Logger;
64
import org.slf4j.LoggerFactory;
65

    
66
/**
67
 * Panel to show a table of Feature data.
68
 *
69
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
70
 */
71
public class FeatureTablePanel extends JPanel implements Observer {
72

    
73
    private static final Logger logger = LoggerFactory.getLogger(FeatureTablePanel.class);
74

    
75
    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
     *
88
     * @param featureStore
89
     * to extract the features from
90
     * @throws BaseException
91
     * if there is an error reading data from the FeatureStore
92
     */
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
     *
100
     * @param featureStore
101
     * to extract the features from
102
     * @param isDoubleBuffered
103
     * a boolean, true for double-buffering, which uses additional
104
     * memory space to achieve fast, flicker-free updates
105
     * @throws BaseException
106
     * if there is an error reading data from the FeatureStore
107
     */
108
    public FeatureTablePanel(FeatureStore featureStore, boolean isDoubleBuffered)
109
            throws BaseException {
110
        this(featureStore, null, isDoubleBuffered);
111
    }
112

    
113
    /**
114
     * @throws BaseException
115
     *
116
     */
117
    public FeatureTablePanel(FeatureStore featureStore,
118
            FeatureQuery featureQuery) throws BaseException {
119
        this(featureStore, featureQuery, true);
120
    }
121

    
122
    /**
123
     * @param isDoubleBuffered
124
     * @throws BaseException
125
     */
126
    public FeatureTablePanel(FeatureStore featureStore,
127
            FeatureQuery featureQuery, boolean isDoubleBuffered)
128
            throws BaseException {
129
        this(createModel(featureStore, featureQuery));
130
    }
131

    
132
    public FeatureTablePanel(ConfigurableFeatureTableModel tableModel)
133
            throws DataException {
134
        this(tableModel, true);
135
    }
136

    
137
    public FeatureTablePanel(ConfigurableFeatureTableModel tableModel,
138
            boolean isDoubleBuffered) throws DataException {
139
        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
        if ( selectionPanel == null ) {
149
            I18nManager i18n = ToolsLocator.getI18nManager();
150
            selectionLabel = new JLabel();
151
            selectionLabel.setText(getFeatureSelectionSize() + " / "
152
                    + getTableModel().getHelper().getTotalSize() + " "
153
                    + 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
            selectionPanel = new JPanel();
164
            selectionPanel.add(selectionLabel, BorderLayout.EAST);
165
        }
166
        return selectionPanel;
167
    }
168

    
169
    private void updateSelection() {
170
            selectionLabel.setText(getFeatureSelectionSize() + " / "
171
                + getTableModel().getRowCount() + " "
172
                + Messages.getText("registros_seleccionados_total") + ".");
173
    }
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
                    e);
181
        }
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
     *
191
     * @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
     *
201
     * @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
     *
210
     * @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
            FeatureStore featureStore, FeatureQuery featureQuery)
229
            throws BaseException {
230
        FeatureQuery query
231
                = featureQuery == null ? featureStore.createFeatureQuery()
232
                : featureQuery;
233

    
234
        return new ConfigurableFeatureTableModel(featureStore, query);
235
    }
236

    
237
    public FeatureTable getTable() throws DataException {
238
        if ( table == null ) {
239
            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
     *
253
     * @return javax.swing.JScrollPane
254
     * @throws DataException
255
     */
256
    private JScrollPane getJScrollPane() throws DataException {
257
        if ( jScrollPane == null ) {
258
            FeatureTable theTable = getTable();
259
            jScrollPane = new JScrollPane();
260
            jScrollPane.setViewportView(theTable);
261
            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
        }
282
        return jScrollPane;
283
    }
284

    
285
    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
                rowHeader.setBackground(table.getTableHeader().getBackground());
308
                rowHeader.setCellRenderer(new RowHeaderRenderer(table,rowHeader));
309
                jScrollPane.setRowHeaderView(rowHeader);
310
            }
311
        });
312
    }
313

    
314
    private static class RowHeaderRenderer extends JButton implements ListCellRenderer {
315
        private JTable table = null;
316
        private final Dimension dimension = new Dimension();
317
        private JList rowHeader;
318
        
319
        RowHeaderRenderer(JTable table,JList rowHeader) {
320
            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
            this.rowHeader = rowHeader;
329
        }
330

    
331
        public Component getListCellRendererComponent(JList list, Object value,
332
                int index, boolean isSelected, boolean cellHasFocus) {
333
            setText((value == null) ? "" : value.toString());
334
            this.setPreferredSize(null); // Fuerza recalcular el tama?o del boton
335
            this.dimension.height = this.table.getRowHeight(index);
336
            this.dimension.width = this.getPreferredSize().width+10;
337
            this.setPreferredSize(this.dimension);
338
            return this;
339
        }
340

    
341
    }
342

    
343
    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
        if ( notification instanceof DataStoreNotification ) {
347
            String type = ((DataStoreNotification) notification).getType();
348
            if ( DataStoreNotification.SELECTION_CHANGE.equals(type) ) {
349
                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
}