/**
* �������Ȩ���������ӹɷ�����˾ ��Ȩ����
* ϵͳ���ƣ�JRES Studio
*/
package com.hundsun.ares.studio.reference.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.ObjectUtils;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.RunnableWithResult;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import com.hundsun.ares.studio.core.ARESCore;
import com.hundsun.ares.studio.core.ARESElementChangedEvent;
import com.hundsun.ares.studio.core.ARESModelException;
import com.hundsun.ares.studio.core.IARESElement;
import com.hundsun.ares.studio.core.IARESElementChangeListener;
import com.hundsun.ares.studio.core.IARESProject;
import com.hundsun.ares.studio.core.IARESResource;
import com.hundsun.ares.studio.core.IReferencedLibrary;
import com.hundsun.ares.studio.model.reference.ProjectRelationCollection;
import com.hundsun.ares.studio.model.reference.ReferenceFactory;
import com.hundsun.ares.studio.model.reference.ReferenceInfo;
import com.hundsun.ares.studio.model.reference.RelationInfo;
import com.hundsun.ares.studio.model.reference.RelationTable;
import com.hundsun.ares.studio.reference.ViewerUtils;
/**
* �ṩ�����ù�ϵ�IJ鿴��ͼ
*
* @author gongyf
*
*/
public class RelationTableViewer {
private static class RemoveProjectInfo extends RecordingCommand {
private RelationTable table;
private IARESProject project;
/**
* @param domain
* @param table
* @param project
*/
public RemoveProjectInfo(TransactionalEditingDomain domain,
RelationTable table, IARESProject project) {
super(domain);
this.table = table;
this.project = project;
}
/* (non-Javadoc)
* @see org.eclipse.emf.transaction.RecordingCommand#doExecute()
*/
@Override
protected void doExecute() {
table.getProjects().remove(project);
}
}
private static class RemoveResourceInfo extends RecordingCommand {
private RelationTable table;
private IARESResource resource;
/**
* @param domain
* @param table
* @param resource
*/
public RemoveResourceInfo(TransactionalEditingDomain domain,
RelationTable table, IARESResource resource) {
super(domain);
this.table = table;
this.resource = resource;
}
/* (non-Javadoc)
* @see org.eclipse.emf.transaction.RecordingCommand#doExecute()
*/
@Override
protected void doExecute() {
ProjectRelationCollection pi = table.getProjects().get(resource.getARESProject());
pi.getRelations().getRelationOperator().removeRelationsByResource(resource);
}
}
private static class ChangeResourceInfo extends RecordingCommand {
private RelationTable table;
private IARESResource resource;
private Map<Object, Object> context;
/**
* @param domain
* @param table
* @param resource
* @param context
*/
public ChangeResourceInfo(TransactionalEditingDomain domain,
RelationTable table, IARESResource resource,
Map<Object, Object> context) {
super(domain);
this.table = table;
this.resource = resource;
this.context = context;
}
/* (non-Javadoc)
* @see org.eclipse.emf.transaction.RecordingCommand#doExecute()
*/
@Override
protected void doExecute() {
ProjectRelationCollection pi = table.getProjects().get(resource.getARESProject());
List<RelationInfo> oldList = ViewerUtils.getRelationInfos(table, resource);
List<RelationInfo> newList = ViewerUtils.getRelationInfos(resource, context);
// �ҳ���������Ŀ��ɾ������Ŀ
HashSet<RelationInfo> tempSetAll = new HashSet<RelationInfo>();
for (int i=0; i<oldList.size(); i++) {
tempSetAll.add(oldList.get(i));
}
HashSet<RelationInfo> setDup = new HashSet<RelationInfo>();
ArrayList<RelationInfo> newClean = new ArrayList<RelationInfo>();
for (RelationInfo relationInfo: newList) {
if (tempSetAll.add(relationInfo)) {
newClean.add(relationInfo);
} else {
setDup.add(relationInfo);
}
}
ArrayList<RelationInfo> oldListClean = new ArrayList<RelationInfo>();
for (RelationInfo relationInfo: oldList ) {
if (setDup.add(relationInfo)) {
oldListClean.add(relationInfo);
}
}
pi.getRelations().getRelationOperator().updateRelationsByResourceChange(resource, oldListClean, newClean);
}
}
private static class AddProjectInfo extends RecordingCommand {
private RelationTable table;
private IARESProject project;
private List<RelationInfo> infoList;
/**
* @param domain
* @param table
* @param project
* @param collecion
*/
public AddProjectInfo(TransactionalEditingDomain domain,
RelationTable table, IARESProject project,
List<RelationInfo> infoList) {
super(domain);
this.table = table;
this.project = project;
this.infoList = infoList;
}
/* (non-Javadoc)
* @see org.eclipse.emf.transaction.RecordingCommand#doExecute()
*/
@Override
protected void doExecute() {
ProjectRelationCollection value = table.getProjects().get(project);
if (value == null) {
value = ReferenceFactory.eINSTANCE.createProjectRelationCollection();
table.getProjects().put(project, value);
}
value.getRelations().getRelationOperator().initProjectRelation(infoList);
}
}
/**
* �༭�ڴ�ͳ��������Ϣ�ı༭��
*/
private TransactionalEditingDomain editingDomain;
private RelationTable table;
/**
* ���ڱ�����й�Ԥ����ķ�Χ
*/
private Set<IARESProject> processedProjects = new HashSet<IARESProject>();
private IResourceChangeListener listener = new IResourceChangeListener() {
@Override
public void resourceChanged(IResourceChangeEvent event) {
IResourceDelta delta = event.getDelta();
if (delta != null) {
ARESElementDeltaVisitor visitor = new ARESElementDeltaVisitor();
try {
delta.accept(visitor);
synchronized (processedProjects) {
CompoundCommand command = new CompoundCommand();
for (IARESElement element : visitor.getRemovedElements()) {
if (element instanceof IARESProject) {
// ���̱�ɾ������Ҫɾ��������ص�����
processedProjects.remove(element);
// ɾ������
command.append(new RemoveProjectInfo(editingDomain, table, (IARESProject)element));
} else if (element instanceof IARESResource) {
// ������Ѿ�����ķ�Χ��������������
IARESResource aresResource = (IARESResource) element;
if (processedProjects.contains(aresResource.getARESProject())) {
command.append(new RemoveResourceInfo(editingDomain, table, aresResource));
}
}
}
for (IARESElement element : visitor.getAddedOrChangedElements()) {
// ��Ӻ��Ĺ����Dz���Ҫ�����
if (element instanceof IARESResource) {
IARESResource aresResource = (IARESResource) element;
if (processedProjects.contains(aresResource.getARESProject())) {
Map<Object, Object> context = createRelationProviderContext();
command.append(new ChangeResourceInfo(editingDomain, table, aresResource, context));
}
}
}
excute(command);
}
} catch (CoreException e) {
}
}
}
};
/**
* ���ڼ������ñ仯
*/
private IARESElementChangeListener listener2 = new IARESElementChangeListener() {
@Override
public void elementChanged(ARESElementChangedEvent event) {
if (event.getType() == ARESElementChangedEvent.RES_PATH) {
IARESProject changedProject = (IARESProject) event.getElement();
synchronized (processedProjects) {
processedProjects.remove(changedProject);
excute(new RemoveProjectInfo(editingDomain, table, changedProject));
}
}
}};
/**
*
*/
public RelationTableViewer() {
// ����ģ��
editingDomain = TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain();
Resource xmlRes = new XMLResourceImpl();
xmlRes.getContents().add(table = ReferenceFactory.eINSTANCE.createRelationTable());
editingDomain.getResourceSet().getResources().add(xmlRes);
ResourcesPlugin.getWorkspace().addResourceChangeListener(listener);
ARESCore.addElementListener(listener2);
}
public void dispose() {
ARESCore.removeElementListener(listener2);
ResourcesPlugin.getWorkspace().removeResourceChangeListener(listener);
editingDomain.dispose();
editingDomain = null;
}
/**
* @return the table
*/
public RelationTable getTable() {
return table;
}
/**
* ������ȡ��Դ������Ϣʱ��������
* @return
*/
private Map<Object, Object> createRelationProviderContext() {
return Collections.emptyMap();
}
// ���µĽӿ�Ŀǰû�ã�������ʱע�͵�
// /**
// * ���ҳ�ָ�����������õ�������Ϣ
// *
// * @param path һ�������ռ�����·��
// * @param location ��λ�ַ���������Ϊnull
// * @return
// */
// public List<RelationInfo> getRelationInfoBySource(IARESResource resource) {
//
// return null;
// }
/**
* ͨ�������õ���Ϣ���ҳ�ʹ������Щ������Ϣ�����ù�ϵ
*
* @param refType ����Ϊnull
* @param refName ����Ϊnull
* @param project ��Ϊ���õ����λ�ã����ҷ�Χ�Ǹù����Լ�ֱ�ӻ��������ù��̵Ĺ���
* @return
*/
public List<RelationInfo> getRelationInfoByTarget(final String refType, final String refName, final IARESProject project) {
process(project, true);
try {
return TransactionUtil.runExclusive(editingDomain, new RunnableWithResult.Impl<List<RelationInfo>>(){
@Override
public void run() {
List<RelationInfo> result = new ArrayList<RelationInfo>();
for (IARESProject p : ViewerUtils.getAllRelatedProjects(project)) {
ProjectRelationCollection prc = table.getProjects().get(p);
if (prc != null) {
result.addAll(prc.getRelationInfos(refType, refName));
}
}
setResult(result);
}
});
} catch (InterruptedException e) {
return Collections.emptyList();
}
}
/**
* ͨ�������õ���Ϣ���ҳ�ʹ������Щ������Ϣ�����ù�ϵ
*
* @param refType ����Ϊnull
* @param refName ����Ϊnull
* @param refNamespace ����Ϊnull
* @param project ��Ϊ���õ����λ�ã����ҷ�Χ�Ǹù����Լ�ֱ�ӻ��������ù��̵Ĺ���
* @return
*/
public List<RelationInfo> getRelationInfoByTarget(final String refType, final String refName, final String refNamespace, final IARESProject project) {
process(project, true);
try {
return TransactionUtil.runExclusive(editingDomain, new RunnableWithResult.Impl<List<RelationInfo>>(){
@Override
public void run() {
List<RelationInfo> result = new ArrayList<RelationInfo>();
for (IARESProject p : ViewerUtils.getAllRelatedProjects(project)) {
ProjectRelationCollection prc = table.getProjects().get(p);
if (prc != null) {
result.addAll(prc.getRelationInfos(refType, refName, refNamespace));
}
}
setResult(result);
}
});
} catch (InterruptedException e) {
return Collections.emptyList();
}
}
/**
* ������Ҫ�Ĺ��̣����һ�������Ѿ���������ٽ��д���
* @param project
* @param inRelatedProjects �Ƿ�����صĹ��̣���ֱ�ӻ��������ù��̵Ĺ���
*/
private void process(IARESProject project, boolean inRelatedProjects) {
synchronized (processedProjects) {
List<IARESProject> needProcessProjects = new ArrayList<IARESProject>();
if (inRelatedProjects) {
needProcessProjects.addAll(Arrays.asList(ViewerUtils.getAllRelatedProjects(project)));
} else {
needProcessProjects.add(project);
}
Map<Object, Object> context = createRelationProviderContext();
CompoundCommand command = new CompoundCommand();
for (IARESProject p : needProcessProjects) {
if (!processedProjects.contains(p)) {
List<RelationInfo>infoList = new ArrayList<RelationInfo>();
// ��Ҫ�ռ����̱�������ð�����
List<IARESResource> resourceList = new ArrayList<IARESResource>();
try {
resourceList.addAll(Arrays.asList(p.getResources()));
for (IReferencedLibrary lib : p.getReferencedLibs()) {
resourceList.addAll(Arrays.asList(lib.getResources()));
}
} catch (ARESModelException e) {
}
for (IARESResource res : resourceList) {
infoList.addAll(ViewerUtils.getRelationInfos(res, context));
}
command.append(new AddProjectInfo(editingDomain, table, p, infoList));
// ���ñ��
processedProjects.add(p);
}
}
excute(command);
}
}
/**
* ִ������������
* @param command
*/
private void excute(Command command) {
editingDomain.getCommandStack().execute(command);
editingDomain.getCommandStack().flush();
}
}