/* * Freeplane - mind map editor * Copyright (C) 2008 Dimitry Polivaev * * This file author is Dimitry Polivaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.freeplane.features.filter.condition; import java.util.Date; import org.freeplane.core.io.xml.TreeXmlWriter; import org.freeplane.core.resources.ResourceController; import org.freeplane.core.util.TextUtils; import org.freeplane.core.util.TypeReference; import org.freeplane.features.filter.ExactStringMatchingStrategy; import org.freeplane.features.filter.StringMatchingStrategy; import org.freeplane.features.format.FormattedDate; import org.freeplane.features.format.FormattedNumber; import org.freeplane.features.format.IFormattedObject; import org.freeplane.n3.nanoxml.XMLElement; /** * Adapter for Conditions which compare values (</<=/>/>=/=/!=) * * @author ? * */ abstract public class CompareConditionAdapter extends ASelectableCondition { public static final String OBJECT = "OBJECT"; public static final String MATCH_CASE = "MATCH_CASE"; public static final String MATCH_APPROXIMATELY = "MATCH_APPROXIMATELY"; public static final String VALUE = "VALUE"; private Comparable<?> conditionValue; final private boolean matchCase; final protected boolean matchApproximately; final StringMatchingStrategy stringMatchingStrategy; private int comparisonResult; private boolean error; abstract public boolean isEqualityCondition(); @SuppressWarnings("deprecation") protected CompareConditionAdapter(final Object value, final boolean matchCase, final boolean matchApproximately) { super(); this.matchCase = matchCase; this.matchApproximately = matchApproximately; stringMatchingStrategy = matchApproximately ? StringMatchingStrategy.DEFAULT_APPROXIMATE_STRING_MATCHING_STRATEGY : new ExactStringMatchingStrategy(); final ResourceController resourceController = ResourceController.getResourceController(); if(value instanceof String && resourceController.getBooleanProperty("compare_as_number") && TextUtils.isNumber((String) value)) { Number number = TextUtils.toNumber((String) value); if(number instanceof Comparable<?>){ conditionValue = (Comparable<?>) number; } return; } if(value instanceof FormattedNumber){ conditionValue = (FormattedNumber)value; return; } if(value instanceof FormattedDate){ final FormattedDate date = (FormattedDate) value; if(date.containsTime() || date.getHours() == 0 && date.getMinutes() == 0 && date.getSeconds() == 0) { conditionValue = date; } else{ final Date reducedDate = new Date(date.getYear(), date.getMonth(), date.getDate()); conditionValue = new FormattedDate(reducedDate.getTime(), date.getDateFormat()); } return; } conditionValue = value.toString(); } protected CompareConditionAdapter(final Double value) { super(); this.matchCase = false; this.matchApproximately = false; conditionValue = value; stringMatchingStrategy = matchApproximately ? StringMatchingStrategy.DEFAULT_APPROXIMATE_STRING_MATCHING_STRATEGY : new ExactStringMatchingStrategy(); } protected CompareConditionAdapter(final Long value) { super(); this.matchCase = false; this.matchApproximately = false; conditionValue = value; stringMatchingStrategy = matchApproximately ? StringMatchingStrategy.DEFAULT_APPROXIMATE_STRING_MATCHING_STRATEGY : new ExactStringMatchingStrategy(); } @Override public void fillXML(final XMLElement child) { super.fillXML(child); if(conditionValue instanceof IFormattedObject){ child.setAttribute(OBJECT, TypeReference.toSpec(conditionValue)); } else child.setAttribute(CompareConditionAdapter.VALUE, conditionValue.toString()); child.setAttribute(CompareConditionAdapter.MATCH_CASE, TreeXmlWriter.BooleanToXml(matchCase)); child.setAttribute(CompareConditionAdapter.MATCH_APPROXIMATELY, TreeXmlWriter.BooleanToXml(matchApproximately)); } protected void compareTo(final Object transformedContent) throws NumberFormatException { error = false; comparisonResult = Integer.signum(compareToData(transformedContent)); } private int compareToData(final Object transformedContent) { if (conditionValue instanceof FormattedNumber && transformedContent instanceof Number){ return -((FormattedNumber)conditionValue).compareTo((Number)transformedContent); } if (conditionValue instanceof Number && transformedContent instanceof String) { try { Number number = TextUtils.toNumber((String)transformedContent); if (conditionValue instanceof FormattedNumber){ return -((FormattedNumber)conditionValue).compareTo(number); } if(number instanceof Long) return compareTo((Long)number); if(number instanceof Double) return compareTo((Double)number); } catch (final NumberFormatException fne) { }; error = true; return 0; } if (conditionValue instanceof FormattedDate) { if (transformedContent instanceof FormattedDate) { return compareTo((FormattedDate)transformedContent); } error = true; return 0; } final String valueAsString = conditionValue.toString(); final String text = transformedContent.toString(); if (isEqualityCondition()) { return stringMatchingStrategy.matches(valueAsString, text, false, matchCase) ? 0 : -1; } else { return matchCase ? text.compareTo(valueAsString) : text.compareToIgnoreCase(valueAsString); } } protected int getComparisonResult() { return comparisonResult; } protected boolean isComparisonOK() { return ! error; } private int compareTo(final Double value) { return value.compareTo(((Number) conditionValue).doubleValue()); } protected int compareTo(final Long value) { return value.compareTo((Long) conditionValue); } @SuppressWarnings("deprecation") private int compareTo(final Date value) { if (((FormattedDate) conditionValue).containsTime() || (value.getHours() == 0 && value.getMinutes() == 0 && value.getSeconds() == 0)) return value.compareTo((Date) conditionValue); return new Date(value.getYear(), value.getMonth(), value.getDate()).compareTo((Date) conditionValue); } public String createDescription(final String attribute, final int comparationResult, final boolean succeed) { String simpleCondition; switch (comparationResult) { case -1: simpleCondition = succeed ? ConditionFactory.FILTER_LT : ConditionFactory.FILTER_GE; break; case 0: simpleCondition = TextUtils.getText(succeed ? ConditionFactory.FILTER_IS_EQUAL_TO : ConditionFactory.FILTER_IS_NOT_EQUAL_TO); break; case 1: simpleCondition = succeed ? ConditionFactory.FILTER_GT : ConditionFactory.FILTER_LE; break; default: throw new IllegalArgumentException(); } return ConditionFactory.createDescription(attribute, simpleCondition, valueDescription(), matchCase, matchApproximately); } private String valueDescription() { return conditionValue.toString(); } public Comparable<?> getConditionValue() { return conditionValue; } }