/*****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
****************************************************************/
package org.apache.cayenne.modeler.editor.dbentity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import javax.swing.JOptionPane;
import org.apache.cayenne.dba.TypesMapping;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.DbRelationship;
import org.apache.cayenne.map.event.AttributeEvent;
import org.apache.cayenne.modeler.Application;
import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.util.CayenneTableModel;
import org.apache.cayenne.modeler.util.ProjectUtil;
/**
* Model for DbEntity attributes. Allows adding/removing attributes, modifying types and
* names.
*
*/
public class DbAttributeTableModel extends CayenneTableModel {
// Columns
private static final int DB_ATTRIBUTE_NAME = 0;
private static final int DB_ATTRIBUTE_TYPE = 1;
private static final int DB_ATTRIBUTE_PRIMARY_KEY = 2;
private static final int DB_ATTRIBUTE_MANDATORY = 3;
private static final int DB_ATTRIBUTE_MAX = 4;
private static final int DB_ATTRIBUTE_SCALE = 5;
protected DbEntity entity;
public DbAttributeTableModel(DbEntity entity, ProjectController mediator,
Object eventSource) {
this(entity, mediator, eventSource, new ArrayList<DbAttribute>(entity
.getAttributes()));
this.entity = entity;
}
public DbAttributeTableModel(DbEntity entity, ProjectController mediator,
Object eventSource, List<DbAttribute> objectList) {
super(mediator, eventSource, objectList);
}
public int nameColumnInd() {
return DB_ATTRIBUTE_NAME;
}
public int typeColumnInd() {
return DB_ATTRIBUTE_TYPE;
}
public int mandatoryColumnInd() {
return DB_ATTRIBUTE_MANDATORY;
}
/**
* Returns DbAttribute class.
*/
@Override
public Class<?> getElementsClass() {
return DbAttribute.class;
}
/**
* Returns the number of columns in the table.
*/
public int getColumnCount() {
return 6;
}
public DbAttribute getAttribute(int row) {
return (row >= 0 && row < objectList.size())
? (DbAttribute) objectList.get(row)
: null;
}
public String getColumnName(int col) {
switch (col) {
case DB_ATTRIBUTE_NAME:
return "Name";
case DB_ATTRIBUTE_TYPE:
return "Type";
case DB_ATTRIBUTE_PRIMARY_KEY:
return "PK";
case DB_ATTRIBUTE_SCALE:
return "Scale";
case DB_ATTRIBUTE_MANDATORY:
return "Mandatory";
case DB_ATTRIBUTE_MAX:
return "Max Length";
default:
return "";
}
}
@Override
public Class<?> getColumnClass(int col) {
switch (col) {
case DB_ATTRIBUTE_PRIMARY_KEY:
case DB_ATTRIBUTE_MANDATORY:
return Boolean.class;
default:
return String.class;
}
}
public Object getValueAt(int row, int column) {
DbAttribute attr = getAttribute(row);
if (attr == null) {
return "";
}
switch (column) {
case DB_ATTRIBUTE_NAME:
return getAttributeName(attr);
case DB_ATTRIBUTE_TYPE:
return getAttributeType(attr);
case DB_ATTRIBUTE_PRIMARY_KEY:
return isPrimaryKey(attr);
case DB_ATTRIBUTE_SCALE:
return getScale(attr);
case DB_ATTRIBUTE_MANDATORY:
return isMandatory(attr);
case DB_ATTRIBUTE_MAX:
return getMaxLength(attr);
default:
return "";
}
}
public void setUpdatedValueAt(Object newVal, int row, int col) {
DbAttribute attr = getAttribute(row);
if (attr == null) {
return;
}
AttributeEvent e = new AttributeEvent(eventSource, attr, entity);
switch (col) {
case DB_ATTRIBUTE_NAME:
e.setOldName(attr.getName());
attr.setName((String) newVal);
((DbEntity) attr.getEntity()).dbAttributeChanged(e);
fireTableCellUpdated(row, col);
break;
case DB_ATTRIBUTE_TYPE:
setAttributeType((String) newVal, attr);
break;
case DB_ATTRIBUTE_PRIMARY_KEY:
if (!setPrimaryKey(((Boolean) newVal), attr, row)) {
return;
}
break;
case DB_ATTRIBUTE_SCALE:
setScale((String) newVal, attr);
break;
case DB_ATTRIBUTE_MANDATORY:
setMandatory((Boolean) newVal, attr);
break;
case DB_ATTRIBUTE_MAX:
setMaxLength((String) newVal, attr);
break;
}
mediator.fireDbAttributeEvent(e);
}
public String getMaxLength(DbAttribute attr) {
return (attr.getMaxLength() >= 0) ? String.valueOf(attr.getMaxLength()) : "";
}
public String getAttributeName(DbAttribute attr) {
return attr.getName();
}
public String getAttributeType(DbAttribute attr) {
return TypesMapping.getSqlNameByType(attr.getType());
}
public String getScale(DbAttribute attr) {
return (attr.getScale() >= 0) ? String.valueOf(attr.getScale()) : "";
}
public Boolean isPrimaryKey(DbAttribute attr) {
return (attr.isPrimaryKey()) ? Boolean.TRUE : Boolean.FALSE;
}
public Boolean isMandatory(DbAttribute attr) {
return (attr.isMandatory()) ? Boolean.TRUE : Boolean.FALSE;
}
public void setMaxLength(String newVal, DbAttribute attr) {
if (newVal == null || newVal.trim().length() <= 0) {
attr.setMaxLength(-1);
}
else {
try {
attr.setMaxLength(Integer.parseInt(newVal));
}
catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(
null,
"Invalid Max Length (" + newVal + "), only numbers are allowed",
"Invalid Maximum Length",
JOptionPane.ERROR_MESSAGE);
return;
}
}
}
public void setAttributeType(String newVal, DbAttribute attr) {
attr.setType(TypesMapping.getSqlTypeByName(newVal));
}
public void setScale(String newVal, DbAttribute attr) {
if (newVal == null || newVal.trim().length() <= 0) {
attr.setScale(-1);
}
else {
try {
attr.setScale(Integer.parseInt(newVal));
}
catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(
null,
"Invalid precision (" + newVal + "), only numbers are allowed.",
"Invalid Precision Value",
JOptionPane.ERROR_MESSAGE);
}
}
}
public boolean setPrimaryKey(Boolean newVal, DbAttribute attr, int row) {
boolean flag = newVal.booleanValue();
// when PK is unset, we need to fix some derived flags
if (!flag) {
attr.setGenerated(false);
Collection<DbRelationship> relationships = ProjectUtil
.getRelationshipsUsingAttributeAsTarget(attr);
relationships
.addAll(ProjectUtil.getRelationshipsUsingAttributeAsSource(attr));
if (relationships.size() > 0) {
Iterator<DbRelationship> it = relationships.iterator();
while (it.hasNext()) {
DbRelationship relationship = it.next();
if (!relationship.isToDependentPK()) {
it.remove();
}
}
// filtered only those that are to dep PK
if (relationships.size() > 0) {
String message = (relationships.size() == 1)
? "Fix \"To Dep PK\" relationship using this attribute?"
: "Fix "
+ relationships.size()
+ " \"To Dep PK\" relationships using this attribute?";
int answer = JOptionPane.showConfirmDialog(
Application.getFrame(),
message);
if (answer != JOptionPane.YES_OPTION) {
// no action needed
return false;
}
// fix target relationships
for (DbRelationship relationship : relationships) {
relationship.setToDependentPK(false);
}
}
}
}
attr.setPrimaryKey(flag);
if (flag) {
attr.setMandatory(true);
fireTableCellUpdated(row, DB_ATTRIBUTE_MANDATORY);
}
return true;
}
public void setMandatory(Boolean newVal, DbAttribute attr) {
attr.setMandatory(newVal.booleanValue());
}
public void setGenerated(Boolean newVal, DbAttribute attr) {
attr.setGenerated(newVal.booleanValue());
}
public boolean isCellEditable(int row, int col) {
DbAttribute attrib = getAttribute(row);
if (null == attrib) {
return false;
}
else if (col == mandatoryColumnInd()) {
if (attrib.isPrimaryKey()) {
return false;
}
}
return true;
}
@Override
public boolean isColumnSortable(int sortCol) {
return true;
}
@Override
public void sortByColumn(int sortCol, boolean isAscent) {
switch(sortCol){
case DB_ATTRIBUTE_NAME:
sortByElementProperty("name", isAscent);
break;
case DB_ATTRIBUTE_TYPE:
Collections.sort(objectList, new Comparator<DbAttribute>() {
public int compare(DbAttribute o1, DbAttribute o2) {
if ((o1 == null && o2 == null) || o1 == o2) {
return 0;
}
else if (o1 == null && o2 != null) {
return -1;
}
else if (o1 != null && o2 == null) {
return 1;
}
String attrType1 = getAttributeType(o1);
String attrType2 = getAttributeType(o2);
return (attrType1 == null) ? -1 : (attrType2 == null)
? 1
: attrType1.compareTo(attrType2);
}
});
if (!isAscent) {
Collections.reverse(objectList);
}
break;
case DB_ATTRIBUTE_PRIMARY_KEY:
sortByElementProperty("primaryKey", isAscent);
break;
case DB_ATTRIBUTE_SCALE:
sortByElementProperty("scale", isAscent);
break;
case DB_ATTRIBUTE_MANDATORY:
sortByElementProperty("mandatory", isAscent);
break;
case DB_ATTRIBUTE_MAX:
sortByElementProperty("maxLength", isAscent);
break;
}
}
}