/*
* Copyright 2000-2007 JetBrains s.r.o.
*
* Licensed 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 com.intellij.persistence.diagram;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.jam.view.DefaultUserResponse;
import com.intellij.jam.view.JamDeleteProvider;
import com.intellij.jam.view.tree.JamObjectDescriptor;
import com.intellij.javaee.model.common.CommonModelElement;
import com.intellij.javaee.util.JamCommonUtil;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.actionSystem.DataKeys;
import com.intellij.openapi.actionSystem.DataSink;
import com.intellij.openapi.actionSystem.TypeSafeDataProvider;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.graph.view.EditMode;
import com.intellij.openapi.graph.view.Graph2DView;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.persistence.PersistenceDataKeys;
import com.intellij.persistence.facet.PersistenceFacetBase;
import com.intellij.persistence.facet.PersistenceFacetConfiguration;
import com.intellij.persistence.model.*;
import com.intellij.persistence.util.PersistenceCommonUtil;
import com.intellij.persistence.util.PersistenceModelBrowser;
import com.intellij.pom.Navigatable;
import com.intellij.psi.*;
import com.intellij.util.PairProcessor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xml.ElementPresentationManager;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
/**
* @author Gregory.Shrago
*/
public class DefaultDiagramSupport implements PersistenceDiagramSupport<PersistencePackage, PersistentObject, PersistentAttribute> {
private Map<PsiClass, PersistentObject> myClassMap;
private Collection<PersistentObject> myPersistentObjects;
private final PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage> myFacet;
private PersistenceModelBrowser myModelBrowser;
public DefaultDiagramSupport(final PersistenceFacetBase<PersistenceFacetConfiguration, PersistencePackage> facet) {
myFacet = facet;
}
public PersistenceFacetBase getModificationTracker(final PersistencePackage unit) {
return myFacet;
}
public void startDataModelUpdate(final PersistencePackage persistencePackage) {
myModelBrowser = PersistenceCommonUtil.createFacetAndUnitModelBrowser(myFacet, persistencePackage, null);
if (persistencePackage == null || !persistencePackage.isValid()) {
myPersistentObjects = Collections.emptyList();
myClassMap = Collections.emptyMap();
}
else {
final PersistenceMappings entityMappings = myFacet.getEntityMappings(persistencePackage);
startDataModelUpdate(entityMappings);
}
}
public void startDataModelUpdate(final PersistenceMappings entityMappings) {
myPersistentObjects = PersistenceCommonUtil.queryPersistentObjects(entityMappings).findAll();
myClassMap = new THashMap<PsiClass, PersistentObject>();
for (PersistentObject persistentObject : myPersistentObjects) {
final PsiClass psiClass = persistentObject.getClazz().getValue();
if (psiClass != null) {
myClassMap.put(psiClass, persistentObject);
}
}
}
public void finishDataModelUpdate() {
myPersistentObjects = null;
myClassMap = null;
}
public PersistenceModelBrowser getModelBrowser() {
return myModelBrowser;
}
public void processEntities(final PairProcessor<? super PersistentObject, String> pairProcessor) {
for (PersistentObject object : myPersistentObjects) {
final PsiClass psiClass = object.getClazz().getValue();
if (!pairProcessor.process(object, psiClass == null? object.getClazz().getStringValue() : psiClass.getQualifiedName())) {
return;
}
}
}
public void processSuper(final PersistentObject sourceEntity, final PairProcessor<? super PersistentObject, String> pairProcessor) {
final PsiClass psiClass = sourceEntity.getClazz().getValue();
if (psiClass == null) return;
for (final PsiClass curClass : JamCommonUtil.getSuperClassList(psiClass.getSuperClass())) {
final PersistentObject superObject = myClassMap.get(curClass);
if (superObject != null && !pairProcessor.process(superObject, curClass.getQualifiedName())) {
return;
}
}
}
public void processRelated(final PersistentObject sourceEntity, final PairProcessor<? super PersistentAttribute, String> pairProcessor) {
for (PersistentAttribute persistentAttribute : sourceEntity.getObjectModelHelper().getAttributes()) {
if (persistentAttribute instanceof PersistentRelationshipAttribute) {
final PersistentRelationshipAttribute attribute = (PersistentRelationshipAttribute)persistentAttribute;
final PsiClass psiClass = PersistenceCommonUtil.getTargetClass(attribute);
if (!pairProcessor.process(persistentAttribute, psiClass == null? attribute.getTargetEntityClass().getStringValue() : psiClass.getQualifiedName())) {
return;
}
}
}
}
public void processEmbedded(final PersistentObject sourceEntity, final PairProcessor<? super PersistentAttribute, String> pairProcessor) {
for (PersistentAttribute persistentAttribute : sourceEntity.getObjectModelHelper().getAttributes()) {
if (persistentAttribute instanceof PersistentEmbeddedAttribute) {
final PersistentEmbeddedAttribute attribute = (PersistentEmbeddedAttribute)persistentAttribute;
final PsiClass psiClass = PersistenceCommonUtil.getTargetClass(attribute);
if (!pairProcessor.process(persistentAttribute, psiClass == null ? attribute.getTargetEmbeddableClass().getStringValue() : psiClass.getQualifiedName())) {
return;
}
}
}
}
public void processAttributes(final PersistentObject persistentObject, final PairProcessor<? super PersistentAttribute, String> pairProcessor) {
for (PersistentAttribute persistentAttribute : persistentObject.getObjectModelHelper().getAttributes()) {
if (persistentAttribute instanceof PersistentTransientAttribute) continue;
if (persistentAttribute instanceof PersistentRelationshipAttribute) continue;
if (persistentAttribute instanceof PersistentEmbeddedAttribute) continue;
if (!pairProcessor.process(persistentAttribute, persistentAttribute.getName().getValue())) {
return;
}
}
}
@Nullable
public PersistentObject getAttributeTarget(final PersistentAttribute persistentAttribute) {
if (persistentAttribute instanceof PersistentRelationshipAttribute) {
return myModelBrowser.queryTargetPersistentObjects((PersistentRelationshipAttribute)persistentAttribute).findFirst();
}
else if (persistentAttribute instanceof PersistentEmbeddedAttribute) {
return myModelBrowser.queryTargetPersistentObjects((PersistentEmbeddedAttribute)persistentAttribute).findFirst();
}
return null;
}
public String getUniqueId(final PersistentObject persistentObject) {
return PersistenceCommonUtil.getUniqueId(persistentObject == null? null : persistentObject.getIdentifyingPsiElement());
}
@Nullable
public PersistentAttribute getInverseSideAttribute(final PersistentAttribute persistentAttribute) {
assert persistentAttribute instanceof PersistentRelationshipAttribute;
return myModelBrowser.queryTheOtherSideAttributes((PersistentRelationshipAttribute)persistentAttribute, false).findFirst();
}
@Nullable
public String getAttributeName(final PersistentAttribute persistentAttribute) {
return persistentAttribute.getName().getValue();
}
@Nullable
public PsiType getAttributePsiType(final PersistentAttribute persistentAttribute) {
return persistentAttribute.getPsiType();
}
@NonNls
@NotNull
public String getEntityTypeName(final PersistentObject persistentObject) {
return ElementPresentationManager.getTypeNameForObject(persistentObject);
}
@NonNls
@NotNull
public String getAttributeTypeName(final PersistentAttribute persistentAttribute) {
return ElementPresentationManager.getTypeNameForObject(persistentAttribute);
}
public boolean isIdAttribute(final PersistentAttribute persistentAttribute) {
return persistentAttribute.getAttributeModelHelper().isIdAttribute();
}
@NotNull
public String getAttributeMultiplicityLabel(final PersistentAttribute first, final PersistentAttribute second, final boolean isSource) {
assert first instanceof PersistentRelationshipAttribute && (second == null || second instanceof PersistentRelationshipAttribute);
final PersistentRelationshipAttribute attribute = ((PersistentRelationshipAttribute)first);
final boolean many = attribute.getAttributeModelHelper().getRelationshipType().isMany(isSource);
final boolean optional = attribute.getAttributeModelHelper().isRelationshipSideOptional(isSource) && !isNotNull((PersistentRelationshipAttribute)second);
return PersistenceCommonUtil.getMultiplicityString(optional, many);
}
private boolean isNotNull(final PersistentRelationshipAttribute attribute) {
final PsiMember owner = attribute == null? null : attribute.getPsiMember();
return owner != null && AnnotationUtil.isNotNull(owner);
}
@Nullable
public Icon getEntityIcon(final PersistentObject persistentObject) {
return ElementPresentationManager.getIcon(persistentObject);
}
@Nullable
public Icon getAttributeIcon(final PersistentAttribute persistentAttribute) {
return ElementPresentationManager.getIcon(persistentAttribute);
}
@NotNull
public TypeSafeDataProvider createDataProvider(final PersistenceDiagram<PersistencePackage, PersistentObject, PersistentAttribute> diagram) {
return new TypeSafeDataProvider() {
public void calcData(final DataKey key, final DataSink sink) {
getData(diagram, key, sink);
}
};
}
protected boolean getData(final PersistenceDiagram<PersistencePackage, PersistentObject, PersistentAttribute> diagram, final DataKey key,
final DataSink sink) {
boolean set = false;
if (DataKeys.PROJECT.equals(key)) {
set = true;
sink.put(DataKeys.PROJECT, diagram.getUnit().getPsiManager().getProject());
}
else if (DataKeys.MODULE.equals(key)) {
set = true;
sink.put(DataKeys.MODULE, diagram.getUnit().getModule());
}
else if (PersistenceDataKeys.PERSISTENCE_FACET.equals(key)) {
set = true;
sink.put(PersistenceDataKeys.PERSISTENCE_FACET, myFacet);
}
else if (JamObjectDescriptor.SELECTED_COMMON_MODEL_ELEMENT.equals(key)) {
final CommonModelElement element = diagram.getSelectedEntity() != null ? diagram.getSelectedEntity() : diagram.getUnit();
set = true;
sink.put(JamObjectDescriptor.SELECTED_COMMON_MODEL_ELEMENT, element);
}
else if (PersistenceDataKeys.PERSISTENCE_UNIT.equals(key)) {
set = true;
sink.put(PersistenceDataKeys.PERSISTENCE_UNIT, diagram.getUnit());
}
else if (DataKeys.PSI_ELEMENT_ARRAY.equals(key)) {
set = true;
final Collection<CommonModelElement> elements = getSelectedElements(diagram);
if (!elements.isEmpty()) {
final HashSet<PsiElement> result = new HashSet<PsiElement>();
for (CommonModelElement element : elements) {
final PsiElement psiElement = element.getIdentifyingPsiElement();
ContainerUtil.addIfNotNull(psiElement, result);
}
sink.put(DataKeys.PSI_ELEMENT_ARRAY, result.toArray(new PsiElement[result.size()]));
}
}
else if (DataKeys.DELETE_ELEMENT_PROVIDER.equals(key)) {
set = true;
final Collection<CommonModelElement> elements = getSelectedElements(diagram);
if (!elements.isEmpty()) {
sink.put(DataKeys.DELETE_ELEMENT_PROVIDER, new JamDeleteProvider(new DefaultUserResponse(diagram.getUnit().getPsiManager().getProject()), elements));
}
}
else if (DataKeys.NAVIGATABLE_ARRAY.equals(key)) {
set = true;
final Collection<CommonModelElement> elements = getSelectedElements(diagram);
if (!elements.isEmpty()) {
final HashSet<OpenFileDescriptor> result = new HashSet<OpenFileDescriptor>();
for (CommonModelElement element : elements) {
final PsiElement psiElement = element.getIdentifyingPsiElement();
if (psiElement != null) {
final PsiFile containingFile = psiElement.getContainingFile();
final VirtualFile file = containingFile == null ? null : containingFile.getVirtualFile();
if (file != null) {
result.add(new OpenFileDescriptor(psiElement.getProject(), file, psiElement.getTextOffset()));
}
}
}
sink.put(DataKeys.NAVIGATABLE_ARRAY, result.toArray(new Navigatable[result.size()]));
}
}
return set;
}
private Collection<CommonModelElement> getSelectedElements(final PersistenceDiagram<PersistencePackage, PersistentObject, PersistentAttribute> diagram) {
final Collection<CommonModelElement> elements = new HashSet<CommonModelElement>();
diagram.processSelectedNodes(new PairProcessor<PersistentObject, String>() {
public boolean process(final PersistentObject persistentObject, final String persistentAttribute) {
ContainerUtil.addIfNotNull(persistentObject, elements);
return true;
}
});
diagram.processSelectedEdges(new PairProcessor<PersistentObject, PersistentAttribute>() {
public boolean process(final PersistentObject persistentObject, final PersistentAttribute persistentAttribute) {
ContainerUtil.addIfNotNull(persistentAttribute, elements);
if (persistentAttribute instanceof PersistentRelationshipAttribute) {
elements.addAll(myModelBrowser.queryTheOtherSideAttributes((PersistentRelationshipAttribute)persistentAttribute, false).findAll());
}
return true;
}
});
return elements;
}
public boolean processEditNode(final PersistenceDiagram<PersistencePackage, PersistentObject, PersistentAttribute> diagram, final PersistentObject entity) {
return false;
}
public boolean processEditEdge(final PersistenceDiagram<PersistencePackage, PersistentObject, PersistentAttribute> persistenceDiagram) {
return false;
}
public void processCreateEdge(final PersistenceDiagram<PersistencePackage, PersistentObject, PersistentAttribute> persistenceDiagram,
final PersistentObject sourceEntity, final PersistentObject targetEntity) {
}
public void customizeGraphView(final Graph2DView view, final EditMode editMode) {
// nothing
}
}