/*!
* 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 java.io.Serializable;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.event.EventListenerList;
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;
/**
* 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();
}
}