/*! * 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.model.lineal; import org.pentaho.reporting.designer.core.settings.SettingsListener; import org.pentaho.reporting.designer.core.settings.WorkspaceSettings; import org.pentaho.reporting.designer.core.util.exceptions.UncaughtExceptionsModel; import javax.swing.event.EventListenerList; import java.io.Serializable; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * The lineal model is a collection of immutable guideline objects. * <p/> * PRD-622: Move the undo stuff out of the data-model. It belongs into the GUI */ public class LinealModel implements Serializable { private class GlobalUpdateHandler implements SettingsListener { private boolean globalState; private GlobalUpdateHandler() { this.globalState = WorkspaceSettings.getInstance().isSnapToGuideLines(); } public void settingsChanged() { final boolean newState = WorkspaceSettings.getInstance().isSnapToGuideLines(); if ( globalState != newState ) { globalState = newState; setGlobalState( globalState ); } } } private ArrayList<GuideLine> guideLines; private transient EventListenerList linealModelListeners; private long modificationCount; /** * A strong reference is needed to make sure that the listener gets garbage collected with the model and not earlier. * * @noinspection FieldCanBeLocal */ private transient GlobalUpdateHandler updateHandler; public LinealModel() { guideLines = new ArrayList<GuideLine>(); linealModelListeners = new EventListenerList(); updateHandler = new GlobalUpdateHandler(); WorkspaceSettings.getInstance().addSettingsListener( updateHandler ); } public long getModificationCount() { return modificationCount; } public GuideLine[] getGuideLines() { return guideLines.toArray( new GuideLine[ guideLines.size() ] ); } public boolean removeGuideLine( final GuideLine guideLine ) { if ( guideLines.remove( guideLine ) ) { modificationCount += 1; fireModelChanged(); return true; } return false; } public boolean addGuidLine( final GuideLine guideLine ) { if ( guideLines.add( guideLine ) ) { modificationCount += 1; fireModelChanged(); return true; } return false; } public void updateGuideLine( final int position, final GuideLine guideLine ) { guideLines.set( position, guideLine ); modificationCount += 1; fireModelChanged(); } public int getGuideLineCount() { return guideLines.size(); } public GuideLine getGuideLine( final int index ) { return guideLines.get( index ); } private void fireModelChanged() { final LinealModelEvent event = new LinealModelEvent( this ); final LinealModelListener[] lml = linealModelListeners.getListeners( LinealModelListener.class ); for ( final LinealModelListener linealModelListener : lml ) { linealModelListener.modelChanged( event ); } } public void addLinealModelListener( final LinealModelListener linealModelListener ) { linealModelListeners.add( LinealModelListener.class, linealModelListener ); } public void removeLinealModelListener( final LinealModelListener linealModelListener ) { linealModelListeners.remove( LinealModelListener.class, linealModelListener ); } public void parse( final String model ) { try { final String number = "\\d*(?:\\.\\d*)?";//NON-NLS final Pattern fullPattern = Pattern.compile( "\\((\\s*\\w*\\s*,\\s*" + number + "\\s*)\\)" );//NON-NLS final Matcher m = fullPattern.matcher( model ); final ArrayList<GuideLine> matches = new ArrayList<GuideLine>(); while ( m.find() ) { final String guildeLineDef = m.group( 1 ); final String[] strings = guildeLineDef.split( "," ); if ( strings.length != 2 ) { return; } final boolean active = "true".equals( strings[ 0 ] );//NON-NLS final double pos = Double.parseDouble( strings[ 1 ] ); matches.add( new GuideLine( pos, active ) ); } this.guideLines.clear(); this.guideLines.addAll( matches ); } catch ( Exception e ) { UncaughtExceptionsModel.getInstance().addException( e ); } } public String externalize() { final GuideLine[] guidelines = getGuideLines(); if ( guidelines.length > 0 ) { final StringBuffer b = new StringBuffer( 100 ); for ( int i = 0; i < guidelines.length; i++ ) { final GuideLine guideline = guidelines[ i ]; if ( i != 0 ) { b.append( ' ' ); } b.append( guideline.externalize() ); } return b.toString(); } return null; } public void setGlobalState( final boolean active ) { final GuideLine[] lines = getGuideLines(); for ( int i = 0; i < lines.length; i++ ) { final GuideLine line = lines[ i ]; guideLines.set( i, line.updateActive( active ) ); modificationCount += 1; } fireModelChanged(); } }