001    /*
002     * Copyright (C) 2008-2010 by Holger Arndt
003     *
004     * This file is part of the Universal Java Matrix Package (UJMP).
005     * See the NOTICE file distributed with this work for additional
006     * information regarding copyright ownership and licensing.
007     *
008     * UJMP is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU Lesser General Public License as
010     * published by the Free Software Foundation; either version 2
011     * of the License, or (at your option) any later version.
012     *
013     * UJMP is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016     * GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public
019     * License along with UJMP; if not, write to the
020     * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
021     * Boston, MA  02110-1301  USA
022     */
023    
024    package org.ujmp.gui.panels;
025    
026    import java.awt.Component;
027    import java.awt.Font;
028    import java.awt.GridBagConstraints;
029    import java.awt.GridBagLayout;
030    import java.awt.Insets;
031    import java.awt.Rectangle;
032    import java.awt.event.KeyEvent;
033    import java.awt.event.KeyListener;
034    import java.awt.event.MouseEvent;
035    import java.awt.event.MouseListener;
036    
037    import javax.swing.AbstractListModel;
038    import javax.swing.BorderFactory;
039    import javax.swing.JLabel;
040    import javax.swing.JList;
041    import javax.swing.JPanel;
042    import javax.swing.JPopupMenu;
043    import javax.swing.JScrollPane;
044    import javax.swing.JTable;
045    import javax.swing.JViewport;
046    import javax.swing.ListCellRenderer;
047    import javax.swing.ListSelectionModel;
048    import javax.swing.UIManager;
049    import javax.swing.border.Border;
050    import javax.swing.event.ListSelectionEvent;
051    import javax.swing.event.ListSelectionListener;
052    import javax.swing.event.TableModelEvent;
053    import javax.swing.event.TableModelListener;
054    import javax.swing.table.DefaultTableModel;
055    import javax.swing.table.JTableHeader;
056    import javax.swing.table.TableModel;
057    
058    import org.ujmp.gui.MatrixGUIObject;
059    import org.ujmp.gui.editor.MatrixTableCellEditor;
060    import org.ujmp.gui.menu.MatrixPopupMenu;
061    import org.ujmp.gui.renderer.MatrixValueTableCellRenderer;
062    
063    public class MatrixTableEditorPanel extends JPanel implements TableModelListener, MouseListener, KeyListener,
064                    ListSelectionListener {
065            private static final long serialVersionUID = -1794955656888362574L;
066    
067            private MatrixGUIObject dataModel = null;
068    
069            private final TableModel emptyModel = new DefaultTableModel();
070    
071            private JTable jTable = null;
072    
073            private JList rowHeader = null;
074    
075            private JScrollPane scrollPane = null;
076    
077            private boolean scroll = true;
078    
079            public MatrixTableEditorPanel(MatrixGUIObject m) {
080                    this();
081                    setMatrix(m);
082            }
083    
084            public MatrixTableEditorPanel() {
085                    setBorder(BorderFactory.createTitledBorder("Matrix Editor"));
086                    setLayout(new GridBagLayout());
087    
088                    jTable = new JTable();
089                    jTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
090                    jTable.getTableHeader().setReorderingAllowed(false);
091                    jTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
092                    jTable.setColumnSelectionAllowed(true);
093                    jTable.setDefaultRenderer(Object.class, new MatrixValueTableCellRenderer());
094                    jTable.setDefaultEditor(Object.class, new MatrixTableCellEditor());
095                    jTable.addMouseListener(this);
096                    jTable.addKeyListener(this);
097                    jTable.getSelectionModel().addListSelectionListener(this);
098    
099                    rowHeader = new JList();
100                    rowHeader.setOpaque(true);
101                    rowHeader.setFixedCellHeight(jTable.getRowHeight());
102                    rowHeader.setCellRenderer(new RowHeaderRenderer(jTable));
103    
104                    scrollPane = new JScrollPane(jTable);
105    
106                    this.addMouseListener(this);
107    
108                    this.add(jTable.getTableHeader(), new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.EAST,
109                                    GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
110                    this.add(scrollPane, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.EAST,
111                                    GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
112            }
113    
114            public void tableChanged(TableModelEvent e) {
115            }
116    
117            public void mouseClicked(MouseEvent e) {
118                    if (e.getButton() == MouseEvent.BUTTON3) {
119                            int row = jTable.rowAtPoint(e.getPoint());
120                            int col = jTable.columnAtPoint(e.getPoint());
121                            JPopupMenu popup = new MatrixPopupMenu(null, dataModel, row, col);
122                            popup.show(jTable, e.getX(), e.getY());
123                    }
124            }
125    
126            public void mouseEntered(MouseEvent e) {
127            }
128    
129            public void mouseExited(MouseEvent e) {
130            }
131    
132            public void mousePressed(MouseEvent e) {
133                    scroll = false;
134            }
135    
136            public void mouseReleased(MouseEvent e) {
137                    scroll = true;
138            }
139    
140            public void keyPressed(KeyEvent e) {
141            }
142    
143            public void keyReleased(KeyEvent e) {
144            }
145    
146            public void keyTyped(KeyEvent e) {
147            }
148    
149            public void valueChanged(ListSelectionEvent e) {
150                    if (scroll && e.getValueIsAdjusting() == false) {
151                            int minRow = jTable.getSelectionModel().getMinSelectionIndex();
152                            int minCol = jTable.getColumnModel().getSelectionModel().getMinSelectionIndex();
153                            int maxRow = jTable.getSelectionModel().getMaxSelectionIndex();
154                            int maxCol = jTable.getColumnModel().getSelectionModel().getMaxSelectionIndex();
155                            if (minRow == maxRow && minCol == maxCol) {
156                                    JViewport viewport = (JViewport) jTable.getParent();
157                                    Rectangle rect = jTable.getCellRect(minRow, minCol, true);
158                                    Rectangle viewRect = viewport.getViewRect();
159                                    rect.setLocation(rect.x - viewRect.x, rect.y - viewRect.y);
160                                    int centerX = (viewRect.width - rect.width) / 2;
161                                    int centerY = (viewRect.height - rect.height) / 2;
162                                    if (rect.x < centerX) {
163                                            centerX = -centerX;
164                                    }
165                                    if (rect.y < centerY) {
166                                            centerY = -centerY;
167                                    }
168                                    rect.translate(centerX, centerY);
169                                    viewport.scrollRectToVisible(rect);
170                            }
171                    }
172            }
173    
174            
175            protected void finalize() throws Throwable {
176                    super.finalize();
177                    if (dataModel != null)
178                            dataModel.removeTableModelListener(this);
179            }
180    
181            public void setMatrix(MatrixGUIObject m) {
182                    if (dataModel != null) {
183                            dataModel.removeTableModelListener(this);
184                            dataModel.getRowSelectionModel().removeListSelectionListener(this);
185                            dataModel.getColumnSelectionModel().removeListSelectionListener(this);
186                    }
187    
188                    dataModel = m;
189    
190                    if (dataModel != null) {
191                            jTable.setModel(dataModel);
192                            jTable.setSelectionModel(dataModel.getRowSelectionModel());
193                            jTable.getColumnModel().setSelectionModel(dataModel.getColumnSelectionModel());
194                            dataModel.getRowSelectionModel().addListSelectionListener(this);
195                            dataModel.getColumnSelectionModel().addListSelectionListener(this);
196                            if (dataModel.getRowCount() <= 100000) {
197                                    AbstractListModel rowListModel = new RowListModel(dataModel);
198                                    rowHeader.setModel(rowListModel);
199                                    scrollPane.setRowHeaderView(rowHeader);
200                            } else {
201                                    scrollPane.setRowHeaderView(null);
202                            }
203                    } else {
204                            jTable.setModel(emptyModel);
205                            scrollPane.setRowHeaderView(null);
206                    }
207            }
208    
209    }
210    
211    class RowListModel extends AbstractListModel {
212            private static final long serialVersionUID = 508583105448562780L;
213    
214            private MatrixGUIObject model = null;
215    
216            public RowListModel(MatrixGUIObject m) {
217                    this.model = m;
218            }
219    
220            public Object getElementAt(int index) {
221                    return model.getRowName(index);
222            }
223    
224            public int getSize() {
225                    return model.getRowCount();
226            }
227    
228    }
229    
230    class RowHeaderRenderer extends JLabel implements ListCellRenderer {
231            private static final long serialVersionUID = -9181159352100487913L;
232    
233            private final JTable table;
234    
235            private final Border selectedBorder;
236    
237            private final Border normalBorder;
238    
239            private final Font selectedFont;
240    
241            private final Font normalFont;
242    
243            final JTableHeader header;
244    
245            RowHeaderRenderer(JTable table) {
246                    this.table = table;
247                    normalBorder = UIManager.getBorder("TableHeader.cellBorder");
248                    selectedBorder = BorderFactory.createRaisedBevelBorder();
249                    header = table.getTableHeader();
250                    normalFont = header.getFont();
251                    // selectedFont = normalFont.deriveFont(normalFont.getStyle() |
252                    // Font.BOLD);
253                    selectedFont = normalFont;
254                    setForeground(header.getForeground());
255                    setBackground(header.getBackground());
256                    setOpaque(true);
257                    setHorizontalAlignment(RIGHT);
258            }
259    
260            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
261                            boolean cellHasFocus) {
262                    if (table.getSelectionModel().isSelectedIndex(index)) {
263                            setFont(selectedFont);
264                            // setBackground(Color.blue);
265                            // setBorder(selectedBorder);
266                    } else {
267                            setFont(normalFont);
268                            setBackground(header.getBackground());
269                            // setBorder(normalBorder);
270                    }
271                    String label = String.valueOf(value);
272                    setText(label + " ");
273                    return this;
274            }
275    }