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;
|
}
|
}
|