X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Fjvcard%2FBaseClass.java;fp=src%2Fbe%2Fnikiroo%2Fjvcard%2FBaseClass.java;h=fe7742ab1cea0d52c1d71b77742b2ea6b7ad066a;hb=26d2bd0591901a8d52bd24802a8d6827d0e9b833;hp=0000000000000000000000000000000000000000;hpb=89d9d47d0c2be35228ae8add7dc166722df04db8;p=jvcard.git diff --git a/src/be/nikiroo/jvcard/BaseClass.java b/src/be/nikiroo/jvcard/BaseClass.java new file mode 100644 index 0000000..fe7742a --- /dev/null +++ b/src/be/nikiroo/jvcard/BaseClass.java @@ -0,0 +1,368 @@ +package be.nikiroo.jvcard; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +/** + * This class is basically a List with a parent and a "dirty" state check. It + * sends all commands down to the initial list, but will mark itself and its + * children as dirty or not when needed. + * + * All child elements can identify their parent. + * + * The dirty state is bubbling up (when dirty = true) or down (when dirty = + * false) -- so, making changes to a child element will also mark its parent as + * "dirty", and marking an element as pristine will also affect all its child + * elements. + * + * @author niki + * + * @param + * the type of the child elements + */ +public abstract class BaseClass> implements List { + protected boolean dirty; + protected BaseClass parent; + private List list; + + /** + * Create a new {@link BaseClass} with the given list as its descendants. + * + * @param list + * the descendants of this object, or NULL if none + */ + protected BaseClass(List list) { + this.list = new ArrayList(); + list.addAll(list); + for (E child : this) { + _enter(child, true); + } + } + + /** + * Check if this element has unsaved changes. + * + * @return TRUE if it has + */ + public boolean isDirty() { + return dirty; + } + + /** + * Delete this element from its parent if any. + * + * @return TRUE in case of success + */ + public boolean delete() { + if (parent != null) { + return parent.remove(this); + } + + return false; + } + + /** + * Replace the elements contained in this with those in the given + * {@link List}. + * + * Note: the elements will be copied from the {@link List}, you cannot + * manage the {@link List} from outside + * + * @param list + * the list of new elements + */ + public void replaceListContent(List list) { + List del = new ArrayList(); + List add = new ArrayList(); + + for (E oldChild : this) { + if (!list.contains(oldChild)) { + del.add(oldChild); + } + } + for (E newChild : list) { + if (!contains(newChild)) { + add.add(newChild); + } + } + + removeAll(del); + addAll(add); + } + + /** + * Notify that this element has unsaved changes. + */ + void setDirty() { + dirty = true; + } + + /** + * Notify this element and all its descendants that it is in pristine + * state (as opposed to dirty). + */ + void setPristine() { + dirty = false; + for (E child : this) { + child.setPristine(); + } + } + + /** + * Set the parent of this element and all its descendants. + * + * @param parent + * the new parent + */ + void setParent(BaseClass parent) { + this.parent = parent; + for (E child : this) { + child.setParent(this); + } + } + + /** + * Each element that leaves the parent will pass trough here. + * + * @param child + * the element to remove from this + */ + private void _leave(E child) { + setDirty(); + } + + /** + * Each element that enters the parent will pass trough here. + * + * @param child + * the element to add to this + */ + private void _enter(E child) { + _enter(child, false); + } + + /** + * Each element that enters the parent will pass trough here. + * + * @param child + * the element to add to this + */ + private void _enter(E child, boolean initialLoad) { + child.setParent(this); + if (!initialLoad) + child.setDirty(); + } + + @Override + public boolean add(E e) { + _enter(e, false); + return list.add(e); + } + + @Override + @SuppressWarnings("unchecked") + public boolean remove(Object o) { + if (list.remove(o)) { + if (o instanceof BaseClass) { + _leave((E) o); // expected warning + } + return true; + } + + return false; + } + + @Override + public boolean addAll(Collection c) { + for (E child : c) { + _enter(child); + } + + return list.addAll(c); + } + + @Override + public boolean addAll(int index, Collection c) { + for (E child : c) { + _enter(child); + } + + return list.addAll(index, c); + } + + @Override + public boolean removeAll(Collection c) { + boolean changed = false; + + for (Object o : c) { + if (remove(o)) + changed = true; + } + + return changed; + } + + @Override + public boolean retainAll(Collection c) { + ArrayList del = new ArrayList(); + for (Object o : c) { + del.add(o); + } + return removeAll(del); + } + + @Override + public void clear() { + for (E child : this) { + _leave(child); + } + + list.clear(); + } + + @Override + public E set(int index, E element) { + E child = get(index); + if (child != null) + _leave(child); + _enter(element); + + return list.set(index, element); + } + + @Override + public void add(int index, E element) { + _enter(element); + list.add(index, element); + } + + @Override + public E remove(int index) { + E child = get(index); + _leave(child); + return list.remove(index); + } + + @Override + public Iterator iterator() { + return listIterator(0); + } + + @Override + public ListIterator listIterator() { + return listIterator(0); + } + + @Override + public ListIterator listIterator(int index) { + final int i = index; + return new ListIterator() { + ListIterator base = list.listIterator(i); + E last; + + @Override + public boolean hasNext() { + return base.hasNext(); + } + + @Override + public E next() { + last = base.next(); + return last; + } + + @Override + public boolean hasPrevious() { + return base.hasPrevious(); + } + + @Override + public E previous() { + last = base.previous(); + return last; + } + + @Override + public int nextIndex() { + return base.nextIndex(); + } + + @Override + public int previousIndex() { + return base.previousIndex(); + } + + @Override + public void remove() { + base.remove(); + _leave(last); + } + + @Override + public void set(E e) { + base.set(e); + _leave(last); + _enter(e); + } + + @Override + public void add(E e) { + base.add(e); + _enter(e); + } + }; + } + + @Override + public Object[] toArray() { + return list.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return list.toArray(a); + } + + @Override + public int size() { + return list.size(); + } + + @Override + public boolean isEmpty() { + return list.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return list.contains(o); + } + + @Override + public boolean containsAll(Collection c) { + return list.containsAll(c); + } + + @Override + public E get(int index) { + return list.get(index); + } + + @Override + public int indexOf(Object o) { + return list.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return list.lastIndexOf(o); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return list.subList(fromIndex, toIndex); + } +}