package org.freeplane.features.styles;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import org.freeplane.core.extension.IExtension;
import org.freeplane.core.util.TextUtils;
import org.freeplane.features.filter.condition.ASelectableCondition;
import org.freeplane.features.map.NodeModel;
import org.freeplane.n3.nanoxml.XMLElement;
public class ConditionalStyleModel implements IExtension, Iterable<ConditionalStyleModel.Item>{
public class Item{
private ASelectableCondition condition;
private IStyle style;
private boolean isActive;
private boolean isLast;
private Item(boolean isActive, ASelectableCondition condition, IStyle style, boolean isLast) {
super();
this.isActive = isActive;
this.condition = condition;
this.style = style;
this.setLast(isLast);
}
public void setCondition(ASelectableCondition condition) {
this.condition = condition;
}
public ASelectableCondition getCondition() {
return condition;
}
public void setStyle(IStyle style) {
this.style = style;
}
public IStyle getStyle() {
return style;
}
public void setActive(boolean isActive) {
this.isActive = isActive;
}
public boolean isActive() {
return isActive;
}
public void setLast(boolean isLast) {
this.isLast = isLast;
}
public boolean isLast() {
return isLast;
}
public void toXml(XMLElement conditionalStylesRoot)
{
final XMLElement itemElement = conditionalStylesRoot.createElement("conditional_style");
conditionalStylesRoot.addChild(itemElement);
itemElement.setAttribute("ACTIVE", Boolean.toString(isActive()));
final IStyle style = getStyle();
if (style instanceof StyleNamedObject) {
final String referencedStyle = ((StyleNamedObject)style).getObject().toString();
itemElement.setAttribute("LOCALIZED_STYLE_REF", referencedStyle);
}
else {
final String referencedStyle = style.toString();
itemElement.setAttribute("STYLE_REF", referencedStyle);
}
itemElement.setAttribute("LAST", Boolean.toString(isLast()));
if(condition != null)
condition.toXml(itemElement);
}
}
private ArrayList<Item> styles;
public ConditionalStyleModel() {
super();
this.styles = new ArrayList<Item>();
}
private boolean recursiveCall;
public Collection<IStyle> getStyles(NodeModel node){
if(recursiveCall){
return Collections.emptyList();
}
try{
recursiveCall = true;
Collection<IStyle> matchingStyles = new LinkedHashSet<IStyle>();
for(Item item : styles){
final ASelectableCondition condition = item.getCondition();
if( item.isActive() && (condition == null || condition.checkNode(node))){
matchingStyles.add(item.style);
if(item.isLast()){
break;
}
}
}
return matchingStyles;
}
finally{
recursiveCall = false;
}
}
void addCondition(boolean isActive, ASelectableCondition condition, IStyle style, boolean isLast){
styles.add(new Item(isActive, condition, style, isLast));
if(table == null){
return;
}
int index = styles.size() - 1;
table.fireTableRowsInserted(index, index);
}
void insertCondition(int index, boolean isActive, ASelectableCondition condition, IStyle style, boolean isLast){
styles.add(index, new Item(isActive, condition, style, isLast));
if(table == null){
return;
}
table.fireTableRowsInserted(index, index);
}
Item removeCondition(int index){
final Item item = styles.remove(index);
if(table == null){
return item;
}
table.fireTableRowsDeleted(index, index);
return item;
}
void swapConditions(int index1, int index2){
final Item item1 = styles.get(index1);
final Item item2 = styles.get(index2);
styles.set(index1, item2);
styles.set(index2, item1);
if(table == null){
return;
}
table.fireTableRowsUpdated(index1, index1);
table.fireTableRowsUpdated(index2, index2);
}
void moveUp(int index){
if(index == 0){
return;
}
swapConditions(index, index - 1);
}
void moveDown(int index){
if(index == styles.size() - 1){
return;
}
swapConditions(index, index + 1);
}
void clear(){
styles.clear();
}
public Iterator<Item> iterator() {
return styles.iterator();
}
private AbstractTableModel table;
public TableModel asTableModel(){
if(table != null){
return table;
}
table = new AbstractTableModel() {
/**
*
*/
private static final long serialVersionUID = 1L;
public Object getValueAt(int rowIndex, int columnIndex) {
Item item = styles.get(rowIndex);
switch(columnIndex){
case 0:
return item.isActive();
case 1:
return item.getCondition();
case 2:
return item.getStyle();
case 3:
return item.isLast();
default:
throw new ArrayIndexOutOfBoundsException();
}
}
public int getRowCount() {
return styles.size();
}
public int getColumnCount() {
return 4;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch(columnIndex){
case 0:
case 3: return Boolean.class;
case 1: return ASelectableCondition.class;
}
return super.getColumnClass(columnIndex);
}
@Override
public String getColumnName(int column) {
switch(column){
case 0: return TextUtils.getText("active");
case 1: return TextUtils.getText("condition");
case 2: return TextUtils.getText("style");
case 3: return TextUtils.getText("stop_processing");
}
return super.getColumnName(column);
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
Item item = styles.get(rowIndex);
switch(columnIndex){
case 0:
item.setActive((Boolean) aValue);
break;
case 1:
item.setCondition((ASelectableCondition) aValue);
break;
case 2:
item.setStyle((IStyle) aValue);
break;
case 3:
item.setLast((Boolean) aValue);
break;
default:
throw new ArrayIndexOutOfBoundsException();
}
fireTableCellUpdated(rowIndex, columnIndex);
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
};
return table;
}
public int getStyleCount() {
return styles.size();
}
}