/*! * 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.core.editor.styles; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.reporting.designer.core.settings.WorkspaceSettings; import org.pentaho.reporting.designer.core.util.exceptions.UncaughtExceptionsModel; import org.pentaho.reporting.designer.core.util.table.GroupingHeader; import org.pentaho.reporting.designer.core.util.table.TableStyle; import org.pentaho.reporting.engine.classic.core.metadata.ElementMetaData; import org.pentaho.reporting.engine.classic.core.metadata.ElementTypeRegistry; import org.pentaho.reporting.engine.classic.core.metadata.GroupedMetaDataComparator; import org.pentaho.reporting.engine.classic.core.metadata.PlainMetaDataComparator; import org.pentaho.reporting.engine.classic.core.metadata.StyleMetaData; import org.pentaho.reporting.engine.classic.core.style.ElementStyleSheet; import org.pentaho.reporting.engine.classic.core.style.StyleKey; import org.pentaho.reporting.libraries.base.util.ObjectUtilities; import javax.swing.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Locale; import java.util.concurrent.Executor; import java.util.concurrent.Executors; public class SimpleStyleTableModel extends AbstractStyleTableModel<SimpleStyleTableModel.SimpleStyleDataBackend> { private static final Log logger = LogFactory.getLog( SimpleStyleTableModel.class ); public static class SimpleStyleDataBackend extends AbstractStyleDataBackend { private ElementStyleSheet styleSheet; public SimpleStyleDataBackend() { } public SimpleStyleDataBackend( final StyleMetaData[] metaData, final GroupingHeader[] groupings, final ElementStyleSheet styleSheet ) { super( metaData, groupings ); this.styleSheet = styleSheet; if ( this.styleSheet != null ) { getResolvedStyle().copyFrom( styleSheet ); } } public void resetCache() { super.resetCache(); if ( this.styleSheet != null ) { getResolvedStyle().copyFrom( styleSheet ); } } public ElementStyleSheet getStyleSheet() { return styleSheet; } } private class UpdateDataTask implements Runnable { private ElementStyleSheet elements; private boolean synchronous; private UpdateDataTask( final ElementStyleSheet elements, final boolean synchronous ) { this.elements = elements; this.synchronous = synchronous; } public void run() { try { final SimpleStyleDataBackend dataBackend = updateData( elements ); if ( synchronous || SwingUtilities.isEventDispatchThread() ) { setDataBackend( dataBackend ); fireTableDataChanged(); } else { SwingUtilities.invokeAndWait( new NotifyChangeTask( dataBackend ) ); } } catch ( Exception e ) { UncaughtExceptionsModel.getInstance().addException( e ); } } } private SimpleStyleDataBackend oldDataBackend; private Executor pool; public SimpleStyleTableModel() { pool = Executors.newSingleThreadExecutor(); super.setDataBackend( new SimpleStyleDataBackend() ); } public void setTableStyle( final TableStyle tableStyle ) { super.setTableStyle( tableStyle ); pool.execute( new UpdateDataTask( getData(), isSynchronous() ) ); } public void setData( final ElementStyleSheet elements ) { final SimpleStyleDataBackend backend = this.getDataBackend(); if ( isSameStyleSheet( elements, backend.getStyleSheet() ) ) { SwingUtilities.invokeLater( new SameElementsUpdateDataTask( backend, isSynchronous() ) ); return; } pool.execute( new UpdateDataTask( elements, isSynchronous() ) ); } private boolean isSameStyleSheet( final ElementStyleSheet elements, final ElementStyleSheet styleSheet ) { if ( elements == styleSheet ) { return true; } if ( elements == null ) { return false; } if ( styleSheet == null ) { return false; } return styleSheet.getId() == elements.getId(); } public ElementStyleSheet getData() { return getDataBackend().getStyleSheet(); } protected synchronized void setDataBackend( final SimpleStyleDataBackend dataBackend ) { this.oldDataBackend = getDataBackend(); super.setDataBackend( dataBackend ); } protected SimpleStyleDataBackend updateData( final ElementStyleSheet styleSheet ) { final StyleMetaData[] metaData = selectCommonAttributes(); final TableStyle tableStyle = getTableStyle(); if ( tableStyle == TableStyle.ASCENDING ) { Arrays.sort( metaData, new PlainMetaDataComparator() ); return ( new SimpleStyleDataBackend( metaData, new GroupingHeader[ metaData.length ], styleSheet ) ); } else if ( tableStyle == TableStyle.DESCENDING ) { Arrays.sort( metaData, Collections.reverseOrder( new PlainMetaDataComparator() ) ); return ( new SimpleStyleDataBackend( metaData, new GroupingHeader[ metaData.length ], styleSheet ) ); } else { Arrays.sort( metaData, new GroupedMetaDataComparator() ); final Locale locale = Locale.getDefault(); int groupCount = 0; int metaDataCount = 0; if ( metaData.length > 0 ) { String oldValue = null; for ( int i = 0; i < metaData.length; i++ ) { final StyleMetaData data = metaData[ i ]; if ( data.isHidden() ) { continue; } if ( !WorkspaceSettings.getInstance().isVisible( data ) ) { continue; } metaDataCount += 1; if ( groupCount == 0 ) { groupCount = 1; oldValue = data.getGrouping( locale ); continue; } final String grouping = data.getGrouping( locale ); if ( ( ObjectUtilities.equal( oldValue, grouping ) ) == false ) { groupCount += 1; oldValue = grouping; continue; } } } final StyleMetaData[] groupedMetaData = new StyleMetaData[ metaDataCount + groupCount ]; int targetIdx = 0; GroupingHeader[] groupings = new GroupingHeader[ groupedMetaData.length ]; GroupingHeader group = null; for ( int sourceIdx = 0; sourceIdx < metaData.length; sourceIdx++ ) { final StyleMetaData data = metaData[ sourceIdx ]; if ( data.isHidden() ) { continue; } if ( !WorkspaceSettings.getInstance().isVisible( data ) ) { continue; } if ( targetIdx == 0 ) { group = new GroupingHeader( data.getGrouping( locale ) ); groupings[ targetIdx ] = group; targetIdx += 1; } else { final String newgroup = data.getGrouping( locale ); if ( ( ObjectUtilities.equal( newgroup, group.getHeaderText() ) ) == false ) { group = new GroupingHeader( newgroup ); groupings[ targetIdx ] = group; targetIdx += 1; } } groupings[ targetIdx ] = group; groupedMetaData[ targetIdx ] = data; targetIdx += 1; } if ( oldDataBackend != null ) { groupings = reconcileState( groupings, oldDataBackend.getGroupings() ); } return new SimpleStyleDataBackend( groupedMetaData, groupings, styleSheet ); } } private StyleMetaData[] selectCommonAttributes() { final HashSet<StyleKey> seenKeys = new HashSet<StyleKey>(); final ArrayList<StyleMetaData> result = new ArrayList<StyleMetaData>(); final ElementMetaData[] allElementTypes = ElementTypeRegistry.getInstance().getAllElementTypes(); for ( int i = 0; i < allElementTypes.length; i++ ) { final ElementMetaData elementType = allElementTypes[ i ]; final StyleMetaData[] datas = elementType.getStyleDescriptions(); for ( int j = 0; j < datas.length; j++ ) { final StyleMetaData data = datas[ j ]; if ( seenKeys.add( data.getStyleKey() ) ) { result.add( data ); } } } return result.toArray( new StyleMetaData[ result.size() ] ); } protected Object computeInheritValue( final StyleMetaData metaData, final int rowIndex ) { final ElementStyleSheet styleSheet = getDataBackend().getStyleSheet(); if ( styleSheet == null ) { return null; } return styleSheet.isLocalKey( metaData.getStyleKey() ) == false; } protected boolean defineFullValue( final StyleMetaData metaData, final Object value ) { if ( value != null && metaData.getTargetType().isInstance( value ) == false ) { // not the correct type logger.warn( "Invalid type: " + value + "(" + value.getClass() + ") but expected " + // NON-NLS metaData.getTargetType() ); return false; } final ElementStyleSheet styleSheet = getDataBackend().getStyleSheet(); if ( styleSheet == null ) { return false; } final long changeTrackerHash = styleSheet.getChangeTrackerHash(); styleSheet.setStyleProperty( metaData.getStyleKey(), value ); return changeTrackerHash != styleSheet.getChangeTrackerHash(); } }