/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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 Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.ui.datasources.table;
import org.pentaho.reporting.libraries.designtime.swing.BorderlessButton;
import org.pentaho.reporting.libraries.designtime.swing.settings.LocaleSettings;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
public class TableEditorPanel extends JPanel {
private class AddRowAction extends AbstractAction {
/**
* Defines an <code>Action</code> object with a default description string and default icon.
*/
private AddRowAction() {
setEnabled( false );
final URL location = TableDataSourceEditor.class.getResource
( "/org/pentaho/reporting/ui/datasources/table/resources/AddRow.png" ); // NON-NLS
if ( location != null ) {
putValue( Action.SMALL_ICON, new ImageIcon( location ) );
} else {
putValue( Action.NAME, Messages.getString( "TableDataSourceEditor.AddRow.Name" ) );
}
putValue( Action.SHORT_DESCRIPTION, Messages.getString( "TableDataSourceEditor.AddRow.Description" ) );
}
/**
* Invoked when an action occurs.
*/
public void actionPerformed( final ActionEvent e ) {
table.addRow();
updateComponents();
}
}
private class AddColumnAction extends AbstractAction {
/**
* Defines an <code>Action</code> object with a default description string and default icon.
*/
private AddColumnAction() {
setEnabled( false );
final URL location = TableDataSourceEditor.class.getResource
( "/org/pentaho/reporting/ui/datasources/table/resources/AddColumn.png" ); // NON-NLS
if ( location != null ) {
putValue( Action.SMALL_ICON, new ImageIcon( location ) );
} else {
putValue( Action.NAME, Messages.getString( "TableDataSourceEditor.AddColumn.Name" ) );
}
putValue( Action.SHORT_DESCRIPTION, Messages.getString( "TableDataSourceEditor.AddColumn.Description" ) );
}
/**
* Invoked when an action occurs.
*/
public void actionPerformed( final ActionEvent e ) {
table.addColumn( " " );
updateComponents();
}
}
private class RemoveColumnAction extends AbstractAction {
/**
* Defines an <code>Action</code> object with a default description string and default icon.
*/
private RemoveColumnAction() {
setEnabled( false );
final URL location = TableDataSourceEditor.class.getResource
( "/org/pentaho/reporting/ui/datasources/table/resources/RemoveColumn.png" ); // NON-NLS
if ( location != null ) {
putValue( Action.SMALL_ICON, new ImageIcon( location ) );
} else {
putValue( Action.NAME, Messages.getString( "TableDataSourceEditor.RemoveColumn.Name" ) );
}
putValue( Action.SHORT_DESCRIPTION, Messages.getString( "TableDataSourceEditor.RemoveColumn.Description" ) );
}
/**
* Invoked when an action occurs.
*/
public void actionPerformed( final ActionEvent e ) {
table.removeColumn();
setEnabled( false );
}
}
private class RemoveRowAction extends AbstractAction {
/**
* Defines an <code>Action</code> object with a default description string and default icon.
*/
private RemoveRowAction() {
setEnabled( false );
final URL location = TableDataSourceEditor.class.getResource
( "/org/pentaho/reporting/ui/datasources/table/resources/RemoveRow.png" ); // NON-NLS
if ( location != null ) {
putValue( Action.SMALL_ICON, new ImageIcon( location ) );
} else {
putValue( Action.NAME, Messages.getString( "TableDataSourceEditor.RemoveRow.Name" ) );
}
putValue( Action.SHORT_DESCRIPTION, Messages.getString( "TableDataSourceEditor.RemoveRow.Description" ) );
}
/**
* Invoked when an action occurs.
*/
public void actionPerformed( final ActionEvent e ) {
table.removeRow();
setEnabled( false );
}
}
private class TableSelectionHandler implements ListSelectionListener {
private TableSelectionHandler() {
}
public void valueChanged( final ListSelectionEvent e ) {
if ( selectingHeaderColumn ) {
return;
}
final EditableHeader editableHeader = (EditableHeader) table.getTableHeader();
removeColumnAction.setEnabled( false );
removeRowAction.setEnabled( table.getSelectedRowCount() > 0 && table.getRowCount() > 1 );
editableHeader.editingStopped( null );
editableHeader.removeEditor();
}
}
private class TableHeaderDataSourceMouseListener extends MouseAdapter {
private TableHeaderDataSourceMouseListener() {
}
public void mousePressed( final MouseEvent event ) {
final Object eventSource = event.getSource();
if ( eventSource instanceof JTableHeader == false ) {
return;
}
final JTableHeader tableHeader = (JTableHeader) eventSource;
removeColumnAction.setEnabled( table.getColumnCount() > 1 );
removeRowAction.setEnabled( false );
final TableCellEditor theTableCellEditor = table.getCellEditor();
if ( theTableCellEditor != null ) {
table.getCellEditor().stopCellEditing();
}
selectColumn( tableHeader, event.getPoint() );
}
private void selectColumn( final JTableHeader aTableHeader, final Point aPoint ) {
try {
selectingHeaderColumn = true;
final TableColumnModel columnModel = table.getColumnModel();
final int columnIndex = aTableHeader.columnAtPoint( aPoint );
if ( columnIndex <= 0 ) {
return;
}
final TableColumn tableColumn = columnModel.getColumn( columnIndex );
table.clearSelection();
table.setColumnSelectionInterval( columnIndex, columnIndex );
table.setSelectedColumn( tableColumn );
if ( table.getRowCount() > 0 ) {
table.addRowSelectionInterval( 0, table.getRowCount() - 1 );
}
} finally {
selectingHeaderColumn = false;
}
}
}
private class TableAddEmptyRowAtEndHandler extends KeyAdapter {
private TableAddEmptyRowAtEndHandler() {
}
public void keyTyped( final KeyEvent aEvt ) {
final int key = aEvt.getKeyCode();
if ( key == KeyEvent.VK_TAB ) {
if ( table.getSelectedColumn() == ( table.getColumnCount() - 1 ) ) {
if ( table.getSelectedRow() == ( table.getRowCount() - 1 ) ) {
table.addRow();
}
}
}
}
}
private class TableUpdateHandler implements TableModelListener {
private TableUpdateHandler() {
}
/**
* This fine grain notification tells listeners the exact range of cells, rows, or columns that changed.
*/
public void tableChanged( final TableModelEvent e ) {
fireChangeEvent();
}
}
private void fireChangeEvent() {
final ChangeEvent changeEvent = new ChangeEvent( this );
final ChangeListener[] listeners = listenerList.getListeners( ChangeListener.class );
for ( int i = 0; i < listeners.length; i++ ) {
final ChangeListener listener = listeners[ i ];
listener.stateChanged( changeEvent );
}
}
private TableEditor table;
private AddRowAction addRowAction;
private AddColumnAction addColumnAction;
private RemoveRowAction removeRowAction;
private RemoveColumnAction removeColumnAction;
private boolean selectingHeaderColumn;
public TableEditorPanel() {
table = new TableEditor();
table.setAutoResizeMode( JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS );
table.addKeyListener( new TableAddEmptyRowAtEndHandler() );
table.getSelectionModel().addListSelectionListener( new TableSelectionHandler() );
table.getTableHeader().addMouseListener( new TableHeaderDataSourceMouseListener() );
table.getModel().addTableModelListener( new TableUpdateHandler() );
table.setColumnSelectionAllowed( true );
addRowAction = new AddRowAction();
addColumnAction = new AddColumnAction();
removeRowAction = new RemoveRowAction();
removeColumnAction = new RemoveColumnAction();
final JPanel toolbar = new JPanel( new FlowLayout( FlowLayout.RIGHT ) );
toolbar.add( new BorderlessButton( addRowAction ) );
toolbar.add( new BorderlessButton( addColumnAction ) );
toolbar.add( new BorderlessButton( removeRowAction ) );
toolbar.add( new BorderlessButton( removeColumnAction ) );
setLayout( new BorderLayout() );
add( toolbar, BorderLayout.NORTH );
setBorder( BorderFactory.createEmptyBorder( 0, 5, 5, 5 ) );
add( new JScrollPane( table ), BorderLayout.CENTER );
}
public TableModel getTableEditorModel() {
return table.getTableEditorModel();
}
public void applyLocaleSettings( final LocaleSettings localeSettings ) {
table.applyLocaleSettings( localeSettings );
}
public void setEnabled( final boolean enabled ) {
super.setEnabled( enabled );
addRowAction.setEnabled( enabled );
addColumnAction.setEnabled( enabled );
removeRowAction.setEnabled( enabled && table.getSelectedRow() != -1 );
removeColumnAction.setEnabled( enabled && table.getSelectedColumn() != -1 );
}
private void updateComponents() {
final boolean enabled = isEnabled();
removeRowAction.setEnabled( enabled && table.getSelectedRow() != -1 );
removeColumnAction.setEnabled( enabled && table.getSelectedColumn() != -1 );
}
public void stopEditing() {
table.stopEditing();
}
public void addChangeListener( ChangeListener listener ) {
listenerList.add( ChangeListener.class, listener );
}
public void removeChangeListener( ChangeListener listener ) {
listenerList.remove( ChangeListener.class, listener );
}
public void setTableEditorModel( final TableModel tableModel ) {
stopEditing();
this.table.setTableEditorModel( tableModel );
}
}