/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Copyright (C) 2011-2013 Marchand Eric <ricoh51@free.fr>
This file is part of Freegressi.
Freegressi is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Freegressi is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Freegressi. If not, see <http://www.gnu.org/licenses/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package freegressi.tableur;
import beans.JTextFieldSouligneDouble;
import freegressi.tableur.SpreadSheets.ActiveSheetChangedEvent;
import freegressi.tableur.SpreadSheets.SheetAddedEvent;
import freegressi.tableur.SpreadSheets.SheetDeletedEvent;
import freegressi.tableur.SpreadSheets.SheetDescriptionChangedEvent;
import freegressi.tableur.SpreadSheets.SheetsAngleChangedEvent;
import freegressi.tableur.SpreadSheets.SheetsCSChangedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnAddedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnDeletedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnModifiedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnMovedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnSortedEvent;
import freegressi.tableur.SpreadSheets.SheetsColumnsEditedEvent;
import freegressi.tableur.SpreadSheets.SheetsListener;
import freegressi.tableur.SpreadSheets.SheetsRenamedEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.*;
import java.text.DecimalFormat;
import javax.swing.*;
import javax.swing.table.*;
/**
*
* @author marchand
*/
public class JTableColonnes extends JTable implements SheetsListener {
private Tableur tableur;
private Color gris = new Color(220, 220, 220);
// le format d'affichage des doubles dans la table
private DecimalFormat df = new DecimalFormat("0.00E0");
private int ligneEditee, colonneEditee;
private final JPanelSerie jps;
private int lastFrom = -1;
private int lastTo = -1;
//private boolean draggedColumn = false;
private JTableHeader header;
public JTableColonnes(final Tableur sheet, JPanelSerie jps) {
super(sheet);
this.tableur = sheet;
this.jps = jps;
// Mettre ce flag à false sinon lorsque on a bougé des colonnes
// et que la table reçoit un structurechanged, les positions des
// colonnes sont réinitialisées!
this.setAutoCreateColumnsFromModel(false);
header = getTableHeader();
header.setBackground(Color.WHITE);
// Augmenter la hauteur du header pour pouvoir afficher l'unité en dessous du nom
header.setPreferredSize(new Dimension(1000, 40));
// autoriser les déplacements
header.setReorderingAllowed(false);
header.addMouseListener(new ColumnListener()); // écouter les clics souris
header.setDefaultRenderer(new SerieHeaderRenderer(/*evaluateur*/)); // la façon de se dessiner
setDefaultRenderer(Double.class, new SerieDoubleRenderer());
setDefaultRenderer(Integer.class, new SerieIntegerRenderer());
setDefaultEditor(Double.class, new SerieDoubleCellEditor());
setRowSelectionAllowed(true);
setColumnSelectionAllowed(true);
// autoriser seulement les selections contigues, sinon c'est difficile
// de faire des undo redo
setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
setAutoResizeMode(AUTO_RESIZE_OFF);
setRowHeight(35);
// getColumnModel().addColumnModelListener(new TableColumnModelListener() {
//
// @Override
// public void columnAdded(TableColumnModelEvent e) {
// //revalidate();
// }
//
// @Override
// public void columnRemoved(TableColumnModelEvent e) {
// }
//
// @Override
// public void columnMoved(TableColumnModelEvent e) {
// draggedColumn = true;
// //System.out.println("columnMoved");
// }
//
// @Override
// public void columnMarginChanged(ChangeEvent e) {
// }
//
// @Override
// public void columnSelectionChanged(ListSelectionEvent e) {
// }
// });
//putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
// Gestion du focus dans la JTable
addKeyListener(new java.awt.event.KeyAdapter() {
@Override
public void keyReleased(java.awt.event.KeyEvent ke) {
//System.out.println("<JTable.keyReleased>");
Tableur.Coordonnee coord;
switch (ke.getKeyCode()) {
case KeyEvent.VK_ENTER:
//case KeyEvent.VK_TAB:
//case KeyEvent.VK_RIGHT:
coord = tableur.tableDonneCelluleSuivante(ligneEditee, colonneEditee);
//coord.colonne = convertColumnIndexToView(coord.colonne);
donneFocus(coord.ligne, coord.colonne);
break;
case KeyEvent.VK_UP:
coord = tableur.tableDonneCelluleAuDessus(ligneEditee, colonneEditee);
donneFocus(coord.ligne, coord.colonne);
break;
case KeyEvent.VK_DOWN:
coord = tableur.tableDonneCelluleEnDessous(ligneEditee, colonneEditee);
donneFocus(coord.ligne, coord.colonne);
break;
}
}
});
SpreadSheets.getInstance().addSheetsListener(this);
}
@Override
public void finalize() throws Throwable {
System.err.println("JTableColonnes détruit");
super.finalize();
}
public Tableur getTableur() {
return tableur;
}
/**
* rend la cellule éditable (row et col sont dans les coordonnées du tableur)
* @param row la ligne
* @param col la colonne
*/
public void donneFocus(int row, int col) {
final int r = row;
// +1 pour ajouter la colonne des N°, ensuite on convertit en indexView
//col = convertColumnIndexToView(col + 1);
col++;
final int c = col;
// s'il n'y a pas assez de ligne...
if (tableur.getRowCount() - 1 < r) {
return;
}
// Ne rien faire s'il n'y a plus de série
if (tableur.getListeColonnes().isEmpty()) {
return;
}
// Pour donner le focus, il faut attendre un peu...
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
changeSelection(r, c, false, false);
editCellAt(r, c);
getEditorComponent().requestFocusInWindow();
}
});
}
@Override
public int[] getSelectedColumns() {
int[] columns = super.getSelectedColumns();
// for (int i = 0; i < columns.length; i++) {
// columns[i] = convertColumnIndexToModel(columns[i]);
// }
return columns;
}
@Override
public void activeSheetChanged(ActiveSheetChangedEvent event) {
}
@Override
public void sheetAdded(SheetAddedEvent event) {
}
@Override
public void sheetDeleted(SheetDeletedEvent event) {
if (event.getSheet() == tableur) {
SpreadSheets.getInstance().removeSheetsListener(this);
}
}
@Override
public void sheetRenamed(SheetsRenamedEvent event) {
}
/**
* Une colonne est ajoutée dans le modèle, je rajoute une colonne en
* bout de tableau
* @param event
*/
@Override
public void columnAdded(SheetsColumnAddedEvent event) {
int position = getColumnCount();
getColumnModel().addColumn(new TableColumn(position, 80,
getDefaultRenderer(Double.class), getDefaultEditor(Double.class)));
tableur.fireTableDataChanged();
}
@Override
public void columnDeleted(SheetsColumnDeletedEvent event) {
TableColumn tc;
// Supprimer les dernières colonnes
int n = getColumnModel().getColumnCount();
for (int i = 0; i < event.getPositions().length; i++) {
tc = getColumnModel().getColumn(n - 1 - i);
getColumnModel().removeColumn(tc);
}
}
/**
* L'utilisateur a édité les colonnes, il faut redimensionner la table
* (ajouter des colonnes s'il en manque ou en supprimer s'il y en a trop)
* @param event
*/
@Override
public void columnsEdited(SheetsColumnsEditedEvent event) {
int before = event.getOldNames().size();
int after = event.getNewNames().size();
int n;
TableColumn tc;
int dernier = getColumnCount() - 1;
if (before > after) {
n = before - after;
for (int i = 0; i < n; i++) {
tc = getColumnModel().getColumn(dernier - i);
getColumnModel().removeColumn(tc);
}
} else if (before < after) {
n = after - before;
for (int i = 0; i < n; i++) {
tc = new TableColumn(getColumnCount(), 80,
getDefaultRenderer(Double.class), getDefaultEditor(Double.class));
getColumnModel().addColumn(tc);
}
}
header.repaint();
}
@Override
public void columnModified(SheetsColumnModifiedEvent event) {
//System.out.println("Colonne modifiée");
header.repaint();
}
@Override
public void angleChanged(SheetsAngleChangedEvent event) {
}
@Override
public void columnSorted(SheetsColumnSortedEvent event) {
}
@Override
public void columnMoved(SheetsColumnMovedEvent event) {
// if (event.isMoved() && event.getSheet().equals(tableur)) {
// return;
// }
// moveColumn(event.getFrom(), event.getTo());
}
@Override
public void sheetDescriptionChanged(SheetDescriptionChangedEvent event) {
// throw new UnsupportedOperationException("Not supported yet.");
}
/**
*
* @param event
*/
@Override
public void sheetsCSChanged(SheetsCSChangedEvent event) {
String str = "0";
if (event.getNewCS() > 1) {
str += ".";
}
for (int i = 1; i < event.getNewCS(); i++) {
str += "0";
}
str += "E0";
df = new DecimalFormat(str);
repaint();
}
/**
* La classe qui permet de répondre quand on clique sur un header
*/
private final class ColumnListener extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
TableColumnModel colModel = getColumnModel();
int columnModelIndex = colModel.getColumnIndexAtX(e.getX());
jps.modiferColonne(columnModelIndex - 1);
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
}
class SerieHeaderRenderer implements TableCellRenderer {
private JButton button = new JButton();
public SerieHeaderRenderer() {
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row, int column) {
if (column == 0) {
button.setText("<html><strong>" + tableur.getNameI()
+ "</strong></html>");
return button;
} else {
// colonne des double
String nom = tableur.getListeColonnes().get(column - 1).getColonneDescription().getNom();
String unite = tableur.getListeColonnes().get(column - 1).getColonneDescription().getUnite();
String str;
if (!unite.equals("")) {
str = "<html><strong>" + nom + "</strong><br>" + unite + "</html>";
} else {
str = "<html><strong>" + nom + "</strong></html>";
}
button.setText(str);
button.setToolTipText("Modifier " + nom);
}
return button;
}
}
/**
* Classe qui s'occupe du rendu des Integer
*/
class SerieIntegerRenderer extends JLabel implements TableCellRenderer {
public SerieIntegerRenderer() {
setOpaque(true); //MUST do this for background to show up.
setBackground(gris);
setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
}
@Override
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
setText(value.toString());
if (!isPaintingForPrint()) {
if (isSelected) {
setBackground(table.getSelectionBackground());
setForeground(table.getSelectionForeground());
} else {
setForeground(table.getForeground());
setBackground(gris);
}
}
return this;
}
}
/**
* Classe qui s'occupe du rendu des Doubles
*/
class SerieDoubleRenderer extends DefaultTableCellRenderer {
public SerieDoubleRenderer() {
setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
}
@Override
public void setValue(Object value) {
if (value == null) {
setText("");
} else if (value instanceof Double) {
setText(df.format(value).toString());
} else {
System.err.println("Erreur <SerieDoubleRenderer> ");
}
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (!isPaintingForPrint()) {
if (isSelected) {
setBackground(table.getSelectionBackground());
setForeground(table.getSelectionForeground());
} else {
setForeground(table.getForeground());
if (column == 0 || tableur.getListeColonnes().get(column - 1).getColonneDescription().getType()
== Sym.TypeVariable.VARIABLE_CALCULEE) {
setBackground(gris);
} else {
setBackground(table.getBackground());
}
}
}
setValue(value);
return this;
}
}
/**
* Un JtextField qui sélectionne son contenu quand il prend le focus
*/
class SerieJTextFieldSelect extends JTextField {
public SerieJTextFieldSelect() {
super();
addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
selectAll();
}
});
}
}
class SerieDoubleCellEditor extends javax.swing.DefaultCellEditor {
public SerieDoubleCellEditor() {
//super(new SerieJTextFieldSelect());
super(new JTextFieldSouligneDouble(""));
//clickCountToStart = 1;
}
@Override
public Component getTableCellEditorComponent(JTable table,
Object value,
boolean isSelected,
int row,
int column) {
ligneEditee = row;
colonneEditee = column;
// terminate editing
this.stopCellEditing();
((JTextField) getComponent()).requestFocus();
if (value != null) {
((JTextField) getComponent()).setText(value.toString());
} else {
((JTextField) getComponent()).setText("");
}
return (JTextField) getComponent();
}
/** Returns the value contained in the editor.
*/
@Override
public Object getCellEditorValue() {
try {
// Modif pour le cas ou on tape un nombre plus grand que MAX_VALUE
Double d = Double.parseDouble(((JTextField) getComponent()).getText());
if (d > Double.MAX_VALUE){
d = Double.MAX_VALUE;
} else if (d < Double.MIN_VALUE){
d = Double.MIN_VALUE;
}
//return Double.parseDouble(((JTextField) getComponent()).getText());
return d;
} catch (Exception e) {
return null;
}
}
}
}