/*! * 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.libraries.designtime.swing.table; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.reporting.libraries.designtime.swing.BorderlessButton; import org.pentaho.reporting.libraries.designtime.swing.ColorUtility; import org.pentaho.reporting.libraries.designtime.swing.CommonDialog; import org.pentaho.reporting.libraries.designtime.swing.GenericTransferable; import org.pentaho.reporting.libraries.designtime.swing.Messages; import org.pentaho.reporting.libraries.designtime.swing.bulk.SortBulkDownAction; import org.pentaho.reporting.libraries.designtime.swing.bulk.SortBulkUpAction; import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.*; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyEditor; import java.lang.reflect.Array; import java.util.ArrayList; public class ArrayCellEditorDialog extends CommonDialog { private static class AddEntryAction extends AbstractAction { private ArrayTableModel tableModel; private AddEntryAction( final ArrayTableModel tableModel ) { this.tableModel = tableModel; putValue( Action.SMALL_ICON, Messages.getInstance().getIcon( "Icons.Add" ) ); putValue( Action.SHORT_DESCRIPTION, Messages.getInstance().getString( "ArrayCellEditorDialog.AddEntry.Description" ) ); } public void actionPerformed( final ActionEvent e ) { tableModel.add( null ); } } private class RemoveEntryAction extends AbstractAction implements ListSelectionListener { private ListSelectionModel selectionModel; private ArrayTableModel tableModel; private RemoveEntryAction( final ArrayTableModel tableModel, final ListSelectionModel selectionModel ) { this.tableModel = tableModel; putValue( Action.SMALL_ICON, Messages.getInstance().getIcon( "Icons.Remove" ) ); putValue( Action.SHORT_DESCRIPTION, Messages.getInstance().getString( "ArrayCellEditorDialog.RemoveEntry.Description" ) ); this.selectionModel = selectionModel; this.selectionModel.addListSelectionListener( this ); } public void actionPerformed( final ActionEvent e ) { table.stopEditing(); final int maxIdx = selectionModel.getMaxSelectionIndex(); final ArrayList<Integer> list = new ArrayList<Integer>(); for ( int i = selectionModel.getMinSelectionIndex(); i <= maxIdx; i++ ) { if ( selectionModel.isSelectedIndex( i ) ) { list.add( 0, i ); } } for ( int i = 0; i < list.size(); i++ ) { final Integer dataEntry = list.get( i ); tableModel.remove( dataEntry ); } } public void valueChanged( final ListSelectionEvent e ) { setEnabled( selectionModel.isSelectionEmpty() == false ); } } private class DoubleClickHandler extends MouseAdapter { private ListSelectionModel selectionModel; private DoubleClickHandler( final ListSelectionModel selectionModel ) { this.selectionModel = selectionModel; } public void mouseClicked( final MouseEvent e ) { if ( e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2 ) { final ArrayTableModel data = getTableModel(); final ArrayTableModel fields = getPaletteListModel(); for ( int i = 0; i < fields.getSize(); i++ ) { if ( selectionModel.isSelectedIndex( i ) ) { data.add( fields.get( i ) ); } } } } } private class ListTransferHandler extends TransferHandler { private ListTransferHandler() { } public boolean importData( final TransferSupport support ) { final DataFlavor dataFlavor = getDataFlavor(); if ( support.isDataFlavorSupported( dataFlavor ) == false ) { return false; } if ( support.isDrop() == false ) { return false; } try { final Object[] transferData = (Object[]) support.getTransferable().getTransferData( dataFlavor ); if ( transferData == null ) { return false; } final ArrayList<Object> items = new ArrayList<Object>(); for ( final Object item : transferData ) { items.add( item ); } final DropLocation dropLocation = support.getDropLocation(); final Point point = dropLocation.getDropPoint(); final int idx = table.rowAtPoint( point ); if ( idx == -1 ) { for ( int i = 0; i < items.size(); i++ ) { tableModel.add( items.get( i ) ); } } else { for ( int i = items.size() - 1; i >= 0; i -= 1 ) { tableModel.add( idx, items.get( i ) ); } } } catch ( Exception e ) { logger.error( "Unable to transfer data in drag-and-drop operation", e ); // NON-NLS return false; } return super.importData( support ); } public boolean canImport( final TransferSupport support ) { if ( support.isDrop() == false ) { return false; } return ( support.isDataFlavorSupported( getDataFlavor() ) ); } public int getSourceActions( final JComponent c ) { return TransferHandler.COPY; } protected Transferable createTransferable( final JComponent c ) { final JList lcomp = (JList) c; final Object[] selectedValues = lcomp.getSelectedValues(); return new GenericTransferable( selectedValues ); } } private class AddSelectionAction extends AbstractAction implements ListSelectionListener { private ListSelectionModel selectionModel; /** * Defines an <code>Action</code> object with a default description string and default icon. */ private AddSelectionAction( final ListSelectionModel selectionModel ) { this.selectionModel = selectionModel; putValue( Action.SMALL_ICON, Messages.getInstance().getIcon( "Icons.ForwardArrow" ) ); putValue( Action.SHORT_DESCRIPTION, Messages.getInstance().getString( "ArrayCellEditorDialog.AddRow" ) ); selectionModel.addListSelectionListener( this ); setEnabled( selectionModel.isSelectionEmpty() == false ); } public void valueChanged( final ListSelectionEvent e ) { setEnabled( selectionModel.isSelectionEmpty() == false ); } /** * Invoked when an action occurs. */ public void actionPerformed( final ActionEvent e ) { final ArrayTableModel data = getTableModel(); final ArrayTableModel fields = getPaletteListModel(); for ( int i = 0; i < fields.getSize(); i++ ) { if ( selectionModel.isSelectedIndex( i ) ) { data.add( fields.get( i ) ); } } } } private static final Log logger = LogFactory.getLog( ArrayCellEditorDialog.class ); private ArrayTableModel tableModel; private PropertyTable table; private PropertyTable paletteList; private ArrayTableModel paletteListModel; private DataFlavor dataFlavor; private JPanel contentPane; private boolean defaultSize; public ArrayCellEditorDialog() throws HeadlessException { init(); } public ArrayCellEditorDialog( final Frame owner ) throws HeadlessException { super( owner ); init(); } public ArrayCellEditorDialog( final Dialog owner ) throws HeadlessException { super( owner ); init(); } protected void init() { setTitle( Messages.getInstance().getString( "ArrayCellEditorDialog.Title" ) ); tableModel = new ArrayTableModel(); table = new PropertyTable(); table.setModel( tableModel ); paletteListModel = new ArrayTableModel(); paletteListModel.setEditable( false ); paletteList = new PropertyTable(); paletteList.setModel( paletteListModel ); paletteList.setDragEnabled( true ); paletteList.setTransferHandler( new ListTransferHandler() ); paletteList.setDropMode( DropMode.ON ); paletteList.addMouseListener( new DoubleClickHandler( paletteList.getSelectionModel() ) ); contentPane = new JPanel(); contentPane.setLayout( new BorderLayout() ); super.init(); } protected void performInitialResize() { super.performInitialResize(); defaultSize = true; } protected String getDialogId() { return "LibSwing.ArrayCellEditor";// NON-NLS } protected ArrayTableModel getPaletteListModel() { return paletteListModel; } protected ArrayTableModel getTableModel() { return tableModel; } protected Component createContentPane() { return contentPane; } public Object editArray( Object data, final Class arrayType, final Class propertyEditorType ) { if ( arrayType == null ) { throw new NullPointerException(); } if ( arrayType.isArray() == false ) { throw new IllegalArgumentException( "Expect an array class, not a primitive data-type" ); } final Class componentType = arrayType.getComponentType(); if ( ArrayAccessUtility.isArray( data ) == false ) { data = Array.newInstance( componentType, 0 ); } if ( componentType.isArray() ) { dataFlavor = null; } else { dataFlavor = GenericTransferable.ELEMENT_FLAVOR; } tableModel.setType( componentType ); tableModel.setPropertyEditorType( propertyEditorType ); tableModel.setData( ArrayAccessUtility.normalizeArray( data ), componentType ); paletteListModel.setType( componentType ); paletteListModel.setPropertyEditorType( propertyEditorType ); paletteListModel.setData( ArrayAccessUtility.normalizeArray( data ), componentType ); if ( dataFlavor != null ) { paletteListModel.clear(); final Object[] selection = getSelection( arrayType, propertyEditorType ); if ( selection != null && selection.length != 0 ) { for ( final Object s : selection ) { paletteListModel.add( s ); } configurePanelWithSelection(); } else { configurePanelWithoutSelection(); } } else { configurePanelWithoutSelection(); } if ( defaultSize ) { performInitialResize(); defaultSize = false; } if ( performEdit() == false ) { return null; } table.stopEditing(); // process the array .. final Object[] objects = tableModel.toArray(); return ArrayAccessUtility.normalizeNative( objects, componentType ); } public DataFlavor getDataFlavor() { return dataFlavor; } private Object[] getSelection( final Class arrayType, final Class propertyEditorType ) { if ( String[].class.equals( arrayType ) ) { if ( propertyEditorType != null && PropertyEditor.class.isAssignableFrom( propertyEditorType ) ) { try { final PropertyEditor editor = (PropertyEditor) propertyEditorType.newInstance(); return editor.getTags(); } catch ( Throwable e ) { logger.error( "Unable to instantiate property editor.", e );// NON-NLS } } } else if ( Color[].class.equals( arrayType ) ) { return ColorUtility.getPredefinedExcelColors(); } return null; } private void configurePanelWithSelection() { final ListSelectionModel selectionModel = table.getSelectionModel(); final JLabel columnsLabel = new JLabel( Messages.getInstance().getString( "ArrayCellEditorDialog.SelectedItems" ) ); final Action addGroupAction = new AddEntryAction( tableModel ); final Action removeGroupAction = new RemoveEntryAction( tableModel, selectionModel ); final Action sortUpAction = new SortBulkUpAction( tableModel, selectionModel, table ); final Action sortDownAction = new SortBulkDownAction( tableModel, selectionModel, table ); final JPanel tablesPane = new JPanel(); tablesPane.setLayout( new GridBagLayout() ); final JLabel tablesColumnsLabel = new JLabel( Messages.getInstance().getString( "ArrayCellEditorDialog.AvailableSelection" ) ); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 2; gbc.insets = new Insets( 5, 5, 5, 5 ); gbc.anchor = GridBagConstraints.WEST; tablesPane.add( tablesColumnsLabel, gbc ); gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 3; gbc.weighty = 5; gbc.gridheight = 1; gbc.weightx = 2; gbc.fill = GridBagConstraints.BOTH; gbc.insets = new Insets( 0, 5, 5, 5 ); final JScrollPane comp = new JScrollPane ( paletteList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED ); tablesPane.add( comp, gbc ); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; gbc.gridx = 2; gbc.gridy = 2; gbc.weightx = 1; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets( 5, 5, 5, 5 ); tablesPane.add( columnsLabel, gbc ); gbc = new GridBagConstraints(); gbc.gridx = 3; gbc.gridy = 2; gbc.insets = new Insets( 5, 5, 5, 5 ); tablesPane.add( new BorderlessButton( sortUpAction ), gbc ); gbc = new GridBagConstraints(); gbc.gridx = 4; gbc.gridy = 2; gbc.insets = new Insets( 5, 5, 5, 5 ); tablesPane.add( new BorderlessButton( sortDownAction ), gbc ); gbc = new GridBagConstraints(); gbc.gridx = 5; gbc.gridy = 2; gbc.insets = new Insets( 5, 5, 5, 5 ); tablesPane.add( new BorderlessButton( addGroupAction ), gbc ); gbc = new GridBagConstraints(); gbc.gridx = 6; gbc.gridy = 2; gbc.insets = new Insets( 5, 5, 5, 5 ); tablesPane.add( new BorderlessButton( removeGroupAction ), gbc ); gbc = new GridBagConstraints(); gbc.gridx = 2; gbc.gridy = 3; gbc.weighty = 1; gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = 5; gbc.insets = new Insets( 0, 5, 5, 0 ); tablesPane.add( new JScrollPane ( table, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED ), gbc ); gbc = new GridBagConstraints(); gbc.gridx = 1; gbc.gridy = 3; gbc.insets = new Insets( 5, 5, 5, 0 ); tablesPane.add( new BorderlessButton( new AddSelectionAction( paletteList.getSelectionModel() ) ), gbc ); contentPane.removeAll(); contentPane.add( tablesPane ); contentPane.invalidate(); contentPane.revalidate(); contentPane.repaint(); } private void configurePanelWithoutSelection() { final JLabel columnsLabel = new JLabel( Messages.getInstance().getString( "ArrayCellEditorDialog.SelectedItems" ) ); final ListSelectionModel selectionModel = table.getSelectionModel(); final Action addGroupAction = new AddEntryAction( tableModel ); final Action removeGroupAction = new RemoveEntryAction( tableModel, selectionModel ); final Action sortUpAction = new SortBulkUpAction( tableModel, selectionModel, table ); final Action sortDownAction = new SortBulkDownAction( tableModel, selectionModel, table ); final JPanel tablesPane = new JPanel(); tablesPane.setLayout( new GridBagLayout() ); GridBagConstraints gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; gbc.gridx = 2; gbc.gridy = 2; gbc.weightx = 1; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets( 5, 5, 5, 5 ); tablesPane.add( columnsLabel, gbc ); gbc = new GridBagConstraints(); gbc.gridx = 3; gbc.gridy = 2; gbc.insets = new Insets( 5, 5, 5, 5 ); tablesPane.add( new BorderlessButton( sortUpAction ), gbc ); gbc = new GridBagConstraints(); gbc.gridx = 4; gbc.gridy = 2; gbc.insets = new Insets( 5, 5, 5, 5 ); tablesPane.add( new BorderlessButton( sortDownAction ), gbc ); gbc = new GridBagConstraints(); gbc.gridx = 5; gbc.gridy = 2; gbc.insets = new Insets( 5, 5, 5, 5 ); tablesPane.add( new BorderlessButton( addGroupAction ), gbc ); gbc = new GridBagConstraints(); gbc.gridx = 6; gbc.gridy = 2; gbc.insets = new Insets( 5, 5, 5, 5 ); tablesPane.add( new BorderlessButton( removeGroupAction ), gbc ); gbc = new GridBagConstraints(); gbc.gridx = 2; gbc.gridy = 3; gbc.weighty = 1; gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = 5; gbc.insets = new Insets( 0, 5, 5, 0 ); tablesPane.add( new JScrollPane ( table, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED ), gbc ); contentPane.removeAll(); contentPane.add( tablesPane ); contentPane.invalidate(); contentPane.revalidate(); contentPane.repaint(); } }