/* Copyright 2008-2010 Gephi Authors : Mathieu Bastian <mathieu.bastian@gephi.org>, Martin Škurla <bujacik@gmail.com> Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.data.attributes; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.gephi.data.attributes.api.AttributeTable; import org.gephi.data.attributes.api.AttributeColumn; import org.gephi.data.attributes.api.AttributeEvent; import org.gephi.data.attributes.api.AttributeOrigin; import org.gephi.data.attributes.api.AttributeType; 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; /** * * @author Mathieu Bastian * @author Martin Škurla */ public class AttributeTableImpl implements AttributeTable { protected String name; protected final AbstractAttributeModel model; //Listeners //Columns protected final List<AttributeColumnImpl> columns = new ArrayList<AttributeColumnImpl>(); protected final Map<AttributeColumn, AttributeColumn> columnsSet = new HashMap<AttributeColumn, AttributeColumn>(); protected final Map<String, AttributeColumnImpl> columnsMap = new HashMap<String, AttributeColumnImpl>(); //Version protected int version = 0; public AttributeTableImpl(AbstractAttributeModel model, String name) { this.name = name; this.model = model; } public synchronized AttributeColumnImpl[] getColumns() { return columns.toArray(new AttributeColumnImpl[]{}); } public synchronized int countColumns() { return columns.size(); } public AttributeColumn addPropertiesColumn(PropertiesColumn propertiesColumn) { return addColumn(propertiesColumn.getId(), propertiesColumn.getTitle(), propertiesColumn.getType(), propertiesColumn.getOrigin(), propertiesColumn.getDefaultValue()); } public AttributeColumnImpl addColumn(String id, AttributeType type) { return addColumn(id, id, type, AttributeOrigin.DATA, null, null); } public AttributeColumnImpl addColumn(String id, AttributeType type, AttributeOrigin origin) { return addColumn(id, id, type, origin, null, null); } public AttributeColumnImpl addColumn(String id, String title, AttributeType type, AttributeOrigin origin, Object defaultValue) { return addColumn(id, title, type, origin, defaultValue, null); } public AttributeColumn addColumn(String id, String title, AttributeType type, AttributeValueDelegateProvider attributeValueDelegateProvider, Object defaultValue) { return addColumn(id, title, type, AttributeOrigin.DELEGATE, defaultValue, attributeValueDelegateProvider); } private synchronized AttributeColumnImpl addColumn(String id, String title, AttributeType type, AttributeOrigin origin, Object defaultValue, AttributeValueDelegateProvider attributeValueDelegateProvider) { if (title == null || title.isEmpty() || hasColumn(title)) { throw new IllegalArgumentException("The title can't be null, empty or already existing in the table"); } if (defaultValue != null) { if (defaultValue.getClass() != type.getType()) { if (defaultValue.getClass() == String.class) { defaultValue = type.parse((String) defaultValue); } else { throw new IllegalArgumentException("The default value type cannot be cast to the type"); } } defaultValue = model.getManagedValue(defaultValue, type); } AttributeColumnImpl column = new AttributeColumnImpl(this, columns.size(), id, title, type, origin, defaultValue, attributeValueDelegateProvider); columns.add(column); columnsMap.put(id, column); if (title != null && !title.equals(id)) { columnsMap.put(title.toLowerCase(), column); } columnsSet.put(column, column); //Version version++; model.fireAttributeEvent( new ColumnEvent(AttributeEvent.EventType.ADD_COLUMN, column)); return column; } public synchronized void removeColumn(AttributeColumn column) { int index = columns.indexOf(column); if (index == -1) { return; } //update indexes of the next columns of the one to delete: AttributeColumnImpl c; for (index = index + 1; index < columns.size(); index++) { c = columns.get(index); c.index--; } //Remove from collections columns.remove((AttributeColumnImpl) column); columnsMap.remove(column.getId()); if (column.getTitle() != null && !column.getTitle().equals(column.getId())) { columnsMap.remove(column.getTitle()); } columnsSet.remove(column); model.fireAttributeEvent( new ColumnEvent(AttributeEvent.EventType.REMOVE_COLUMN, (AttributeColumnImpl) column)); //Version version++; } public synchronized AttributeColumn replaceColumn(AttributeColumn source, AttributeColumnImpl targetImpl) { int index = columns.indexOf(source); if (index == -1) { return null; } //Remove from collections columnsMap.remove(source.getId()); if (source.getTitle() != null && !source.getTitle().equals(source.getId())) { columnsMap.remove(source.getTitle()); } columnsSet.remove(source); //Add targetImpl.index = index; columns.set(index, targetImpl); columnsMap.put(targetImpl.id, targetImpl); if (targetImpl.title != null && !targetImpl.title.equals(targetImpl.id)) { columnsMap.put(targetImpl.title.toLowerCase(), targetImpl); } columnsSet.put(targetImpl, targetImpl); //Version version++; return targetImpl; } public synchronized AttributeColumn replaceColumn(AttributeColumn source, String id, String title, AttributeType type, AttributeOrigin origin, Object defaultValue) { if (defaultValue != null) { if (defaultValue.getClass() != type.getType()) { if (defaultValue.getClass() == String.class) { defaultValue = type.parse((String) defaultValue); } else { throw new IllegalArgumentException("The default value type cannot be cast to the type"); } } defaultValue = model.getManagedValue(defaultValue, type); } AttributeColumnImpl targetImpl = new AttributeColumnImpl(this, columns.size(), id, title, type, origin, defaultValue, null); return replaceColumn(source, targetImpl); } public synchronized AttributeColumnImpl getColumn(int index) { if (index >= 0 && index < columns.size()) { return columns.get(index); } return null; } public synchronized AttributeColumnImpl getColumn(String id) { AttributeColumnImpl col = columnsMap.get(id); if (col == null) { return columnsMap.get(id.toLowerCase()); } return col; } public synchronized AttributeColumnImpl getColumn(String title, AttributeType type) { AttributeColumnImpl c = columnsMap.get(title.toLowerCase()); if (c != null && c.getType().equals(type)) { return c; } return null; } public synchronized AttributeColumn getColumn(AttributeColumn column) { return columnsSet.get(column); } public synchronized boolean hasColumn(String title) { return columnsMap.containsKey(title) || columnsMap.containsKey(title.toLowerCase()); } public synchronized int getVersion() { return version; } public void setVersion(int version) { this.version = version; } public String getName() { return name; } public void setName(String name) { this.name = name; } public AttributeFactoryImpl getFactory() { return model.getFactory(); } public AbstractAttributeModel getModel() { return model; } public synchronized void mergeTable(AttributeTable table) { for (AttributeColumn column : table.getColumns()) { AttributeColumn existingCol = getColumn(column); if (existingCol == null) { existingCol = getColumn(column.getTitle()); } if (existingCol == null) { addColumn(column.getId(), column.getTitle(), column.getType(), column.getOrigin(), column.getDefaultValue()); } else if (column.getType().isDynamicType() && TypeConvertor.getStaticType(column.getType()).equals(existingCol.getType())) { //The column exists but has the underlying static type //Change type AttributeColumnImpl newCol = new AttributeColumnImpl(this, existingCol.getIndex(), existingCol.getId(), existingCol.getTitle(), column.getType(), existingCol.getOrigin(), column.getDefaultValue(), null); replaceColumn(existingCol, newCol); } } } }