/*
* Copyright (c) 2005-2016 Vincent Vandenschrick. All rights reserved.
*
* This file is part of the Jspresso framework.
*
* Jspresso 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 3 of the License, or
* (at your option) any later version.
*
* Jspresso 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Jspresso. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jspresso.framework.util.event;
import java.util.Arrays;
import java.util.Set;
import gnu.trove.set.hash.THashSet;
import gnu.trove.set.hash.TLinkedHashSet;
/**
* Helper class to ease the {@code ISelectionChangeListener} management.
*
* @author Vincent Vandenschrick
*/
public class SelectionChangeSupport implements ISelectable {
private Set<ISelectionChangeListener> inhibitedListeners;
private int leadingIndex;
private Set<ISelectionChangeListener> listeners;
private int[] oldSelectedIndices;
private int[] selectedIndices;
private ISelectable source;
/**
* Constructs a new support.
*
* @param source
* The selectable to which this support is attached. It will serve as
* {@code source} of fired {@code SelectionChangeEvent}s if
* no other is provided.
*/
public SelectionChangeSupport(ISelectable source) {
if (source == null) {
throw new NullPointerException();
}
this.source = source;
}
/**
* Registers a listener to be excluded (generally temporarily) from the
* notification process without being removed from the actual listeners
* collection.
*
* @param listener
* the excluded listener.
*/
public void addInhibitedListener(ISelectionChangeListener listener) {
if (inhibitedListeners == null && listener != null) {
inhibitedListeners = new TLinkedHashSet<>(1);
}
if (inhibitedListeners != null) {
inhibitedListeners.add(listener);
}
}
/**
* {@inheritDoc}
*/
@Override
public synchronized void addSelectionChangeListener(
ISelectionChangeListener listener) {
if (listener != null) {
if (listeners == null) {
listeners = new THashSet<>(1);
}
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
}
/**
* Fires a new {@code SelectionChangeEvent} built with
* {@code source} as source and parameters as old and new values.
*/
public void fireSelectionChange() {
SelectionChangeEvent evt = new SelectionChangeEvent(source,
oldSelectedIndices, selectedIndices, leadingIndex);
fireSelectionChange(evt);
}
/**
* Propagates the {@code SelectionChangeEvent} as is (i.e. without
* modifying its source) to the listeners.
*
* @param evt
* the propagated {@code BeanChangeEvent}
*/
public void fireSelectionChange(SelectionChangeEvent evt) {
if (listeners != null) {
int[] oldSelection = evt.getOldSelection();
if (oldSelection != null && oldSelection.length == 0) {
oldSelection = null;
}
int[] newSelection = evt.getNewSelection();
if (newSelection != null && newSelection.length == 0) {
newSelection = null;
}
if (oldSelection == null && newSelection == null) {
return;
}
if (oldSelection != null && newSelection != null
&& Arrays.equals(oldSelection, newSelection)) {
return;
}
for (ISelectionChangeListener listener : listeners.toArray(new ISelectionChangeListener[listeners.size()])) {
if (inhibitedListeners == null
|| !inhibitedListeners.contains(listener)) {
listener.selectionChange(evt);
}
}
}
}
/**
* {@inheritDoc}
*/
@Override
public int[] getSelectedIndices() {
return selectedIndices;
}
/**
* Registers a listener to be re-included to the notification process without
* being re-added to the actual listeners collection.
*
* @param listener
* the previously excluded listener.
*/
public void removeInhibitedListener(ISelectionChangeListener listener) {
if (inhibitedListeners == null || listener == null) {
return;
}
inhibitedListeners.remove(listener);
if (inhibitedListeners.size() == 0) {
inhibitedListeners = null;
}
}
/**
* {@inheritDoc}
*/
@Override
public synchronized void removeSelectionChangeListener(
ISelectionChangeListener listener) {
if (listeners == null || listener == null) {
return;
}
listeners.remove(listener);
if (listeners.size() == 0) {
listeners = null;
}
}
/**
* {@inheritDoc}
*/
@Override
public void setSelectedIndices(int... selectedIndices) {
int leadingInd = -1;
if (selectedIndices != null && selectedIndices.length > 0) {
leadingInd = selectedIndices[selectedIndices.length - 1];
}
setSelectedIndices(selectedIndices, leadingInd);
}
/**
* {@inheritDoc}
*/
@Override
public void setSelectedIndices(int[] selectedInds, int leadingInd) {
this.oldSelectedIndices = this.selectedIndices;
this.selectedIndices = selectedInds;
this.leadingIndex = leadingInd;
fireSelectionChange();
}
}