package agg.attribute.view.impl;
import java.lang.ref.WeakReference;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import agg.attribute.AttrEvent;
import agg.attribute.AttrTuple;
import agg.attribute.AttrType;
import agg.attribute.impl.AttrTupleManager;
import agg.attribute.impl.ManagedObject;
import agg.attribute.impl.TupleObject;
import agg.attribute.view.AttrViewObserver;
import agg.attribute.view.AttrViewSetting;
/**
* Common superclass for OpenViewSetting and MaskedViewSetting. Provides most
* routines for handling own observers and event propagation. Most methods that
* actually manipulate the layout of attribute tuples are in the subclasses
* mentioned above.
*
* @author $Author: olga $
* @version $Id: ViewSetting.java,v 1.7 2010/09/23 08:15:32 olga Exp $
*/
public abstract class ViewSetting extends ManagedObject implements
AttrViewSetting {
static final long serialVersionUID = -582744399860233794L;
/** Table of observers for tuples. */
transient protected Hashtable<AttrTuple, Vector<WeakReference<AttrViewObserver>>>
observerTab = new Hashtable<AttrTuple, Vector<WeakReference<AttrViewObserver>>>();
Object obsvs;
public ViewSetting(AttrTupleManager m) {
super(m);
}
public void dispose() {
}
public void finalize() {
}
/**
* Getting the format for a (type) tuple. Formats are created lazily "on
* demand". It means that when there is no format for the specified
* AttrTuple yet, it is created and returned.
*/
protected abstract TupleFormat getFormat(AttrTuple attr);
/** Removing the format for a (type) tuple. */
protected abstract void removeFormat(AttrType type);
/**
* Getting the observers of a tuple managed in this view.
*
* @return A vector of observers for the specified tuple or null if the
* tuple is not in this view.
*/
protected Vector<WeakReference<AttrViewObserver>> getObserversForTuple(
AttrTuple attr) {
if (this.observerTab == null)
this.observerTab = new Hashtable<AttrTuple, Vector<WeakReference<AttrViewObserver>>>();
return this.observerTab.get(attr);
}
/** Adding an observer for an attribute to its observers' table. */
protected void addObserverForTuple(AttrViewObserver o, AttrTuple attr) {
Vector<WeakReference<AttrViewObserver>> observers = getObserversForTuple(attr);
if (observers == null) {
observers = new Vector<WeakReference<AttrViewObserver>>(4);
this.observerTab.put(attr, observers);
observers.add(new WeakReference<AttrViewObserver>(o));
}
else
if (find(observers, o) == null) {
observers.add(new WeakReference<AttrViewObserver>(o));
}
}
/** Removing an observer for an attribute from its observers' table. */
protected void removeObserverForTuple(AttrViewObserver o, AttrTuple attr) {
Vector<WeakReference<AttrViewObserver>> observers = getObserversForTuple(attr);
if (observers == null)
return;
removeElement(observers, o);
}
/**
* finds the WeakReference which contains the AttrViewObserver or returns
* null
*/
private WeakReference<?> find(Vector<WeakReference<AttrViewObserver>> observers, AttrViewObserver o) {
for (int i= 0; i<observers.size(); i++) {
WeakReference<AttrViewObserver> wr = observers.get(i);
if (wr.get() == null) {
observers.remove(i);
i--;
}
else if (o == wr.get()) {
return wr;
}
}
return null;
}
private void removeElement(Vector<WeakReference<AttrViewObserver>> observers, AttrViewObserver o) {
for (int i= 0; i<observers.size(); i++) {
WeakReference<AttrViewObserver> wr = observers.get(i);
if (wr.get() == null) {
observers.remove(i);
i--;
}
else if (o == wr.get()) {
observers.remove(i);
return;
}
}
}
boolean contains(Vector<WeakReference<AttrViewObserver>> observers, AttrViewObserver o) {
return (find(observers, o) != null);
}
/**
* Called by fireAttrChanged() from this class. The change event is sent
* only to observers who are interested in the attribute's representation.
*/
protected void notifyObservers(AttrTuple attr, int id, int slot0, int slot1) {
AttrViewObserver obs;
Vector<WeakReference<AttrViewObserver>> observers = getObserversForTuple(attr);
obsvs = observers;
if (observers == null)
return;
TupleViewEvent evt = new TupleViewEvent(attr, id, slot0, slot1, this);
for (Enumeration<WeakReference<AttrViewObserver>> en = observers.elements(); en.hasMoreElements();) {
WeakReference<AttrViewObserver> wr = en.nextElement();
obs = wr.get();
if (obs == null)
observers.removeElement(wr);
else
obs.attributeChanged(evt);
}
}
/**
* Called from within this class whenever the format (layout) of an
* attribute is changed. Since the change affects only the attribute type
* representation, two things are important:
*
* 1. Only observers that are interested in the attribute's REPRESENTATION
* should be notified. This is ensured by the sub-method notifyObservers().
*
* 2. All the observers of attribute types that are attribute instances have
* to notify THEIR view observers as well. Usually this propagating
* mechanism is provided by the TupleObject class. But here, it cannot be
* used (see 1.). Therefore, this method loops over all the observers of
* 'attr' if it's a type and recursively calls fireAttrChanged() for all the
* AttrInstance instances among them. The same holds for interfaces.
*/
protected void fireAttrChanged(TupleObject attr, int id, int slot0,
int slot1) {
Object obj;
Enumeration<?> objEnum;
notifyObservers(attr, id, slot0, slot1);
if (obsvs == null) return;
for (objEnum = attr.getObservers(); objEnum.hasMoreElements();) {
obj = objEnum.nextElement();
if (obj instanceof AttrTuple) {
fireAttrChanged((TupleObject) obj, id, slot0, slot1);
}
}
}
/** Propagating incoming attribute events to my view observers. */
protected void propagateAttrEvent(AttrEvent event) {
// System.out.println("ViewSetting.propagateAttrEvent "+event.getID());
AttrTuple attr = event.getSource();
// System.out.println(attr);
if (attr == null)
return;
int id = event.getID();
int index0 = event.getIndex0();
int index1 = event.getIndex1();
if (id == AttrEvent.GENERAL_CHANGE) {
notifyObservers(attr, id, index0, index1);
} else {
int slot0 = convertIndexToSlot(attr, event.getIndex0());
int slot1 = convertIndexToSlot(attr, event.getIndex1());
notifyObservers(attr, id, slot0, slot1);
}
}
//
// Part of AttrViewSetting interface implementation.
public void moveSlotAppending(AttrTuple attr, int srcSlot, int destSlot) {
moveSlotInserting(attr, srcSlot, destSlot + 1);
}
public String toString(AttrTuple attr) {
return getFormat(attr).toString();
}
}