提交 8e0cf5eb 编写于 作者: E Eduardo Ramos

More fixes for correct dynamic index updates due to attribute events.

上级 d818ed3c
......@@ -41,6 +41,8 @@ Portions Copyrighted 2011 Gephi Consortium.
*/
package org.gephi.data.attributes.api;
import org.gephi.project.api.Workspace;
/**
* Represents the data model, like a standard database would do. As a database,
* contains a list of tables, where columns are defined. By default, a model
......@@ -147,4 +149,10 @@ public interface AttributeModel {
* @param model the model that is to be merged in this model
*/
public void mergeModel(AttributeModel model);
/**
* Returns the workspace this Attribute model belongs to.
* @return the workspace that owns this Attribute model or null if it is independent from a Workspace
*/
public Workspace getWorkspace();
}
......@@ -66,6 +66,8 @@ public abstract class AttributeUtils {
public abstract boolean isEdgeColumn(AttributeColumn column);
public abstract boolean isGraphColumn(AttributeColumn column);
public abstract boolean isColumnOfType(AttributeColumn column, AttributeType type);
public abstract boolean areAllColumnsOfType(AttributeColumn[] columns, AttributeType type);
......
......@@ -52,6 +52,7 @@ import org.gephi.data.attributes.api.AttributeValueFactory;
import org.gephi.data.attributes.event.AbstractEvent;
import org.gephi.data.attributes.event.AttributeEventManager;
import org.gephi.data.properties.PropertiesColumn;
import org.gephi.project.api.Workspace;
import org.openide.util.NbBundle;
/**
......@@ -61,6 +62,7 @@ import org.openide.util.NbBundle;
*/
public abstract class AbstractAttributeModel implements AttributeModel {
private final Workspace workspace;
//Classes
private final ConcurrentMap<String, AttributeTableImpl> tableMap;
private final AttributeTableImpl nodeTable;
......@@ -72,7 +74,8 @@ public abstract class AbstractAttributeModel implements AttributeModel {
protected AttributeEventManager eventManager;
//Data API
public AbstractAttributeModel() {
public AbstractAttributeModel(Workspace workspace) {
this.workspace = workspace;
tableMap = new ConcurrentHashMap<String, AttributeTableImpl>();
nodeTable = new AttributeTableImpl(this, NbBundle.getMessage(AttributeTableImpl.class, "NodeAttributeTable.name"));
edgeTable = new AttributeTableImpl(this, NbBundle.getMessage(AttributeTableImpl.class, "EdgeAttributeTable.name"));
......@@ -185,4 +188,8 @@ public abstract class AbstractAttributeModel implements AttributeModel {
}
}
}
public Workspace getWorkspace(){
return this.workspace;
}
}
......@@ -46,9 +46,9 @@ import org.gephi.data.attributes.api.AttributeModel;
import org.gephi.data.attributes.model.IndexedAttributeModel;
import org.gephi.data.attributes.model.TemporaryAttributeModel;
import org.gephi.project.api.ProjectController;
import org.gephi.project.api.WorkspaceProvider;
import org.gephi.project.api.Workspace;
import org.gephi.project.api.WorkspaceListener;
import org.gephi.project.api.WorkspaceProvider;
import org.openide.util.Lookup;
import org.openide.util.lookup.ServiceProvider;
......@@ -68,7 +68,7 @@ public class AttributeControllerImpl implements AttributeController {
public void initialize(Workspace workspace) {
AttributeModel m = workspace.getLookup().lookup(AttributeModel.class);
if (m == null) {
workspace.add(new IndexedAttributeModel());
workspace.add(new IndexedAttributeModel(workspace));
}
}
......@@ -88,7 +88,7 @@ public class AttributeControllerImpl implements AttributeController {
for (Workspace workspace : projectController.getCurrentProject().getLookup().lookup(WorkspaceProvider.class).getWorkspaces()) {
AttributeModel m = workspace.getLookup().lookup(AttributeModel.class);
if (m == null) {
workspace.add(new IndexedAttributeModel());
workspace.add(new IndexedAttributeModel(workspace));
}
}
}
......@@ -101,7 +101,7 @@ public class AttributeControllerImpl implements AttributeController {
if (model != null) {
return model;
}
model = new IndexedAttributeModel();
model = new IndexedAttributeModel(workspace);
workspace.add(model);
return model;
}
......@@ -113,13 +113,13 @@ public class AttributeControllerImpl implements AttributeController {
if (model != null) {
return model;
}
model = new IndexedAttributeModel();
model = new IndexedAttributeModel(workspace);
workspace.add(model);
return model;
}
public AttributeModel newModel() {
TemporaryAttributeModel model = new TemporaryAttributeModel();
TemporaryAttributeModel model = new TemporaryAttributeModel(null);
return model;
}
}
......@@ -70,11 +70,16 @@ public class AttributeRowImpl implements AttributeRow {
public void reset() {
rowVersion = attributeTable.getVersion();
int attSize = attributeTable.countColumns();
AttributeValueImpl[] newValues = new AttributeValueImpl[attSize];
if (values == null) {
values = new AttributeValueImpl[attSize];
} else {
updateColumns();
}
for (int i = 0; i < attSize; i++) {
newValues[i] = attributeTable.getColumn(i).defaultValue;
setValue(i, attributeTable.getColumn(i).defaultValue, false);
}
this.values = newValues;
}
public void setValues(AttributeRow attributeRow) {
......@@ -133,17 +138,19 @@ public class AttributeRowImpl implements AttributeRow {
value = attributeTable.getFactory().newValue(column, value.getValue());
}
setValue(column.getIndex(), (AttributeValueImpl) value);
setValue(column.getIndex(), (AttributeValueImpl) value, true);
}
private void setValue(int index, AttributeValueImpl value) {
private void setValue(int index, AttributeValueImpl value, boolean doUpdateColumns) {
if (doUpdateColumns) {
updateColumns();
}
AttributeValueImpl oldValue = this.values[index];
this.values[index] = value;
if (!((oldValue == null && value == null) || (oldValue != null && oldValue.equals(value)))
if (!(oldValue != null && oldValue.equals(value))
&& index > 0 && !value.getColumn().getOrigin().equals(AttributeOrigin.COMPUTED)) { //0 is the index of node id and edge id cols, not useful to send these events
if (oldValue != null) {
attributeTable.model.fireAttributeEvent(new ValueEvent(EventType.UNSET_VALUE, attributeTable, object, oldValue));
......@@ -211,27 +218,32 @@ public class AttributeRowImpl implements AttributeRow {
}
private void updateColumns() {
int tableVersion = attributeTable.getVersion();
if (rowVersion < tableVersion) {
//Need to update
AttributeColumnImpl[] columns = attributeTable.getColumns();
AttributeValueImpl[] newValues = new AttributeValueImpl[columns.length];
AttributeValueImpl[] oldValues = values;
values = new AttributeValueImpl[columns.length];
for (int i = 0; i < columns.length; i++) {
AttributeColumnImpl tableCol = columns[i];
newValues[i] = tableCol.defaultValue;
boolean found = false;
int j = 0;
while (j < values.length) {
AttributeValueImpl val = values[j++];
while (j < oldValues.length) {
AttributeValueImpl val = oldValues[j++];
if (val.getColumn() == tableCol) {
newValues[i] = val;
values[i] = val;
found = true;
break;
}
}
if (!found) {
setValue(i, tableCol.defaultValue, false);
}
}
values = newValues;
//Upd version
rowVersion = tableVersion;
......
......@@ -52,10 +52,17 @@ import org.gephi.data.attributes.api.AttributeEvent;
import org.gephi.data.attributes.api.AttributeOrigin;
import org.gephi.data.attributes.api.AttributeTable;
import org.gephi.data.attributes.api.AttributeType;
import org.gephi.data.attributes.api.AttributeUtils;
import org.gephi.data.attributes.event.ColumnEvent;
import org.gephi.data.attributes.spi.AttributeValueDelegateProvider;
import org.gephi.data.attributes.type.TypeConvertor;
import org.gephi.data.properties.PropertiesColumn;
import org.gephi.graph.api.Attributes;
import org.gephi.graph.api.Edge;
import org.gephi.graph.api.GraphController;
import org.gephi.graph.api.GraphModel;
import org.gephi.graph.api.Node;
import org.openide.util.Lookup;
/**
*
......@@ -116,7 +123,7 @@ public class AttributeTableImpl implements AttributeTable {
throw new IllegalArgumentException("The column id can't be null, empty or already existing in the table");
}
if(title == null || title.isEmpty() || hasColumn(title)){
if (title == null || title.isEmpty() || hasColumn(title)) {
//The id is correct, but the title may be invalid or repeated even when the id is valid
//Use id as title as a compromise so the column can still be added:
......@@ -151,12 +158,58 @@ public class AttributeTableImpl implements AttributeTable {
return column;
}
/**
* Sends unset events for all attribute rows of a column that is going to be removed. (This is basically necessary to correctly update Dynamic index of Dynamic API.)
*
* Events are only sent for node, edge and graph table columns.
*
* @param column Column that is being removed
*/
private boolean sendUnsetValueEventsForRemovedColumn(AttributeColumn column) {
if (this.model.getWorkspace() == null) {
return false;
}
GraphModel graphModel = Lookup.getDefault().lookup(GraphController.class).getModel(this.model.getWorkspace());
Attributes[] rows;
if (AttributeUtils.getDefault().isNodeColumn(column)) {
Node[] nodes = graphModel.getGraph().getNodes().toArray();
rows = new Attributes[nodes.length];
for (int i = 0; i < nodes.length; i++) {
rows[i] = nodes[i].getAttributes();
}
} else if (AttributeUtils.getDefault().isEdgeColumn(column)) {
Edge[] edges = graphModel.getGraph().getEdges().toArray();
rows = new Attributes[edges.length];
for (int i = 0; i < edges.length; i++) {
rows[i] = edges[i].getAttributes();
}
} else if (AttributeUtils.getDefault().isGraphColumn(column)) {
rows = new Attributes[]{graphModel.getGraph().getAttributes()};
} else {
return false;
}
int columnIndex = column.getIndex();
for (Attributes row : rows) {
row.setValue(columnIndex, null);
}
return true;
}
public synchronized void removeColumn(AttributeColumn column) {
int index = columns.indexOf(column);
if (index == -1) {
return;
}
sendUnsetValueEventsForRemovedColumn(column);
//update indexes of the next columns of the one to delete:
AttributeColumnImpl c;
for (index = index + 1; index < columns.size(); index++) {
......@@ -183,6 +236,9 @@ public class AttributeTableImpl implements AttributeTable {
if (index == -1) {
return null;
}
sendUnsetValueEventsForRemovedColumn(source);
//Remove from collections
columnsMap.remove(source.getId().toLowerCase());
if (source.getTitle() != null && !source.getTitle().equals(source.getId())) {
......
......@@ -250,6 +250,19 @@ public class AttributeUtilsImpl extends AttributeUtils {
return false;
}
@Override
public boolean isGraphColumn(AttributeColumn column) {
if (column == null) {
throw new NullPointerException();
}
AttributeColumnImpl columnImpl = (AttributeColumnImpl) column;
AttributeTableImpl table = columnImpl.getTable();
if (table == table.getModel().getGraphTable()) {
return true;
}
return false;
}
@Override
public AttributeColumn[] getNumberColumns(AttributeTable table) {
List<AttributeColumn> res = new ArrayList<AttributeColumn>();
......
......@@ -44,6 +44,7 @@ package org.gephi.data.attributes.model;
import org.gephi.data.attributes.AbstractAttributeModel;
import org.gephi.data.attributes.api.AttributeType;
import org.gephi.data.attributes.event.AttributeEventManager;
import org.gephi.project.api.Workspace;
/**
*
......@@ -54,7 +55,8 @@ public class IndexedAttributeModel extends AbstractAttributeModel {
protected DataIndex dataIndex;
public IndexedAttributeModel() {
public IndexedAttributeModel(Workspace workspace) {
super(workspace);
dataIndex = new DataIndex();
eventManager = new AttributeEventManager(this);
createPropertiesColumn();
......
......@@ -45,6 +45,7 @@ import org.gephi.data.attributes.AbstractAttributeModel;
import org.gephi.data.attributes.api.AttributeListener;
import org.gephi.data.attributes.api.AttributeType;
import org.gephi.data.attributes.event.AbstractEvent;
import org.gephi.project.api.Workspace;
/**
* Specific manager for temporary storing of attributes. This is typically used when new attributes are
......@@ -56,7 +57,8 @@ import org.gephi.data.attributes.event.AbstractEvent;
*/
public class TemporaryAttributeModel extends AbstractAttributeModel {
public TemporaryAttributeModel() {
public TemporaryAttributeModel(Workspace workspace) {
super(workspace);
createPropertiesColumn();
}
......
......@@ -73,7 +73,7 @@ public class AttributeModelPersistenceProvider implements WorkspacePersistencePr
public void readXML(XMLStreamReader reader, Workspace workspace) {
IndexedAttributeModel model = workspace.getLookup().lookup(IndexedAttributeModel.class);
if (model == null) {
model = new IndexedAttributeModel();
model = new IndexedAttributeModel(workspace);
workspace.add(model);
}
AttributeModelSerializer serializer = new AttributeModelSerializer();
......
......@@ -153,6 +153,9 @@ public class DynamicIndex {
public synchronized void clear() {
lowMap.clear();
highMap.clear();
fireEvent(new DynamicModelEvent(DynamicModelEvent.EventType.MIN_CHANGED, model, getMin()));
fireEvent(new DynamicModelEvent(DynamicModelEvent.EventType.MAX_CHANGED, model, getMax()));
fireEvent(new DynamicModelEvent(DynamicModelEvent.EventType.IS_DYNAMIC_GRAPH, model, Boolean.FALSE));
}
public synchronized double getMin() {
......
......@@ -270,15 +270,7 @@ public final class DynamicModelImpl implements DynamicModel {
graphModel.addGraphListener(graphListener);
}
private void refresh() {
timeIntervalIndex.clear();
for (AttributeColumn col : attributeModel.getNodeTable().getColumns()) {
if (col.getType().isDynamicType()) {
nodeDynamicColumns.add(col);
}
}
AttributeColumn[] dynamicCols = nodeDynamicColumns.toArray(new AttributeColumn[0]);
if (dynamicCols.length > 0) {
private void indexNodeColumnsValues(AttributeColumn[] dynamicCols) {
Graph graph = graphModel.getGraph();
for (Node n : graph.getNodes()) {
Attributes attributeRow = n.getNodeData().getAttributes();
......@@ -292,13 +284,8 @@ public final class DynamicModelImpl implements DynamicModel {
}
}
}
for (AttributeColumn col : attributeModel.getNodeTable().getColumns()) {
if (col.getType().isDynamicType()) {
edgeDynamicColumns.add(col);
}
}
dynamicCols = edgeDynamicColumns.toArray(new AttributeColumn[0]);
if (dynamicCols.length > 0) {
private void indexEdgeColumnsValues(AttributeColumn[] dynamicCols) {
Graph graph = graphModel.getGraph();
for (Edge e : graph.getEdges()) {
Attributes attributeRow = e.getEdgeData().getAttributes();
......@@ -312,6 +299,25 @@ public final class DynamicModelImpl implements DynamicModel {
}
}
}
private void refresh() {
timeIntervalIndex.clear();
nodeDynamicColumns.clear();
edgeDynamicColumns.clear();
for (AttributeColumn col : attributeModel.getNodeTable().getColumns()) {
if (col.getType().isDynamicType()) {
nodeDynamicColumns.add(col);
}
}
indexNodeColumnsValues(nodeDynamicColumns.toArray(new AttributeColumn[0]));
for (AttributeColumn col : attributeModel.getNodeTable().getColumns()) {
if (col.getType().isDynamicType()) {
edgeDynamicColumns.add(col);
}
}
indexEdgeColumnsValues(edgeDynamicColumns.toArray(new AttributeColumn[0]));
}
@Override
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册