package timeflow.model;
import timeflow.data.db.*;
import timeflow.data.db.filter.*;
import timeflow.data.time.*;
import java.util.*;
// encapsulates all properties of a timeline model:
// data, display properties, etc.
// also does listening, etc.
public class TFModel {
private ActDB db;
private ActList acts;
private ActFilter filter=new ConstFilter(true);
private ArrayList<TFListener> listeners=new ArrayList<TFListener>();
private Display display=new Display();
private String[] labelGuesses={"label", "LABEL", "Label", "title", "TITLE", "Title",
"name", "Name", "NAME"};
private String[] startGuesses={"start", "Start", "START"};
private String dbFile="[unknown source]";
private boolean changedSinceSave;
private boolean readOnly;
private double minSize, maxSize;
private Interval viewInterval;
public ValueFilter getGrayFilter() {
return display.grayFilter;
}
public void setGrayFilter(ValueFilter grayFilter, Object origin) {
display.grayFilter = grayFilter;
fireEvent(new TFEvent(TFEvent.Type.FILTER_CHANGE, origin));
}
public ActFilter getFilter()
{
return filter;
}
public Interval getViewInterval()
{
return viewInterval;
}
public void setViewInterval(Interval viewInterval)
{
this.viewInterval=viewInterval;
}
public double getMinSize() {
return minSize;
}
public void setMinSize(double minSize) {
this.minSize = minSize;
}
public double getMaxSize() {
return maxSize;
}
public void setMaxSize(double maxSize) {
this.maxSize = maxSize;
}
public String getDbFile() {
return dbFile;
}
public boolean getReadOnly()
{
return readOnly;
}
public void setDbFile(String dbFile, boolean readOnly, Object origin) {
this.dbFile = dbFile;
fireEvent(new TFEvent(TFEvent.Type.SOURCE_CHANGE, origin));
}
public boolean isChangedSinceSave() {
return changedSinceSave;
}
public void setChangedSinceSave(boolean changedSinceSave) {
this.changedSinceSave = changedSinceSave;
}
public Display getDisplay()
{
return display;
}
public ActDB getDB()
{
return db;
}
public ActList getActs()
{
return acts;
}
public void addListener(TFListener t)
{
listeners.add(t);
}
public void removeListener(TFListener t)
{
listeners.remove(t);
}
public void noteNewDescription(Object origin)
{
setChangedSinceSave(true);
fireEvent(new TFEvent(TFEvent.Type.DESCRIPTION_CHANGE, origin));
}
public void noteNewSource(Object origin)
{
setChangedSinceSave(true);
fireEvent(new TFEvent(TFEvent.Type.SOURCE_CHANGE, origin));
}
public void noteRecordChange(Object origin)
{
setChangedSinceSave(true);
fireEvent(new TFEvent(TFEvent.Type.ACT_CHANGE, origin));
}
public void noteAddField(Object origin)
{
setChangedSinceSave(true);
fireEvent(new TFEvent(TFEvent.Type.FIELD_ADD, origin));
}
public void noteError(Object origin)
{
fireEvent(new TFEvent(TFEvent.Type.ERROR, origin));
}
public void noteDelete(Object origin)
{
setChangedSinceSave(true);
updateActs();
fireEvent(new TFEvent(TFEvent.Type.ACT_DELETE, origin));
}
public void noteSchemaChange(Object origin)
{
setChangedSinceSave(true);
updateActs();
fireEvent(new TFEvent(TFEvent.Type.DATABASE_CHANGE, origin)); // @TODO: make schema change?
}
public void noteAdd(Object origin)
{
setChangedSinceSave(true);
updateActs();
fireEvent(new TFEvent(TFEvent.Type.ACT_ADD, origin));
}
public void setFilter(ActFilter filter, Object origin)
{
this.filter=filter;
updateActs();
fireEvent(new TFEvent(TFEvent.Type.FILTER_CHANGE, origin));
}
private void updateActs()
{
acts=db.select(filter);
}
public void setDB(ActDB db, String dbFile, boolean readOnly, Object origin)
{
this.db=db;
this.dbFile=dbFile;
this.readOnly=readOnly;
setChangedSinceSave(false);
this.filter=new ConstFilter(true);
this.acts=db.all();
initVisualEncodings();
refreshColors();
fireEvent(new TFEvent(TFEvent.Type.DATABASE_CHANGE, origin));
}
private void initVisualEncodings()
{
guessField(VirtualField.LABEL, labelGuesses, String.class);
guessField(VirtualField.START, startGuesses, RoughTime.class);
viewInterval=null;
}
public void refreshColors()
{
display.grayFilter=null;
Field colorField=getColorField();
if (colorField==null)
return;
List<String> top25=DBUtils.countValues(db, colorField).listTop(25);
display.refreshColors(top25);
}
private void guessField(String name, String[] guesses, Class type)
{
Field field=db.getField(name);
if (field==null)
{
for (int i=0; i<guesses.length; i++)
{
Field f=db.getField(guesses[i]);
if (f!=null && f.getType()==type)
{
field=f;
break;
}
}
if (field==null)
{
List<Field> f=db.getFields(type);
if (f.size()>0)
field=f.get(0);
}
if (field!=null)
db.setAlias(field, name);
}
}
private void fireEvent(TFEvent e)
{
// clone list before going through it, because some events can cause
// listeners to be added or removed.
for (TFListener t: (List<TFListener>)listeners.clone())
if (t!=e.origin)
t.note(e);
}
public void setFieldAlias(Field field, String alias, Object origin)
{
db.setAlias(field, alias);
if (db.size()>0 && field==getColorField())
refreshColors();
fireEvent(new TFEvent(TFEvent.Type.VIEW_CHANGE, origin));
}
public Field getColorField()
{
if (db==null)
return null;
Field f=db.getField(VirtualField.COLOR);
if (f!=null)
return f;
return db.getField(VirtualField.TRACK);
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
public boolean isReadOnly() {
return readOnly;
}
}