Skip to main content
summaryrefslogtreecommitdiffstats
blob: 2d5e192bd9a3a6917bb49341255db696a9dd8617 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*******************************************************************************
 * Copyright (c) 2007 Oracle. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0, which accompanies this distribution
 * and is available at http://www.eclipse.org/legal/epl-v10.html.
 * 
 * Contributors:
 *     Oracle - initial API and implementation
 ******************************************************************************/
package org.eclipse.jpt.utility.internal.model.value;

import org.eclipse.jpt.utility.internal.BidiFilter;
import org.eclipse.jpt.utility.internal.model.event.PropertyChangeEvent;

/**
 * A <code>FilteringPropertyValueModel</code> wraps another
 * <code>PropertyValueModel</code> and uses a <code>BidiFilter</code>
 * to determine when the wrapped value is to be returned by calls
 * to <code>value()</code> and modified by calls to
 * <code>setValue(Object)</code>
 * <p>
 * As an alternative to building a <code>BidiFilter</code>, a subclass
 * of <code>FilteringPropertyValueModel</code> can override the
 * <code>accept(Object)</code> and <code>reverseAccept(Object)</code>
 * methods.
 * <p>
 * One, possibly undesirable, side-effect of using this value model is that
 * it must return *something* as the value. The default behavior is
 * to return <code>null</code> whenever the wrapped value is not "accepted",
 * which can be configured and/or overridden.
 * <p>
 * Likewise, if an incoming value is not "reverseAccepted", *nothing* will passed
 * through to the wrapped value holder, not even <code>null</code>.
 */
public class FilteringPropertyValueModel
	extends PropertyValueModelWrapper
{
	private final BidiFilter filter;
	private final Object defaultValue;


	// ********** constructors **********

	/**
	 * Construct a property value model with the specified nested
	 * property value model and a disabled filter.
	 * Use this constructor if you want to override the
	 * <code>accept(Object)</code> and <code>reverseAccept(Object)</code>
	 * methods instead of building a <code>BidiFilter</code>.
	 * The default value will be <code>null</code>.
	 */
	public FilteringPropertyValueModel(PropertyValueModel valueHolder) {
		this(valueHolder, BidiFilter.Disabled.instance(), null);
	}

	/**
	 * Construct a property value model with the specified nested
	 * property value model, specified default value, and a disabled filter.
	 * Use this constructor if you want to override the
	 * <code>accept(Object)</code> and <code>reverseAccept(Object)</code>
	 * methods instead of building a <code>BidiFilter</code>
	 * <em>and</em> you need to specify
	 * a default value other than <code>null</code>.
	 */
	public FilteringPropertyValueModel(PropertyValueModel valueHolder, Object defaultValue) {
		this(valueHolder, BidiFilter.Disabled.instance(), defaultValue);
	}

	/**
	 * Construct an property value model with the specified nested
	 * property value model and filter.
	 * The default value will be <code>null</code>.
	 */
	public FilteringPropertyValueModel(PropertyValueModel valueHolder, BidiFilter filter) {
		this(valueHolder, filter, null);
	}

	/**
	 * Construct an property value model with the specified nested
	 * property value model, filter, and default value.
	 */
	public FilteringPropertyValueModel(PropertyValueModel valueHolder, BidiFilter filter, Object defaultValue) {
		super(valueHolder);
		this.filter = filter;
		this.defaultValue = defaultValue;
	}


	// ********** ValueModel implementation **********

	public Object value() {
		return this.filterValue(this.valueHolder.value());
	}


	// ********** PropertyValueModel implementation **********

	public void setValue(Object value) {
		if (this.reverseAccept(value)) {
			this.valueHolder.setValue(value);
		}
	}


	// ********** PropertyValueModelWrapper implementation **********

	@Override
	protected void valueChanged(PropertyChangeEvent e) {
		// filter the values before propagating the change event
		Object oldValue = this.filterValue(e.oldValue());
		Object newValue = this.filterValue(e.newValue());
		this.firePropertyChanged(VALUE, oldValue, newValue);
	}


	// ********** queries **********

	/**
	 * If the specified value is "accepted" simply return it,
	 * otherwise return the default value.
	 */
	protected Object filterValue(Object value) {
		return this.accept(value) ? value : this.defaultValue();
	}

	/**
	 * Return whether the <code>FilteringPropertyValueModel</code> should
	 * return the specified value from a call to the
	 * <code>value()</code> method; the value came
	 * from the nested property value model
	 * <p>
	 * This method can be overridden by a subclass as an
	 * alternative to building a <code>BidiFilter</code>.
	 */
	protected boolean accept(Object value) {
		return this.filter.accept(value);
	}

	/**
	 * Return whether the <code>FilteringPropertyValueModel</code>
	 * should pass through the specified value to the nested
	 * property value model in a call to the
	 * <code>setValue(Object)</code> method
	 * <p>
	 * This method can be overridden by a subclass as an
	 * alternative to building a <code>BidiFilter</code>.
	 */
	protected boolean reverseAccept(Object value) {
		return this.filter.reverseAccept(value);
	}

	/**
	 * Return the object that should be returned if
	 * the nested value was rejected by the filter.
	 * The default is <code>null</code>.
	 */
	protected Object defaultValue() {
		return this.defaultValue;
	}

}

Back to the top