b6be10e47795fd31d1169c07068eb4ca3963c6b2
1 package be
.nikiroo
.jvcard
;
3 import java
.util
.ArrayList
;
4 import java
.util
.Collection
;
5 import java
.util
.Collections
;
6 import java
.util
.Comparator
;
7 import java
.util
.Iterator
;
8 import java
.util
.LinkedList
;
10 import java
.util
.ListIterator
;
13 * This class is basically a List with a parent and a "dirty" state check. It
14 * sends all commands down to the initial list, but will mark itself and its
15 * children as dirty or not when needed.
17 * All child elements can identify their parent.
19 * The dirty state is bubbling up (when dirty = true) or down (when dirty =
20 * false) -- so, making changes to a child element will also mark its parent as
21 * "dirty", and marking an element as pristine will also affect all its child
27 * the type of the child elements
29 public abstract class BaseClass
<E
extends BaseClass
<?
>> implements List
<E
> {
30 protected boolean dirty
;
31 protected BaseClass
<?
> parent
;
34 private Comparator
<E
> comparator
= new Comparator
<E
>() {
36 public int compare(E o1
, E o2
) {
37 if (o1
== null && o2
== null)
39 if (o1
== null && o2
!= null)
41 if (o1
!= null && o2
== null)
44 return o1
.getId().compareTo(o2
.getId());
49 * Create a new {@link BaseClass} with the items in the given list as its
52 * Note: the elements will be copied from the {@link List}, you cannot
53 * manage the {@link List} from outside
56 * the descendants of this object, or NULL if none
58 protected BaseClass(List
<E
> list
) {
59 this.list
= new ArrayList
<E
>();
62 this.list
.addAll(list
);
65 for (E child
: this) {
71 * Check if this element has unsaved changes.
73 * @return TRUE if it has
75 public boolean isDirty() {
80 * Delete this element from its parent if any.
82 * @return TRUE in case of success
84 public boolean delete() {
86 return parent
.remove(this);
93 * Replace the elements contained in this with those in the given
96 * Note: the elements will be copied from the {@link List}, you cannot
97 * manage the {@link List} from outside
100 * the list of new elements
102 public void replaceListContent(List
<E
> list
) {
103 List
<E
> del
= new LinkedList
<E
>();
104 List
<E
> add
= new LinkedList
<E
>();
106 if (!compare(list
, add
, del
, del
, add
)) {
113 * Compare the elements contained in <tt>this</tt> with those in the given
114 * {@link List}. It will return TRUE in case of equality, will return FALSE
117 * If not equals, the differences will be represented by the given
118 * {@link List}s if they are not NULL.
120 * <li><tt>added</tt>will represent the elements in <tt>list</tt> but not in
122 * <li><tt>removed</tt> will represent the elements in <tt>this</tt> but not
123 * in <tt>list</tt></li>
124 * <li><tt>from<tt> will represent the elements in <tt>list</tt> that are
125 * already contained in <tt>this</tt> but are not equals to them (the
126 * original element from <tt>this</tt> is stored here)</li>
127 * <li><tt>to<tt> will represent the elements in <tt>list</tt> that are
128 * already contained in <tt>this</tt> but are not equals to them (the
129 * changed element from <tt>list</tt> is stored here)</li>
133 * the list of new elements
135 * the list to add the <tt>added</tt> elements to, or NULL
137 * the list to add the <tt>removed</tt> elements to, or NULL
139 * the map to add the <tt>from</tt> elements, or NULL
141 * the map to add the <tt>to</tt> elements, or NULL
143 * @return TRUE if the elements are identical
145 @SuppressWarnings({ "unchecked", "rawtypes" })
146 public boolean compare(List
<E
> list
, List
<E
> added
, List
<E
> removed
,
147 List
<E
> from
, List
<E
> to
) {
148 Collections
.sort(this.list
, comparator
);
150 List
<E
> mine
= new LinkedList
<E
>(this.list
);
151 List
<E
> other
= new LinkedList
<E
>(list
);
153 Collections
.sort(other
, comparator
);
156 while (mine
.size() > 0 || other
.size() > 0) {
157 E here
= (mine
.size() > 0) ? mine
.remove(0) : null;
158 E there
= (other
.size() > 0) ? other
.remove(0) : null;
160 if (here
== null || comparator
.compare(here
, there
) > 0) {
164 } else if (there
== null || comparator
.compare(here
, there
) < 0) {
169 // they represent the same item
170 if (!((BaseClass
) here
).isEquals(there
)) {
184 * Check if the given instance and this one represent the same objects (they
185 * may have different states).
190 * @return TRUE if they represent the same object
192 public boolean isSame(BaseClass
<E
> other
) {
196 if (!getClass().equals(other
.getClass()))
199 return getId().equals(other
.getId());
203 * Check if the given instance and this one are equivalent (both objects in
204 * the same state, all child elements equivalent).
209 * @return TRUE if they are equivalent
211 @SuppressWarnings({ "unchecked", "rawtypes" })
212 public boolean isEquals(BaseClass
<E
> other
) {
216 if (size() != other
.size())
222 if (!getState().equals(other
.getState()))
225 Collections
.sort(list
, comparator
);
226 Collections
.sort(other
.list
, other
.comparator
);
227 for (int index
= 0; index
< size(); index
++) {
228 if (!((BaseClass
) get(index
)).isEquals(other
.get(index
)))
236 * Return the current ID of this object -- it is allowed to change over time
237 * (so, do not cache it).
239 * @return the current ID
241 abstract public String
getId();
244 * Get the state of the current object, children <b>not included</b>. It
245 * represents the full state information about this object, that is, two
246 * objects with the same state (and class) must return TRUE if
247 * {@link BaseClass#isEquals(BaseClass)} is called <b>and</b> their children
250 * @return a {@link String} representing the current state of this object,
251 * children not included
253 abstract public String
getState();
256 * Notify that this element has unsaved changes.
260 if (parent
!= null) {
266 * Notify this element <i>and all its descendants</i> that it is in pristine
267 * state (as opposed to dirty).
271 for (E child
: this) {
277 * Set the parent of this element <i>and all its descendants</i>.
282 void setParent(BaseClass
<?
> parent
) {
283 this.parent
= parent
;
284 for (E child
: this) {
285 child
.setParent(this);
290 * Each element that leaves the parent will pass trough here.
293 * the element to remove from this
295 private void _leave(E child
) {
300 * Each element that enters the parent will pass trough here.
303 * the element to add to this
305 private void _enter(E child
) {
306 _enter(child
, false);
310 * Each element that enters the parent will pass trough here.
313 * the element to add to this
315 private void _enter(E child
, boolean initialLoad
) {
316 child
.setParent(this);
324 public boolean add(E e
) {
330 @SuppressWarnings("unchecked")
331 public boolean remove(Object o
) {
332 if (list
.remove(o
)) {
333 if (o
instanceof BaseClass
<?
>) {
334 _leave((E
) o
); // expected warning
343 public boolean addAll(Collection
<?
extends E
> c
) {
348 return list
.addAll(c
);
352 public boolean addAll(int index
, Collection
<?
extends E
> c
) {
357 return list
.addAll(index
, c
);
361 public boolean removeAll(Collection
<?
> c
) {
362 boolean changed
= false;
373 public boolean retainAll(Collection
<?
> c
) {
374 ArrayList
<Object
> del
= new ArrayList
<Object
>();
378 return removeAll(del
);
382 public void clear() {
383 for (E child
: this) {
391 public E
set(int index
, E element
) {
392 E child
= get(index
);
397 return list
.set(index
, element
);
401 public void add(int index
, E element
) {
403 list
.add(index
, element
);
407 public E
remove(int index
) {
408 E child
= get(index
);
410 return list
.remove(index
);
414 public Iterator
<E
> iterator() {
415 return listIterator(0);
419 public ListIterator
<E
> listIterator() {
420 return listIterator(0);
424 public ListIterator
<E
> listIterator(int index
) {
426 return new ListIterator
<E
>() {
427 ListIterator
<E
> base
= list
.listIterator(i
);
431 public boolean hasNext() {
432 return base
.hasNext();
442 public boolean hasPrevious() {
443 return base
.hasPrevious();
447 public E
previous() {
448 last
= base
.previous();
453 public int nextIndex() {
454 return base
.nextIndex();
458 public int previousIndex() {
459 return base
.previousIndex();
463 public void remove() {
469 public void set(E e
) {
476 public void add(E e
) {
484 public Object
[] toArray() {
485 return list
.toArray();
489 public <T
> T
[] toArray(T
[] a
) {
490 return list
.toArray(a
);
499 public boolean isEmpty() {
500 return list
.isEmpty();
504 public boolean contains(Object o
) {
505 return list
.contains(o
);
509 public boolean containsAll(Collection
<?
> c
) {
510 return list
.containsAll(c
);
514 public E
get(int index
) {
515 return list
.get(index
);
519 public int indexOf(Object o
) {
520 return list
.indexOf(o
);
524 public int lastIndexOf(Object o
) {
525 return list
.lastIndexOf(o
);
529 public List
<E
> subList(int fromIndex
, int toIndex
) {
530 return list
.subList(fromIndex
, toIndex
);