/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2008 - 2009, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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. */ package org.geotoolkit.sld; import java.beans.PropertyChangeEvent; import java.util.Collection; import java.util.EventObject; import java.util.List; import java.util.Objects; import javax.swing.event.EventListenerList; import org.geotoolkit.gui.swing.tree.Trees; import org.geotoolkit.util.collection.CollectionChangeEvent; import org.geotoolkit.style.StyleConstants; import org.apache.sis.measure.NumberRange; import org.geotoolkit.util.collection.NotifiedCheckedList; import org.apache.sis.util.Classes; import org.opengis.sld.Constraint; import org.opengis.sld.SLDLibrary; import org.opengis.sld.SLDVisitor; import org.opengis.style.Description; import static org.apache.sis.util.ArgumentChecks.*; /** * Default mutable Style Layer Descriptor, thread safe. * * @author Johann Sorel (Geomatys) * @module */ class DefaultMutableSLD implements MutableStyledLayerDescriptor{ private final List<SLDLibrary> libraries = new NotifiedCheckedList<SLDLibrary>(SLDLibrary.class) { @Override protected Object getLock() { return DefaultMutableSLD.this; } @Override protected void notifyAdd(final SLDLibrary item, final int index) { fireLibraryChange(CollectionChangeEvent.ITEM_ADDED, item, NumberRange.create(index, true, index, true)); } @Override protected void notifyAdd(final Collection<? extends SLDLibrary> items, final NumberRange<Integer> range) { fireLibraryChange(CollectionChangeEvent.ITEM_ADDED, items, range); } @Override protected void notifyRemove(final SLDLibrary item, final int index) { fireLibraryChange(CollectionChangeEvent.ITEM_REMOVED, item, NumberRange.create(index, true, index, true)); } @Override protected void notifyRemove(Collection<? extends SLDLibrary> items, NumberRange<Integer> range) { fireLibraryChange(CollectionChangeEvent.ITEM_REMOVED, items, range); } @Override protected void notifyChange(SLDLibrary oldItem, SLDLibrary newItem, int index) { fireLibraryChange(CollectionChangeEvent.ITEM_CHANGED, oldItem, NumberRange.create(index, true, index, true)); } }; private final List<MutableLayer> layers = new NotifiedCheckedList<MutableLayer>(MutableLayer.class) { @Override protected Object getLock() { return DefaultMutableSLD.this; } @Override protected void notifyAdd(final MutableLayer item, final int index) { item.addListener(layerListener); fireLayerChange(CollectionChangeEvent.ITEM_ADDED, item, NumberRange.create(index, true, index, true)); } @Override protected void notifyAdd(final Collection<? extends MutableLayer> items, final NumberRange<Integer> range) { for(MutableLayer item : items){ item.addListener(layerListener); } fireLayerChange(CollectionChangeEvent.ITEM_ADDED, items, range); } @Override protected void notifyRemove(final MutableLayer item, final int index) { item.removeListener(layerListener); fireLayerChange(CollectionChangeEvent.ITEM_REMOVED, item, NumberRange.create(index, true, index, true)); } @Override protected void notifyRemove(Collection<? extends MutableLayer> items, NumberRange<Integer> range) { for(final MutableLayer ml : items){ ml.removeListener(layerListener); } fireLayerChange(CollectionChangeEvent.ITEM_REMOVED, items, range); } @Override protected void notifyChange(MutableLayer oldItem, MutableLayer newItem, int index) { if(oldItem != null){ oldItem.removeListener(layerListener); } if(newItem != null){ newItem.addListener(layerListener); } fireLayerChange(CollectionChangeEvent.ITEM_CHANGED, oldItem, NumberRange.create(index, true, index, true)); } }; private final LayerListener layerListener = new LayerListener() { @Override public void propertyChange(PropertyChangeEvent event) { fireLayerChange(CollectionChangeEvent.ITEM_CHANGED, (MutableLayer)event.getSource(), null, event); } @Override public void styleChange(CollectionChangeEvent<MutableLayerStyle> event) { fireLayerChange(CollectionChangeEvent.ITEM_CHANGED, (MutableLayer)event.getSource(), null, event); } @Override public void constraintChange(CollectionChangeEvent<Constraint> event) { fireLayerChange(CollectionChangeEvent.ITEM_CHANGED, (MutableLayer)event.getSource(), null, event); } }; private final EventListenerList listeners = new EventListenerList(); private String version = "1.1"; private String name = null; private Description description = StyleConstants.DEFAULT_DESCRIPTION; /** * {@inheritDoc } * This method is thread safe. */ @Override public String getName() { return name; } /** * {@inheritDoc } * This method is thread safe. */ @Override public void setName(final String name) { final String oldName; synchronized (this) { oldName = this.name; if (Objects.equals(oldName, name)) { return; } this.name = name; } firePropertyChange(NAME_PROPERTY, oldName, this.name); } /** * {@inheritDoc } * This method is thread safe. */ @Override public Description getDescription() { return description; } /** * {@inheritDoc } * This method is thread safe. */ @Override public void setDescription(final Description desc) { ensureNonNull("description", desc); final Description oldDesc; synchronized (this) { oldDesc = this.description; if(oldDesc.equals(desc)){ return; } this.description = desc; } firePropertyChange(DESCRIPTION_PROPERTY, oldDesc, this.description); } /** * {@inheritDoc } * This method is thread safe. */ @Override public String getVersion() { return version; } /** * {@inheritDoc } * This method is thread safe. */ @Override public void setVersion(final String version) { final String oldVersion; synchronized (this) { oldVersion = this.version; if (Objects.equals(oldVersion, version)) { return; } this.version = version; } firePropertyChange(VERSION_PROPERTY, oldVersion, this.version); } /** * {@inheritDoc } * This method is thread safe. * This is the live list. */ @Override public List<SLDLibrary> libraries() { return libraries; } /** * {@inheritDoc } * This method is thread safe. * This is the live list. */ @Override public List<MutableLayer> layers() { return layers; } /** * {@inheritDoc } */ @Override public Object accept(final SLDVisitor visitor, final Object extraData) { return visitor.visit(this, extraData); } //-------------------------------------------------------------------------- // listeners management ---------------------------------------------------- //-------------------------------------------------------------------------- protected void firePropertyChange(final String propertyName, final Object oldValue, final Object newValue){ //TODO make fire property change thread safe, preserve fire order final PropertyChangeEvent event = new PropertyChangeEvent(this,propertyName,oldValue,newValue); final SLDListener[] lists = listeners.getListeners(SLDListener.class); for(SLDListener listener : lists){ listener.propertyChange(event); } } protected void fireLibraryChange(final int type, final SLDLibrary lib, final NumberRange<Integer> range) { //TODO make fire property change thread safe, preserve fire order final CollectionChangeEvent<SLDLibrary> event = new CollectionChangeEvent<SLDLibrary>(this, lib, type, range, null); final SLDListener[] lists = listeners.getListeners(SLDListener.class); for(SLDListener listener : lists){ listener.libraryChange(event); } } protected void fireLibraryChange(final int type, final SLDLibrary lib, final NumberRange<Integer> range, final EventObject subEvent) { //TODO make fire property change thread safe, preserve fire order final CollectionChangeEvent<SLDLibrary> event = new CollectionChangeEvent<SLDLibrary>(this, lib, type, range,subEvent); final SLDListener[] lists = listeners.getListeners(SLDListener.class); for(SLDListener listener : lists){ listener.libraryChange(event); } } protected void fireLibraryChange(final int type, final Collection<? extends SLDLibrary> lib, final NumberRange<Integer> range){ //TODO make fire property change thread safe, preserve fire order final CollectionChangeEvent<SLDLibrary> event = new CollectionChangeEvent<SLDLibrary>(this,lib,type,range, null); final SLDListener[] lists = listeners.getListeners(SLDListener.class); for(SLDListener listener : lists){ listener.libraryChange(event); } } protected void fireLayerChange(final int type, final MutableLayer layer, final NumberRange<Integer> range) { //TODO make fire property change thread safe, preserve fire order final CollectionChangeEvent<MutableLayer> event = new CollectionChangeEvent<MutableLayer>(this, layer, type, range, null); final SLDListener[] lists = listeners.getListeners(SLDListener.class); for(SLDListener listener : lists){ listener.layerChange(event); } } protected void fireLayerChange(final int type, final MutableLayer layer, final NumberRange<Integer> range, final EventObject subEvent) { //TODO make fire property change thread safe, preserve fire order final CollectionChangeEvent<MutableLayer> event = new CollectionChangeEvent<MutableLayer>(this, layer, type, range,subEvent); final SLDListener[] lists = listeners.getListeners(SLDListener.class); for(SLDListener listener : lists){ listener.layerChange(event); } } protected void fireLayerChange(final int type, final Collection<? extends MutableLayer> layer, final NumberRange<Integer> range){ //TODO make fire property change thread safe, preserve fire order final CollectionChangeEvent<MutableLayer> event = new CollectionChangeEvent<MutableLayer>(this,layer,type,range, null); final SLDListener[] lists = listeners.getListeners(SLDListener.class); for(SLDListener listener : lists){ listener.layerChange(event); } } /** * {@inheritDoc } */ @Override public void addListener(final SLDListener listener) { listeners.add(SLDListener.class, listener); } /** * {@inheritDoc } */ @Override public void removeListener(final SLDListener listener) { listeners.remove(SLDListener.class, listener); } /** * {@inheritDoc } */ @Override public boolean equals(final Object obj) { if(this == obj){ return true; } if(obj == null || !this.getClass().equals(obj.getClass()) ){ return false; } DefaultMutableSLD other = (DefaultMutableSLD) obj; return Objects.equals(this.name, other.name) && Objects.equals(this.version, other.version) && this.description.equals(other.description) && this.layers.equals(other.layers) && this.libraries.equals(other.libraries); } /** * {@inheritDoc } */ @Override public int hashCode() { int hash = 3; if(name != null) hash *= name.hashCode(); if(version != null) hash *= version.hashCode(); hash *= description.hashCode(); hash *= layers.hashCode(); hash *= libraries.hashCode(); return hash; } /** * {@inheritDoc } */ @Override public String toString() { final StringBuilder builder = new StringBuilder(); builder.append("SLD : "); builder.append(Classes.getShortClassName(this)); builder.append(" ["); if(name != null){ builder.append(" Name="); builder.append(name); } builder.append(" Description="); builder.append(description); if(version != null){ builder.append(" Version="); builder.append(version); } builder.append(" LayerSize="); builder.append(layers.size()); builder.append(" LibrarySize="); builder.append(libraries.size()); builder.append(']'); if(!layers.isEmpty()){ builder.append(Trees.toString("", layers)); } return builder.toString(); } /** * {@inheritDoc } * @todo the complete clone must be applied on the attributes. */ @Override public DefaultMutableSLD clone() { DefaultMutableSLD object = null; try { object = (DefaultMutableSLD) super.clone(); } catch(CloneNotSupportedException cnse) { cnse.printStackTrace(System.err); } return object; } }