/*
* Beanfabrics Framework Copyright (C) by Michael Karneim, beanfabrics.org
* Use is subject to license terms. See license.txt.
*/
// TODO javadoc - remove this comment only when the class and all non-public
// methods and fields are documented
package org.beanfabrics.model;
import java.text.CollationKey;
import java.text.Collator;
import java.util.ResourceBundle;
import org.beanfabrics.event.OptionsEvent;
import org.beanfabrics.event.OptionsListener;
import org.beanfabrics.util.ResourceBundleFactory;
import org.beanfabrics.validation.ValidationRule;
import org.beanfabrics.validation.ValidationState;
/**
* The <code>TextPM</code> is a presentation model for a text value.
* <p>
* The default value is an empty string.
*
* @author Michael Karneim
*/
public class TextPM extends AbstractValuePM implements ITextPM {
protected static final String KEY_MESSAGE_VALUE_NOT_AN_OPTION = "message.not_an_option";
private final ResourceBundle resourceBundle = ResourceBundleFactory.getBundle(TextPM.class);
/**
* The text content of this <code>TextPM</code>. It must never be
* <code>null</code>.
*/
private String text = "";
private String defaultText = "";
private boolean modified = false;
private Options options;
private boolean restrictedToOptions = true;
/**
* Constructs a new <code>TextPM<code>.
*/
public TextPM(String initialText) {
this();
setText(initialText);
}
/**
* Constructs a new <code>TextPM<code>.
*/
public TextPM() {
getValidator().add(new DefaultOptionsValidationRule());
}
/** {@inheritDoc} */
public String getText() {
return text;
}
// TODO (mk) remove this method
public String getText(boolean convertWhitespaceStringToNull) {
if (text.trim().length() == 0) {
return null;
} else {
return text;
}
}
/** {@inheritDoc} */
public void setText(String aText) {
if (aText == null) {
aText = "";
}
if (equals(text, aText)) {
return;
}
String old = text;
text = aText;
revalidate();
updateModified();
getPropertyChangeSupport().firePropertyChange("text", old, text);
}
private void updateModified() {
Boolean old = modified;
modified = (text == null && defaultText == null) || !(text != null && text.equals(defaultText));
getPropertyChangeSupport().firePropertyChange("modified", old, modified);
}
/**
* Get the default text value of this model.
*
* @return the default text value
*/
protected String getDefaultText() {
return defaultText;
}
/**
* Sets the default text value of this model.
* <p>
* Use {@link #reset()} to set the model's value to it's default value or
* {@link #preset()} to set the model's default value to it's current value.
* <p>
* <b>Note:</b> Setting this default value does does not necessarily mean
* that the actual value of this PM is changed to that value also.
*
* @param aText the text to set as default value
*/
protected void setDefaultText(String aText) {
if (aText == null) {
aText = "";
}
String old = defaultText;
defaultText = aText;
updateModified();
revalidate();
getPropertyChangeSupport().firePropertyChange("defaultText", old, defaultText);
}
public boolean isRestrictedToOptions() {
return restrictedToOptions;
}
/**
* If set to <code>true</code> this <code>TextPM</code> is only valid if
* its text content is contained in its options.
*
* @param restrictedToOptions
*/
public void setRestrictedToOptions(boolean restrictedToOptions) {
if (this.restrictedToOptions == restrictedToOptions) {
return;
}
this.restrictedToOptions = restrictedToOptions;
revalidate();
getPropertyChangeSupport().firePropertyChange("restrictedToOptions", !this.restrictedToOptions, this.restrictedToOptions); //$NON-NLS-1$
}
/** {@inheritDoc} */
public boolean isEmpty() {
String text = this.getText();
return text == null || text.trim().length() == 0;
// TODO (mk) think about trimming
}
/** {@inheritDoc} */
public boolean isModified() {
return modified;
}
/** {@inheritDoc} */
public void reset() {
setText(getDefaultText());
}
/** {@inheritDoc} */
public void preset() {
setDefaultText(this.getText());
}
/** {@inheritDoc} */
public void reformat() {
}
public Options getOptions() {
return options;
}
public void setOptions(Options newOptions) {
if (options == newOptions) {
return;
}
Options old = options;
if (options != null) {
options.removeOptionsListener(optionsListener);
}
options = newOptions;
if (options != null) {
options.addOptionsListener(optionsListener);
}
revalidate();
getPropertyChangeSupport().firePropertyChange("options", old, options);
}
/** {@inheritDoc}
* <p>
* The default implementation returns a {@link TextComparable} or one of its subclasses.
* */
@Override
public Comparable<?> getComparable() {
return new TextComparable();
}
/**
* The {@link TextComparable} delegates the comparison to a {@link CollationKey} constructed
* from the PM's text using a {@link Collator}.
*
* @author Michael Karneim
*/
protected class TextComparable implements Comparable {
CollationKey key;
/**
* Constructs a {@link TextComparable} using the locale-sensitve default {@link Collator}.
*/
public TextComparable() {
this(Collator.getInstance());
}
/**
* Constructs a {@link TextComparable} using the given {@link Collator}.
* @param collator
*/
public TextComparable(Collator collator) {
key = collator.getCollationKey(TextPM.this.text);
}
/** {@inheritDoc} */
public int compareTo(Object o) {
if (!(o instanceof TextComparable)) {
throw new IllegalArgumentException("o must be instance of" + TextComparable.class);
}
TextComparable oc = (TextComparable)o;
return key.compareTo(oc.key);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (o.getClass() != getClass()) {
return false;
}
TextComparable oc = (TextComparable)o;
return key.equals(oc.key);
}
@Override
public int hashCode() {
return key.hashCode();
}
}
private final OptionsListener optionsListener = new OptionsListener() {
public void changed(OptionsEvent evt) {
revalidate();
getPropertyChangeSupport().firePropertyChange("options", null, null);
}
};
public class DefaultOptionsValidationRule implements ValidationRule {
public ValidationState validate() {
if (isRestrictedToOptions() && getOptions() != null && !isEmpty()) {
if (getOptions().containsValue(text) == false) {
String message = resourceBundle.getString(KEY_MESSAGE_VALUE_NOT_AN_OPTION);
return new ValidationState(message);
}
}
return null;
}
}
}