/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010, 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;
* version 2.1 of the License.
*
* 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.map;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.*;
import java.util.logging.Logger;
import javax.swing.event.EventListenerList;
import org.geotoolkit.gui.swing.tree.Trees;
import org.geotoolkit.style.StyleConstants;
import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
import org.apache.sis.measure.NumberRange;
import org.geotoolkit.util.Utilities;
import org.geotoolkit.util.collection.CollectionChangeEvent;
import org.apache.sis.util.Classes;
import org.apache.sis.util.logging.Logging;
import org.opengis.style.Description;
/**
* Abstract implementation of a MapItem.
*
* @author Johann Sorel (Geomatys)
* @module
*/
public abstract class AbstractMapItem implements MapItem {
protected static final Logger LOGGER = Logging.getLogger("org.geotoolkit.map");
protected final EventListenerList listeners = new EventListenerList();
private final Map<String,Object> parameters = new HashMap<>();
protected String name = null;
protected Description desc = null;
protected boolean visible = true;
/**
* Constructor that can used by subclass only.
*/
protected AbstractMapItem(){
this.desc = 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 desc;
}
/**
* {@inheritDoc }
* @param desc : Description can't be null
*/
@Override
public void setDescription(final Description desc){
ensureNonNull("description", desc);
final Description oldDesc;
synchronized (this) {
oldDesc = this.desc;
if(oldDesc.equals(desc)){
return;
}
this.desc = desc;
}
firePropertyChange(DESCRIPTION_PROPERTY, oldDesc, this.desc);
}
/**
* Getter for property visible.
*
* @return Value of property visible.
*/
@Override
public boolean isVisible() {
return this.visible;
}
/**
* Setter for property visible.
*
* @param visible : New value of property visible.
*/
@Override
public void setVisible(final boolean visible) {
final boolean oldVisible;
synchronized (this) {
oldVisible = this.visible;
if(oldVisible == visible){
return;
}
this.visible = visible;
}
firePropertyChange(VISIBILITY_PROPERTY, oldVisible, this.visible);
}
/**
* {@inheritDoc }
*/
@Override
public void setUserProperty(final String key,final Object value){
parameters.put(key, value);
}
/**
* {@inheritDoc }
*/
@Override
public Object getUserProperty(final String key){
return parameters.get(key);
}
/**
* {@inheritDoc }
*/
@Override
public Map<String, Object> getUserProperties() {
return parameters;
}
//--------------------------------------------------------------------------
// listeners management ----------------------------------------------------
//--------------------------------------------------------------------------
/**
* {@inheritDoc }
*/
@Override
public void addItemListener(final ItemListener listener){
listeners.add(ItemListener.class, listener);
}
/**
* {@inheritDoc }
*/
@Override
public void removeItemListener(final ItemListener listener){
listeners.remove(ItemListener.class, listener);
}
/**
* {@inheritDoc }
*/
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
listeners.add(PropertyChangeListener.class, listener);
}
/**
* {@inheritDoc }
*/
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
listeners.remove(PropertyChangeListener.class, listener);
}
protected void fireItemChange(final int type, final MapItem item, final NumberRange<Integer> range, final EventObject orig) {
//TODO make fire property change thread safe, preserve fire order
final CollectionChangeEvent<MapItem> event = new CollectionChangeEvent<MapItem>(this, item, type, range, orig);
final ItemListener[] lists = listeners.getListeners(ItemListener.class);
for (ItemListener listener : lists){
listener.itemChange(event);
}
}
protected void fireItemChange(final int type, final Collection<? extends MapItem> item, final NumberRange<Integer> range){
//TODO make fire property change thread safe, preserve fire order
final CollectionChangeEvent<MapItem> event = new CollectionChangeEvent<MapItem>(this,item,type,range, null);
final ItemListener[] lists = listeners.getListeners(ItemListener.class);
for(ItemListener listener : lists){
listener.itemChange(event);
}
}
protected void firePropertyChange(final String propertyName, final Object oldValue, final Object newValue){
//TODO make fire property change thread safe, preserve fire order
final ItemListener[] listIs = listeners.getListeners(ItemListener.class);
final PropertyChangeListener[] listPs = listeners.getListeners(PropertyChangeListener.class);
if(listIs.length==0 && listPs.length==0) return;
final PropertyChangeEvent event = new PropertyChangeEvent(this,propertyName,oldValue,newValue);
for(PropertyChangeListener listener : listIs){
listener.propertyChange(event);
}
for(PropertyChangeListener listener : listPs){
listener.propertyChange(event);
}
}
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append(Classes.getShortClassName(this));
if(name != null){
buf.append(" (");
buf.append(name);
buf.append(") ");
}
if(desc != null){
buf.append(desc);
}
buf.append(" Visible = ");
buf.append(visible);
final List<MapItem> items = items();
if(!items.isEmpty()){
buf.append( Trees.toString("", items) );
}
return buf.toString();
}
}