/*! * 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.designer.extensions.legacycharts; import org.pentaho.reporting.designer.core.ReportDesignerContext; import org.pentaho.reporting.designer.core.editor.expressions.DynamicExpressionTableModel; import org.pentaho.reporting.designer.core.editor.expressions.ExpressionPropertiesTableModel; import org.pentaho.reporting.designer.core.util.ActionToggleButton; import org.pentaho.reporting.designer.core.util.ExpressionListCellRenderer; import org.pentaho.reporting.designer.core.util.table.ElementMetaDataTable; import org.pentaho.reporting.designer.core.util.table.GroupedMetaTableModel; import org.pentaho.reporting.designer.core.util.table.GroupingModel; import org.pentaho.reporting.designer.core.util.table.SortHeaderPanel; import org.pentaho.reporting.engine.classic.core.AttributeNames; import org.pentaho.reporting.engine.classic.core.Element; import org.pentaho.reporting.engine.classic.core.function.Expression; import org.pentaho.reporting.engine.classic.core.metadata.ExpressionMetaData; import org.pentaho.reporting.engine.classic.core.metadata.ExpressionPropertyMetaData; import org.pentaho.reporting.engine.classic.core.metadata.ExpressionRegistry; import org.pentaho.reporting.engine.classic.extensions.legacy.charts.LegacyChartElementModule; import org.pentaho.reporting.libraries.designtime.swing.CommonDialog; import org.pentaho.reporting.libraries.designtime.swing.SmartComboBox; import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import java.awt.*; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.net.URL; import java.util.Locale; public class LegacyChartEditorDialog extends CommonDialog { private class SelectChartExpressionAction extends AbstractAction implements ListDataListener { private Class expressionType; private Icon standardIcon; private Icon selectedIcon; private SelectChartExpressionAction( final Class expressionType ) { this.expressionType = expressionType; final ExpressionRegistry expressionRegistry = ExpressionRegistry.getInstance(); final ExpressionMetaData metaData = expressionRegistry.getExpressionMetaData( expressionType.getName() ); putValue( Action.NAME, metaData.getMetaAttribute( "short-name", Locale.getDefault() ) ); // NON-NLS final String defaultIcon = metaData.getMetaAttribute( "icon", Locale.getDefault() ); // NON-NLS if ( defaultIcon != null ) { final URL defaultIconUrl = LegacyChartEditorDialog.class.getResource( defaultIcon ); if ( defaultIconUrl != null ) { standardIcon = new ImageIcon( defaultIconUrl ); putValue( Action.SMALL_ICON, standardIcon ); } } final String selectedIconProperty = metaData.getMetaAttribute( "selected-icon", Locale.getDefault() ); // NON-NLS if ( selectedIconProperty != null ) { final URL selectedIconUrl = LegacyChartEditorDialog.class.getResource( selectedIconProperty ); if ( selectedIconUrl != null ) { selectedIcon = new ImageIcon( selectedIconUrl ); } } } public void actionPerformed( final ActionEvent e ) { final ExpressionMetaData data = ExpressionRegistry.getInstance().getExpressionMetaData( expressionType.getName() ); editModel.getChartExpressionsModel().setSelectedItem( data ); } public void intervalAdded( final ListDataEvent e ) { // ignore } public void intervalRemoved( final ListDataEvent e ) { // ignore } public void contentsChanged( final ListDataEvent e ) { final ExpressionMetaData o = (ExpressionMetaData) editModel.getChartExpressionsModel().getSelectedItem(); if ( o != null && expressionType.equals( o.getExpressionType() ) ) { putValue( "selected", Boolean.TRUE ); // NON-NLS putValue( Action.SMALL_ICON, selectedIcon ); } else { putValue( "selected", Boolean.FALSE ); // NON-NLS putValue( Action.SMALL_ICON, standardIcon ); } } } private class ChartExpressionChangeHandler implements PropertyChangeListener { private ChartExpressionChangeHandler() { } /** * This method gets called when a bound property is changed. * * @param evt A PropertyChangeEvent object describing the event source and the property that has changed. */ public void propertyChange( final PropertyChangeEvent evt ) { if ( LegacyChartEditModel.CHART_EXPRESSION_PROPERTY.equals( evt.getPropertyName() ) == false ) { return; } final Expression o = (Expression) evt.getNewValue(); if ( o == null ) { chartPropertiesTableModel.setData( EMPTY_EXPRESSION ); dataSourceTabbedPane.setEnabledAt( 1, false ); dataSourceTabbedPane.setSelectedIndex( 0 ); return; } chartPropertiesTableModel.setData( new Expression[] { o } ); final ChartType type = ChartType.getTypeByChartExpression( o.getClass() ); if ( type == null ) { dataSourceTabbedPane.setEnabledAt( 1, false ); dataSourceTabbedPane.setSelectedIndex( 0 ); return; } dataSourceTabbedPane.setEnabledAt( 1, type.getSecondaryDataSourceProperty() != null ); } } private class PrimaryDataSourceChangeHandler implements PropertyChangeListener { private PrimaryDataSourceChangeHandler() { } /** * This method gets called when a bound property is changed. * * @param evt A PropertyChangeEvent object describing the event source and the property that has changed. */ public void propertyChange( final PropertyChangeEvent evt ) { if ( LegacyChartEditModel.PRIMARY_DATA_SOURCE_PROPERTY.equals( evt.getPropertyName() ) == false ) { return; } final Expression o = (Expression) evt.getNewValue(); if ( o == null ) { primaryDataSourcePropertiesTableModel.setData( EMPTY_EXPRESSION ); return; } primaryDataSourcePropertiesTableModel.setData( new Expression[] { o } ); } } private class SecondaryDataSourceChangeHandler implements PropertyChangeListener { private SecondaryDataSourceChangeHandler() { } /** * This method gets called when a bound property is changed. * * @param evt A PropertyChangeEvent object describing the event source and the property that has changed. */ public void propertyChange( final PropertyChangeEvent evt ) { if ( LegacyChartEditModel.SECONDARY_DATA_SOURCE_PROPERTY.equals( evt.getPropertyName() ) == false ) { return; } final Expression o = (Expression) evt.getNewValue(); if ( o == null ) { secondaryDataSourcePropertiesTableModel.setData( EMPTY_EXPRESSION ); return; } secondaryDataSourcePropertiesTableModel.setData( new Expression[] { o } ); } } protected static class ChartExpressionPropertiesTableModel extends ExpressionPropertiesTableModel { public ChartExpressionPropertiesTableModel() { setFilterInlineExpressionProperty( true ); } protected boolean isFiltered( final ExpressionPropertyMetaData metaData ) { if ( "linesDataSource".equals( metaData.getName() ) ) // NON-NLS { return true; } if ( "secondaryDataSet".equals( metaData.getName() ) ) // NON-NLS { return true; } if ( "dataSource".equals( metaData.getName() ) ) // NON-NLS { return true; } return super.isFiltered( metaData ); } } private ExpressionPropertiesTableModel chartPropertiesTableModel; private ExpressionPropertiesTableModel primaryDataSourcePropertiesTableModel; private ExpressionPropertiesTableModel secondaryDataSourcePropertiesTableModel; private JTabbedPane dataSourceTabbedPane; private ElementMetaDataTable chartTable; private ElementMetaDataTable primaryDataSourceTable; private ElementMetaDataTable secondaryDataSourceTable; private LegacyChartEditModel editModel; private static final Expression[] EMPTY_EXPRESSION = new Expression[ 0 ]; public LegacyChartEditorDialog() throws HeadlessException { init(); } public LegacyChartEditorDialog( final Frame owner ) throws HeadlessException { super( owner ); init(); } public LegacyChartEditorDialog( final Dialog owner ) throws HeadlessException { super( owner ); init(); } protected void init() { setTitle( Messages.getInstance().getString( "ChartEditorTitle" ) ); editModel = new LegacyChartEditModel(); editModel .addPropertyChangeListener( LegacyChartEditModel.CHART_EXPRESSION_PROPERTY, new ChartExpressionChangeHandler() ); editModel.addPropertyChangeListener( LegacyChartEditModel.PRIMARY_DATA_SOURCE_PROPERTY, new PrimaryDataSourceChangeHandler() ); editModel.addPropertyChangeListener( LegacyChartEditModel.SECONDARY_DATA_SOURCE_PROPERTY, new SecondaryDataSourceChangeHandler() ); chartTable = new ElementMetaDataTable(); chartPropertiesTableModel = new DynamicExpressionTableModel(); primaryDataSourceTable = new ElementMetaDataTable(); primaryDataSourcePropertiesTableModel = new ExpressionPropertiesTableModel(); primaryDataSourcePropertiesTableModel.setFilterInlineExpressionProperty( true ); secondaryDataSourceTable = new ElementMetaDataTable(); secondaryDataSourcePropertiesTableModel = new ExpressionPropertiesTableModel(); secondaryDataSourcePropertiesTableModel.setFilterInlineExpressionProperty( true ); dataSourceTabbedPane = new JTabbedPane(); dataSourceTabbedPane.add( Messages.getInstance().getString( "PrimaryDataSource" ), createPrimaryDataSourcePanel() ); dataSourceTabbedPane .add( Messages.getInstance().getString( "SecondaryDataSource" ), createSecondaryDataSourcePanel() ); super.init(); } protected String getDialogId() { return "ReportDesigner.Chart.LegacyChartEditor"; } protected Component createContentPane() { final JSplitPane expressionsPane = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT ); expressionsPane.setLeftComponent( createChartPanel() ); expressionsPane.setRightComponent( dataSourceTabbedPane ); final JSplitPane previewPane = new JSplitPane( JSplitPane.VERTICAL_SPLIT ); previewPane.setBottomComponent( expressionsPane ); final JPanel contentPane = new JPanel(); final Border border = contentPane.getBorder(); final Border margin = new EmptyBorder( 5, 20, 0, 0 ); contentPane.setBorder( new CompoundBorder( border, margin ) ); contentPane.setLayout( new BorderLayout() ); contentPane.add( createChartSelectorButtonPane(), BorderLayout.NORTH ); contentPane.add( previewPane, BorderLayout.CENTER ); previewPane.setDividerLocation( 300 ); expressionsPane.setDividerLocation( 350 ); return contentPane; } private JPanel createSecondaryDataSourcePanel() { final JPanel innerSecondaryDataSourcePanel = new JPanel( new BorderLayout() ); innerSecondaryDataSourcePanel.add( new SortHeaderPanel( secondaryDataSourcePropertiesTableModel ), BorderLayout.NORTH ); final JComboBox comboBox = new SmartComboBox( editModel.getSecondaryDataSourcesModel() ); comboBox.setRenderer( new ExpressionListCellRenderer() ); innerSecondaryDataSourcePanel.add( comboBox, BorderLayout.CENTER ); final JPanel secondaryDataSourcePanel = new JPanel( new BorderLayout() ); secondaryDataSourcePanel.add( innerSecondaryDataSourcePanel, BorderLayout.NORTH ); secondaryDataSourcePanel.add( configureExpressionTable( secondaryDataSourceTable, secondaryDataSourcePropertiesTableModel ), BorderLayout.CENTER ); return secondaryDataSourcePanel; } private JPanel createPrimaryDataSourcePanel() { final JPanel innerPrimaryDataSourcePanel = new JPanel( new BorderLayout() ); innerPrimaryDataSourcePanel.add( new SortHeaderPanel( primaryDataSourcePropertiesTableModel ), BorderLayout.NORTH ); final JComboBox comboBox = new SmartComboBox( editModel.getPrimaryDataSourcesModel() ); comboBox.setRenderer( new ExpressionListCellRenderer() ); innerPrimaryDataSourcePanel.add( comboBox, BorderLayout.CENTER ); final JPanel primaryDataSourcePanel = new JPanel( new BorderLayout() ); primaryDataSourcePanel.add( innerPrimaryDataSourcePanel, BorderLayout.NORTH ); primaryDataSourcePanel .add( configureExpressionTable( primaryDataSourceTable, primaryDataSourcePropertiesTableModel ), BorderLayout.CENTER ); return primaryDataSourcePanel; } private JPanel createChartPanel() { final JPanel innerChartExpressionPanel = new JPanel( new BorderLayout() ); innerChartExpressionPanel.add( new SortHeaderPanel( chartPropertiesTableModel ), BorderLayout.NORTH ); final JComboBox comboBox = new SmartComboBox( editModel.getChartExpressionsModel() ); comboBox.setRenderer( new ExpressionListCellRenderer() ); innerChartExpressionPanel.add( comboBox, BorderLayout.CENTER ); final JPanel chartExpressionPanel = new JPanel( new BorderLayout() ); chartExpressionPanel.add( innerChartExpressionPanel, BorderLayout.NORTH ); chartExpressionPanel.add ( configureExpressionTable( chartTable, chartPropertiesTableModel ), BorderLayout.CENTER ); return chartExpressionPanel; } private JComponent configureExpressionTable( final ElementMetaDataTable table, final GroupingModel dataModel ) { table.setModel( new GroupedMetaTableModel( dataModel ) ); return new JScrollPane( table ); } private Component createChartSelectorButtonPane() { final ChartType[] types = ChartType.values(); final ButtonGroup buttonGroup = new ButtonGroup(); final JPanel buttonCarrier = new JPanel(); buttonCarrier.setLayout( new FlowLayout( FlowLayout.LEFT, 5, 5 ) ); for ( int i = 0; i < types.length; i++ ) { final ChartType type = types[ i ]; final SelectChartExpressionAction action = new SelectChartExpressionAction( type.getExpressionType() ); editModel.getChartExpressionsModel().addListDataListener( action ); final ActionToggleButton button = new ActionToggleButton(); button.putClientProperty( "hideActionText", Boolean.TRUE ); // NON-NLS button.setAction( action ); button.setBorder( new EmptyBorder( 0, 0, 0, 0 ) ); buttonGroup.add( button ); buttonCarrier.add( button ); } final JPanel panel = new JPanel(); panel.setLayout( new BorderLayout() ); panel.add( buttonCarrier, BorderLayout.NORTH ); return panel; } public ChartEditingResult performEdit( final Element element, final ReportDesignerContext reportDesignerContext ) throws CloneNotSupportedException { if ( element == null ) { throw new NullPointerException(); } if ( reportDesignerContext == null ) { throw new NullPointerException(); } if ( LegacyChartsUtil.isLegacyChartElement( element ) == false ) { return null; } try { chartTable.setReportDesignerContext( reportDesignerContext ); primaryDataSourceTable.setReportDesignerContext( reportDesignerContext ); secondaryDataSourceTable.setReportDesignerContext( reportDesignerContext ); chartPropertiesTableModel.setActiveContext( reportDesignerContext.getActiveContext() ); primaryDataSourcePropertiesTableModel.setActiveContext( reportDesignerContext.getActiveContext() ); secondaryDataSourcePropertiesTableModel.setActiveContext( reportDesignerContext.getActiveContext() ); final Element editableElement = element.derive(); final Expression chartExpression = editableElement.getAttributeExpression( AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE ); final Expression originalPrimaryDataSourceExpression; final Expression originalSecondaryDataSourceExpression; if ( chartExpression != null ) { originalPrimaryDataSourceExpression = extractPrimaryDatasource( element ); originalSecondaryDataSourceExpression = extractSecondaryDatasource( element ); editModel.setChartExpression( chartExpression.getInstance() ); if ( originalPrimaryDataSourceExpression != null ) { editModel.setPrimaryDataSource( originalPrimaryDataSourceExpression.getInstance() ); } else { editModel.setPrimaryDataSource( null ); } if ( originalSecondaryDataSourceExpression != null ) { editModel.setSecondaryDataSource( originalSecondaryDataSourceExpression.getInstance() ); } else { editModel.setSecondaryDataSource( null ); } } else { editModel.setChartExpression( null ); editModel.setPrimaryDataSource( null ); editModel.setSecondaryDataSource( null ); originalPrimaryDataSourceExpression = null; originalSecondaryDataSourceExpression = null; } if ( editModel.getCurrentChartType() != null ) { final ChartType chartType = editModel.getCurrentChartType(); if ( editModel.getPrimaryDataSource() == null ) { final Class dataSourceImplementation = chartType.getPreferredPrimaryDataSourceImplementation(); final ExpressionMetaData data = ExpressionRegistry.getInstance().getExpressionMetaData( dataSourceImplementation.getName() ); editModel.getPrimaryDataSourcesModel().setSelectedItem( data ); } if ( editModel.getSecondaryDataSource() == null ) { final Class dataSourceImplementation = chartType.getPreferredSecondaryDataSourceImplementation(); if ( dataSourceImplementation != null ) { final ExpressionMetaData data = ExpressionRegistry.getInstance().getExpressionMetaData( dataSourceImplementation.getName() ); editModel.getSecondaryDataSourcesModel().setSelectedItem( data ); } } } if ( performEdit() == false ) { return null; } secondaryDataSourceTable.stopEditing(); primaryDataSourceTable.stopEditing(); chartTable.stopEditing(); return new ChartEditingResult ( chartExpression, originalPrimaryDataSourceExpression, originalSecondaryDataSourceExpression, editModel.getChartExpression(), editModel.getPrimaryDataSource(), editModel.getSecondaryDataSource() ); } finally { chartTable.setReportDesignerContext( null ); primaryDataSourceTable.setReportDesignerContext( null ); secondaryDataSourceTable.setReportDesignerContext( null ); chartPropertiesTableModel.setActiveContext( null ); primaryDataSourcePropertiesTableModel.setActiveContext( null ); secondaryDataSourcePropertiesTableModel.setActiveContext( null ); } } private Expression extractSecondaryDatasource( final Element element ) { final Expression originalSecondaryDataSourceExpression; final Object secondaryDataSource = element.getAttribute ( LegacyChartElementModule.NAMESPACE, LegacyChartElementModule.SECONDARY_DATA_COLLECTOR_FUNCTION_ATTRIBUTE ); if ( secondaryDataSource instanceof Expression ) { originalSecondaryDataSourceExpression = (Expression) secondaryDataSource; } else { originalSecondaryDataSourceExpression = null; } return originalSecondaryDataSourceExpression; } private Expression extractPrimaryDatasource( final Element element ) { final Expression originalPrimaryDataSourceExpression; final Object primaryDataSourceRaw = element.getAttribute ( LegacyChartElementModule.NAMESPACE, LegacyChartElementModule.PRIMARY_DATA_COLLECTOR_FUNCTION_ATTRIBUTE ); if ( primaryDataSourceRaw instanceof Expression ) { originalPrimaryDataSourceExpression = (Expression) primaryDataSourceRaw; } else { originalPrimaryDataSourceExpression = null; } return originalPrimaryDataSourceExpression; } }