package org.signalml.domain.tag;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import javax.swing.KeyStroke;
import javax.swing.event.EventListenerList;
import org.signalml.plugin.export.signal.SignalSelectionType;
import org.signalml.plugin.export.signal.TagStyle;
/**
* This class contains a set of page, block and channel styles.
* It is most often used inside of a {@link StyledTagSet} to manage
* the {@link TagStyle tag styles} used.
*
* @author Piotr Szachewicz
*/
public class TagStyles {
/**
* Map associating tag styles with KeyStrokes assign to them
*/
private HashMap<KeyStroke, TagStyle> stylesByKeyStrokes;
/**
* list of styles of selections of signal pages
*/
private List<TagStyle> pageStyles = new ArrayList<TagStyle>();
/**
* list of styles of selections of signal blocks
*/
private List<TagStyle> blockStyles = new ArrayList<TagStyle>();
/**
* list of styles of custom selections of single channels
*/
private List<TagStyle> channelStyles = new ArrayList<TagStyle>();
/**
* list of listeners associated with the current object
*/
private EventListenerList listenerList = new EventListenerList();
/**
* The {@link StyledTagSet} in which this {@link TagStyles} are used.
* It is necessary to inform its listeners that the styles have changed.
*/
private StyledTagSet styledTagSet;
/**
* Constructor.
*/
public TagStyles() {
}
/**
* Constructor. Creates a
* @param styles
*/
public TagStyles(Collection<TagStyle> styles) {
for (TagStyle style : styles) {
SignalSelectionType type = style.getType();
if (type == SignalSelectionType.PAGE) {
pageStyles.add(style);
} else if (type == SignalSelectionType.BLOCK) {
blockStyles.add(style);
} else if (type == SignalSelectionType.CHANNEL) {
channelStyles.add(style);
}
}
}
/**
* Sets the {@link StyledTagSet} that uses this {@link TagStyles}.
* (Please note: only one tag set may use a single {@link TagStyles}
* object.)
* @param styledTagSet the {@link StyledTagSet} that uses this {@link TagStyles}
*/
public void setStyledTagSet(StyledTagSet styledTagSet) {
this.styledTagSet = styledTagSet;
}
/**
* Returns the list of all {@link TagStyle tag styles} contained in this
* {@link TagStyles}.
* @return all tag styles available
*/
public List<TagStyle> getAllStyles() {
ArrayList<TagStyle> allStyles = new ArrayList<TagStyle>();
allStyles.addAll(pageStyles);
allStyles.addAll(blockStyles);
allStyles.addAll(channelStyles);
return allStyles;
}
/**
* Returns {@link TagStyle tag styles} of a given type.
*
* @param type {@link SignalSelectionType the type} of the styles to
* be returned
* @param allowMarkers determines whether on the returned list marker
* styles may be allowed
* @return all styles of the given type if allowMarkers is true,
* or all styles of the given type excluding markers if allowMarkers
* is false
*/
public List<TagStyle> getStyles(SignalSelectionType type, boolean allowMarkers) {
List<TagStyle> styles = new ArrayList<TagStyle>();
if (allowMarkers) {
styles = getStyles(type);
} else {
for (TagStyle style : getStyles(type)) {
if (!style.isMarker()) {
styles.add(style);
}
}
}
return styles;
}
/**
* Returns the list of styles of a given type.
* @param type the type of styles to be returned.
* @return the styles available in this {@link TagStyles}
*/
public List<TagStyle> getStyles(SignalSelectionType type) {
if (type == SignalSelectionType.BLOCK) {
return blockStyles;
} else if (type == SignalSelectionType.CHANNEL) {
return channelStyles;
} else if (type == SignalSelectionType.PAGE) {
return pageStyles;
} else {
return null;
}
}
/**
* Returns the style having the given name. (If more than one styles
* have equal names, the first on the list is returned).
* @param name the name of the style
* @return the style having the given name
*/
public TagStyle getStyle(String name) {
return getStyle(null, name);
}
/**
* Returns the style of a given type and name.
* @param type the {@link SignalSelectionType} of the style
* @param name the name of the style
* @return the style of the given name and type or null if no such
* style exists.
*/
public TagStyle getStyle(SignalSelectionType type, String name) {
List<TagStyle> styles;
if (type == null) {
styles = getAllStyles();
} else {
styles = getStyles(type);
}
for (TagStyle style : styles) {
if (style.getName().compareTo(name) == 0) {
return style;
}
}
return null;
}
/**
* Returns the number of all styles available.
* @return
*/
public int getStylesCount() {
return pageStyles.size() + blockStyles.size() + channelStyles.size();
}
/**
* Returns the number of styles of the given type available in this {@link TagStyles}.
* @param type the type of the styles to be counted
* @return the number of styles of the given type
*/
public int getStylesCount(SignalSelectionType type) {
return getStyles(type).size();
}
/**
* Returns the style of a given index in an array of styles of a given
* type.
* @param type the type of styles to be concerned
* @param index the index of the style to be returned
* @return the style of the given index and the given type
*/
public TagStyle getStyleAt(SignalSelectionType type, int index) {
return getStyles(type).get(index);
}
/**
* Returns the index of the given style.
* @param style the style which index will be returned
* @return the index of the given style
*/
public int getIndexOf(TagStyle style) {
return getStyles(style.getType()).indexOf(style);
}
/**
* Removes the given style from this {@link TagStyles}.
* @param style the style to be removed
*/
public void removeStyle(TagStyle style) {
if (style != null) {
int inTypeIndex = getIndexOf(style);
getStyles(style.getType()).remove(style);
fireTagStyleRemoved(style, inTypeIndex);
invalidateStylesByKeystrokes();
}
}
/**
* Updates the style of the given name to the given style.
* @param name the name of the style in this {@link TagStyles} to be updated
* @param style the style containing the new values for the style
* (the type of the style to be updated is also taken from this object)
*/
public void updateStyle(String name, TagStyle style) {
TagStyle existingStyle = getStyle(style.getType(), name);
if (existingStyle == null) {
addStyle(style);
return;
}
existingStyle.copyFrom(style);
if (!style.getName().equals(name)) {
existingStyle.setName(style.getName());
}
// invalidate map
stylesByKeyStrokes = null;
fireTagStyleChanged(existingStyle, getIndexOf(existingStyle));
}
/**
* Adds a new style to this {@link TagStyles}.
* @param style the style to be added
*/
public void addStyle(TagStyle style) {
getStyles(style.getType()).add(style);
KeyStroke keyStroke = style.getKeyStroke();
if (keyStroke != null) {
getStylesByKeyStrokes().put(keyStroke, style);
}
invalidateStylesByKeystrokes();
fireTagStyleAdded(style, getIndexOf(style));
}
/**
* Returns the map associating {@link TagStyle tag styles} with
* KeyStrokes assigned to them.
* @return the map associating tag styles with KeyStrokes assign to them.
*/
public HashMap<KeyStroke, TagStyle> getStylesByKeyStrokes() {
if (stylesByKeyStrokes == null) {
stylesByKeyStrokes = new HashMap<KeyStroke, TagStyle>();
KeyStroke keyStroke;
for (TagStyle style : getAllStyles()) {
keyStroke = style.getKeyStroke();
if (keyStroke != null) {
stylesByKeyStrokes.put(keyStroke, style);
}
}
}
return stylesByKeyStrokes;
}
/**
* Invalidates the hashmap of styles keystrokes.
*/
protected void invalidateStylesByKeystrokes() {
stylesByKeyStrokes = null;
}
/**
* Adds a {@link TagStyleListener TagStyleListener} to the list
* of listeners.
* @param listener the TagStyleListener to be added
*/
public void addTagStyleListener(TagStyleListener listener) {
listenerList.add(TagStyleListener.class, listener);
}
/**
* Removes a {@link TagStyleListener TagStyleListener} from the list
* of listeners.
* @param listener the TagStyleListener to be removed
*/
public void removeTagStyleListener(TagStyleListener listener) {
listenerList.remove(TagStyleListener.class, listener);
}
/**
* Fires all {@link TagStyleListener tag style listeners} that a
* {@link TagStyle tag style} of a given index has been added.
* @param tagStyle the added tag style
* @param inTypeIndex an index in an array of tag styles of a given type
*/
protected void fireTagStyleAdded(TagStyle tagStyle, int inTypeIndex) {
Object[] listeners = listenerList.getListenerList();
TagStyleEvent e = null;
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == TagStyleListener.class) {
if (e == null) {
e = new TagStyleEvent(styledTagSet, tagStyle, inTypeIndex);
}
((TagStyleListener) listeners[i + 1]).tagStyleAdded(e);
}
}
}
/**
* Fires all {@link TagStyleListener tag style listeners} that a
* {@link TagStyle tag style} of a given index has been removed.
* @param tagStyle the removed tag style
* @param inTypeIndex an index in an array of tag styles of a given type
*/
protected void fireTagStyleRemoved(TagStyle tagStyle, int inTypeIndex) {
Object[] listeners = listenerList.getListenerList();
TagStyleEvent e = null;
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == TagStyleListener.class) {
if (e == null) {
e = new TagStyleEvent(styledTagSet, tagStyle, inTypeIndex);
}
((TagStyleListener) listeners[i + 1]).tagStyleRemoved(e);
}
}
}
/**
* Fires {@link TagStyleListener tag style listeners} that a
* {@link TagStyle tag style} of a given index has been changed.
* @param tagStyle the changed tag style
* @param inTypeIndex an index in an array of tag styles of a given type
*/
protected void fireTagStyleChanged(TagStyle tagStyle, int inTypeIndex) {
Object[] listeners = listenerList.getListenerList();
TagStyleEvent e = null;
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == TagStyleListener.class) {
if (e == null) {
e = new TagStyleEvent(styledTagSet, tagStyle, inTypeIndex);
}
((TagStyleListener) listeners[i + 1]).tagStyleChanged(e);
}
}
}
@Override
public TagStyles clone() {
TagStyles newStyles = new TagStyles();
newStyles.pageStyles = copyTagList(pageStyles);
newStyles.blockStyles = copyTagList(blockStyles);
newStyles.channelStyles = copyTagList(channelStyles);
return newStyles;
}
/**
* Returns a list containing copies of the {@link TagStyle tag styles}
* from the sourceList.
* @param sourceList the list from which styles are to be copied.
* @return the list of tag styles copies
*/
protected List<TagStyle> copyTagList(List<TagStyle> sourceList) {
List<TagStyle> destinationList = new ArrayList<TagStyle>();
for (TagStyle style : sourceList) {
destinationList.add(new TagStyle(style));
}
return destinationList;
}
}