View Javadoc
1   package fr.ifremer.quadrige3.ui.swing.model;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Quadrige3 UI Common
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2017 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import org.jdesktop.beans.AbstractBean;
27  import org.jdesktop.beans.AbstractSerializableBean;
28  import org.nuiton.jaxx.application.listener.PropagatePropertyChangeListener;
29  import org.nuiton.util.CollectionUtil;
30  import org.nuiton.util.beans.Binder;
31  
32  import java.beans.PropertyChangeListener;
33  import java.util.Collection;
34  import java.util.List;
35  
36  /**
37   * Abstract UI model to edit a bean.
38   *
39   * @param <B> type of Bean
40   * @param <M> type of model
41   * @author Ludovic Pecquot <ludovic.pecquot@e-is.pro>
42   * @since 0.1
43   * <p/>
44   * classes extending this must implement the E interface and delegate methods to delegateObject
45   */
46  public abstract class AbstractBeanUIModel<B, M extends AbstractBeanUIModel<B, M>> extends AbstractSerializableBean implements BeanPropertyChangeListener {
47  
48      /**
49       * Constant <code>PROPERTY_MODIFY="modify"</code>
50       */
51      public static final String PROPERTY_MODIFY = "modify";
52      /**
53       * Constant <code>PROPERTY_VALID="valid"</code>
54       */
55      public static final String PROPERTY_VALID = "valid";
56      /**
57       * Constant <code>PROPERTY_LOADING="loading"</code>
58       */
59      public static final String PROPERTY_LOADING = "loading";
60      private static final long serialVersionUID = 1L;
61      private final Binder<B, M> fromBeanBinder;
62      private final Binder<M, B> toBeanBinder;
63      protected boolean modify;
64      protected boolean valid;
65      protected boolean loading;
66      protected B delegateObject = newBean();
67  
68      /**
69       * <p>Constructor for AbstractBeanUIModel.</p>
70       *
71       * @param fromBeanBinder a {@link org.nuiton.util.beans.Binder} object.
72       * @param toBeanBinder   a {@link org.nuiton.util.beans.Binder} object.
73       */
74      protected AbstractBeanUIModel(Binder<B, M> fromBeanBinder, Binder<M, B> toBeanBinder) {
75          this.fromBeanBinder = fromBeanBinder;
76          this.toBeanBinder = toBeanBinder;
77  
78          // add property change listener and propagate all event to this model
79          addPropagatePropertyChangeListener();
80      }
81  
82      /**
83       * <p>fromBean.</p>
84       *
85       * @param bean a B object.
86       */
87      @SuppressWarnings("unchecked")
88      public void fromBean(B bean) {
89          fromBeanBinder.copy(bean, (M) this);
90      }
91  
92      /**
93       * <p>toBean.</p>
94       *
95       * @return a B object.
96       */
97      @SuppressWarnings("unchecked")
98      public B toBean() {
99          B result = newBean();
100         toBeanBinder.copy((M) this, result);
101         return result;
102     }
103 
104     /**
105      * <p>setBean.</p>
106      *
107      * @param bean a B object.
108      */
109     public void setBean(B bean) {
110 
111         // remove previous listeners
112         removePropagatePropertyChangeListener();
113 
114         // Set new bean
115         delegateObject = bean;
116 
117         // add new listener
118         addPropagatePropertyChangeListener();
119     }
120 
121     private void addPropagatePropertyChangeListener() {
122         if (delegateObject instanceof AbstractBean) {
123             PropagatePropertyChangeListener.listenAndPropagateAll((AbstractBean) delegateObject, this);
124         }
125     }
126 
127     private void removePropagatePropertyChangeListener() {
128         if (delegateObject instanceof AbstractBean) {
129             for (PropertyChangeListener listener : ((AbstractBean) delegateObject).getPropertyChangeListeners()) {
130                 ((AbstractBean) delegateObject).removePropertyChangeListener(listener);
131             }
132         }
133     }
134 
135     /**
136      * <p>newBean.</p>
137      *
138      * @return a B object.
139      */
140     protected abstract B newBean();
141 
142     /**
143      * <p>isModify.</p>
144      *
145      * @return a boolean.
146      */
147     public boolean isModify() {
148         return modify;
149     }
150 
151     /**
152      * <p>Setter for the field <code>modify</code>.</p>
153      *
154      * @param modify a boolean.
155      */
156     public void setModify(boolean modify) {
157         boolean oldValue = isModify();
158         this.modify = modify;
159         firePropertyChange(PROPERTY_MODIFY, oldValue, modify);
160     }
161 
162     /**
163      * <p>isValid.</p>
164      *
165      * @return a boolean.
166      */
167     public boolean isValid() {
168         return valid;
169     }
170 
171     /**
172      * <p>Setter for the field <code>valid</code>.</p>
173      *
174      * @param valid a boolean.
175      */
176     public void setValid(boolean valid) {
177         boolean oldValue = isValid();
178         this.valid = valid;
179         firePropertyChange(PROPERTY_VALID, oldValue, valid);
180     }
181 
182     /**
183      * <p>isLoading.</p>
184      *
185      * @return a boolean.
186      */
187     public boolean isLoading() {
188         return loading;
189     }
190 
191     /**
192      * <p>Setter for the field <code>loading</code>.</p>
193      *
194      * @param loading a boolean.
195      */
196     public void setLoading(boolean loading) {
197         boolean oldValue = isLoading();
198         this.loading = loading;
199         firePropertyChange(PROPERTY_LOADING, oldValue, loading);
200     }
201 
202     //------------------------------------------------------------------------//
203     //-- PropagatePropertyChangeListener methods                            --//
204     //------------------------------------------------------------------------//
205 
206     /**
207      * {@inheritDoc}
208      */
209     @Override
210     public void firePropertyChanged(String propertyName, Object oldValue, Object newValue) {
211         firePropertyChange(propertyName, oldValue, newValue);
212         setModelModify(propertyName, oldValue, newValue);
213     }
214 
215     @Override
216     public void fireIndexedPropertyChanged(String propertyName, int index, Object oldValue, Object newValue) {
217         fireIndexedPropertyChange(propertyName, index, oldValue, newValue);
218         setModelModify(propertyName, oldValue, newValue);
219     }
220 
221     private void setModelModify(String propertyName, Object oldValue, Object newValue) {
222         // set model is modify only if oldValue != newValue
223         // some property change event has both oldValue and newValue as null and we don't want to handle it
224         if (!PROPERTY_MODIFY.equals(propertyName)
225                 && !PROPERTY_LOADING.equals(propertyName)
226                 && oldValue != newValue) {
227             setModify(true);
228         }
229     }
230 
231     /**
232      * <p>getChild.</p>
233      *
234      * @param child a {@link java.util.Collection} object.
235      * @param index a int.
236      * @return a B object.
237      */
238     protected B getChild(Collection<B> child, int index) {
239         return CollectionUtil.getOrNull(child, index);
240     }
241 
242     /**
243      * <p>getChild.</p>
244      *
245      * @param child a {@link java.util.List} object.
246      * @param index a int.
247      * @return a B object.
248      */
249     protected B getChild(List<B> child, int index) {
250         return CollectionUtil.getOrNull(child, index);
251     }
252 
253 }