blob: 02a29594867669c558305600151d850dcab12709 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2009 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - initial API and implementation
* IBM Corporation
*******************************************************************************/
/* -- ST-Origin --
* Source folder: org.eclipse.cdt.ui/src
* Class: org.eclipse.cdt.internal.ui.typehierarchy.THHierarchyModel
* Version: 1.15
*/
package org.eclipse.ptp.internal.rdt.ui.typehierarchy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.IFunctionDeclaration;
import org.eclipse.cdt.internal.ui.typehierarchy.ITHModelPresenter;
import org.eclipse.cdt.internal.ui.typehierarchy.Messages;
import org.eclipse.cdt.internal.ui.typehierarchy.THNode;
import org.eclipse.cdt.internal.ui.typehierarchy.THSchedulingRule;
import org.eclipse.cdt.internal.ui.viewsupport.IndexUI;
import org.eclipse.cdt.internal.ui.viewsupport.WorkingSetFilterUI;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.ptp.internal.rdt.core.model.Scope;
import org.eclipse.ptp.internal.rdt.core.typehierarchy.ITypeHierarchyService;
import org.eclipse.ptp.internal.rdt.core.typehierarchy.THGraph;
import org.eclipse.ptp.internal.rdt.core.typehierarchy.THGraphEdge;
import org.eclipse.ptp.internal.rdt.core.typehierarchy.THGraphNode;
import org.eclipse.ptp.rdt.core.serviceproviders.IIndexServiceProvider;
import org.eclipse.ptp.rdt.core.services.IRDTServiceConstants;
import org.eclipse.ptp.services.core.IService;
import org.eclipse.ptp.services.core.IServiceConfiguration;
import org.eclipse.ptp.services.core.IServiceModelManager;
import org.eclipse.ptp.services.core.IServiceProvider;
import org.eclipse.ptp.services.core.ServiceModelManager;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
public class THHierarchyModel {
public class BackgroundJob extends Job {
public BackgroundJob() {
super(Messages.THHierarchyModel_Job_title);
}
@Override
protected IStatus run(IProgressMonitor monitor) {
return onComputeGraph(this, monitor);
}
}
static final int TYPE_HIERARCHY = 0;
static final int SUB_TYPE_HIERARCHY = 1;
static final int SUPER_TYPE_HIERARCHY = 2;
static final int END_OF_COMPUTATION = 0;
private static final ISchedulingRule RULE = new THSchedulingRule();
private static final Object[] NO_CHILDREN= new Object[0];
private ICElement fInput;
private int fHierarchyKind;
private boolean fShowInheritedMembers;
private THGraph fGraph;
private THNode[] fRootNodes;
private THNode fSelectedTypeNode;
private ICElement fTypeToSelect;
private ICElement fSelectedMember;
private String fMemberSignatureToSelect;
private Job fJob;
private Display fDisplay;
private ITHModelPresenter fView;
private WorkingSetFilterUI fFilter;
public THHierarchyModel(ITHModelPresenter view, Display display) {
fDisplay= display;
fView= view;
}
public ICElement getInput() {
return fInput;
}
public int getHierarchyKind() {
return fHierarchyKind;
}
public void setHierarchyKind(int hierarchyKind) {
fHierarchyKind = hierarchyKind;
computeNodes();
}
public boolean isShowInheritedMembers() {
return fShowInheritedMembers;
}
public void setShowInheritedMembers(boolean showInheritedMembers) {
fShowInheritedMembers = showInheritedMembers;
updateSelectedMember();
updateImplementors();
}
public Object[] getHierarchyRootElements() {
if (fRootNodes == null) {
return new Object[] {"..."}; //$NON-NLS-1$
}
return fRootNodes;
}
public void setWorkingSetFilter(WorkingSetFilterUI filterUI) {
fFilter= filterUI;
computeNodes();
}
synchronized public void setInput(ICElement input, ICElement member) {
stopGraphComputation();
fInput= input;
fSelectedMember= member;
fMemberSignatureToSelect= getLocalElementSignature(fSelectedMember);
fRootNodes= null;
fSelectedTypeNode= null;
fTypeToSelect= input;
}
synchronized public void computeGraph() {
if (fJob != null) {
fJob.cancel();
}
fJob= new BackgroundJob();
fJob.setRule(RULE);
IWorkbenchSiteProgressService ps= fView.getProgressService();
if (ps != null) {
ps.schedule(fJob, 0L, true);
}
else {
fJob.schedule();
}
}
synchronized public void stopGraphComputation() {
if (fJob != null) {
fJob.cancel();
}
fJob= null;
}
protected IStatus onComputeGraph(Job job, IProgressMonitor monitor) {
THGraph graph = null;
try {
IProject project = fInput.getCProject().getProject();
IServiceModelManager smm = ServiceModelManager.getInstance();
IServiceConfiguration serviceConfig = smm.getActiveConfiguration(project);
IService indexingService = smm.getService(IRDTServiceConstants.SERVICE_C_INDEX);
IServiceProvider serviceProvider = serviceConfig.getServiceProvider(indexingService);
if (serviceProvider instanceof IIndexServiceProvider) {
ITypeHierarchyService service = ((IIndexServiceProvider) serviceProvider).getTypeHierarchyService();
graph = service.computeGraph(Scope.WORKSPACE_ROOT_SCOPE, fInput, monitor);
}
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
} catch (CoreException e) {
CUIPlugin.log(e);
} catch (InterruptedException e) {
return Status.CANCEL_STATUS;
}
finally {
onJobDone(graph, job);
}
return Status.OK_STATUS;
}
protected void computeNodes() {
if (fGraph == null) {
return;
}
boolean fwd= fHierarchyKind == SUPER_TYPE_HIERARCHY;
ArrayList<THNode> stack= new ArrayList<THNode>();
ArrayList<THNode> roots= new ArrayList<THNode>();
ArrayList<THNode> leafs= new ArrayList<THNode>();
THGraphNode inputNode= fGraph.getInputNode();
Collection<THGraphNode> groots;
if (fHierarchyKind == TYPE_HIERARCHY) {
groots= fGraph.getLeaveNodes();
}
else {
THGraphNode node= fGraph.getInputNode();
if (node != null) {
groots= Collections.singleton(node);
}
else {
groots= Collections.emptySet();
}
}
for (Iterator<THGraphNode> iterator = groots.iterator(); iterator.hasNext();) {
THGraphNode gnode = iterator.next();
THNode node = createNode(null, gnode, inputNode);
roots.add(node);
stack.add(node);
}
while(!stack.isEmpty()) {
THNode node= stack.remove(stack.size()-1);
THGraphNode gnode= fGraph.getNode(node.getElement());
List<THGraphEdge> edges= fwd ? gnode.getOutgoing() : gnode.getIncoming();
if (edges.isEmpty()) {
leafs.add(node);
}
else {
for (Iterator<THGraphEdge> iterator = edges.iterator(); iterator.hasNext();) {
THGraphEdge edge = iterator.next();
THGraphNode gchildNode= fwd ? edge.getEndNode() : edge.getStartNode();
THNode childNode= createNode(node, gchildNode, inputNode);
node.addChild(childNode);
stack.add(childNode);
}
}
}
fRootNodes= roots.toArray(new THNode[roots.size()]);
removeFilteredLeafs(fRootNodes);
fSelectedTypeNode= findSelection(fRootNodes);
if (fSelectedTypeNode != null) {
fTypeToSelect= fSelectedTypeNode.getElement();
updateSelectedMember();
}
updateImplementors();
}
private void removeFilteredLeafs(THNode[] rootNodes) {
for (int i = 0; i < rootNodes.length; i++) {
THNode node = rootNodes[i];
node.removeFilteredLeafs();
}
}
private THNode findSelection(THNode[] searchme) {
THNode[] result= new THNode[2];
findSelection(searchme, result);
if (result[0] != null) {
return result[0];
}
return result[1];
}
private void findSelection(THNode[] seachme, THNode[] result) {
for (int i = 0; i < seachme.length; i++) {
findSelection(seachme[i], result);
if (result[0] != null) {
break;
}
}
}
private void findSelection(THNode node, THNode[] result) {
if (node.equals(fSelectedTypeNode)) {
result[0]= node;
return;
}
else if (result[1] == null) {
if (node.getElement().equals(fTypeToSelect)) {
result[1]= node;
}
}
THNode[] children= node.getChildren();
findSelection(children, result);
}
private void updateSelectedMember() {
ICElement oldSelection= fSelectedMember;
fSelectedMember= null;
if (fSelectedTypeNode != null && fMemberSignatureToSelect != null) {
THGraphNode gnode= fGraph.getNode(fSelectedTypeNode.getElement());
if (gnode != null) {
ICElement[] members= gnode.getMembers(fShowInheritedMembers);
if (members != null) {
for (int i = 0; i < members.length; i++) {
ICElement member= members[i];
if (member.equals(oldSelection)) {
fSelectedMember= member;
return;
}
}
for (int i = 0; i < members.length; i++) {
ICElement member= members[i];
if (fMemberSignatureToSelect.equals(getLocalElementSignature(member))) {
fSelectedMember= member;
return;
}
}
}
}
}
}
private THNode createNode(THNode parent, THGraphNode gnode, THGraphNode inputNode) {
ICElement element = gnode.getElement();
THNode node= new THNode(parent, element);
if (gnode != inputNode && fFilter != null && !fFilter.isPartOfWorkingSet(element)) {
node.setIsFiltered(true);
}
return node;
}
synchronized private void onJobDone(final THGraph graph, Job job) {
if (fJob == job) {
fJob= null;
fDisplay.asyncExec(new Runnable(){
public void run() {
fGraph= graph;
THGraphNode inputNode= fGraph.getInputNode();
if (!fGraph.isFileIndexed()) {
fView.setMessage(IndexUI.getFileNotIndexedMessage(fInput));
}
else if (inputNode == null) {
fView.setMessage(Messages.THHierarchyModel_errorComputingHierarchy);
}
else {
if (fTypeToSelect == fInput) {
fTypeToSelect= inputNode.getElement();
}
fInput= inputNode.getElement();
}
computeNodes();
notifyEvent(END_OF_COMPUTATION);
}
});
}
}
private void notifyEvent(int event) {
fView.onEvent(event);
}
synchronized public void refresh() {
computeGraph();
}
public boolean isComputed() {
return fRootNodes!=null;
}
public THNode getSelectionInHierarchy() {
return fSelectedTypeNode;
}
public void onHierarchySelectionChanged(THNode node) {
fSelectedTypeNode= node;
if (node != null) {
fTypeToSelect= node.getElement();
}
updateSelectedMember();
updateImplementors();
}
public Object[] getMembers() {
if (fSelectedTypeNode != null) {
THGraphNode gnode= fGraph.getNode(fSelectedTypeNode.getElement());
Object[] result= gnode.getMembers(fShowInheritedMembers);
if (result != null) {
return result;
}
}
return NO_CHILDREN;
}
public void onMemberSelectionChanged(ICElement elem) {
fSelectedMember= elem;
if (fSelectedMember != null) {
fMemberSignatureToSelect= getLocalElementSignature(fSelectedMember);
}
updateImplementors();
}
private void updateImplementors() {
if (fRootNodes != null) {
for (int i = 0; i < fRootNodes.length; i++) {
THNode node = fRootNodes[i];
updateImplementors(node);
}
}
}
private void updateImplementors(THNode node) {
node.setIsImplementor(isImplementor(node.getElement()));
THNode[] children= node.getChildren();
for (int i = 0; i < children.length; i++) {
THNode child = children[i];
updateImplementors(child);
}
}
private boolean isImplementor(ICElement element) {
if (element == null
|| fSelectedMember == null || fMemberSignatureToSelect == null) {
return false;
}
THGraphNode gnode= fGraph.getNode(element);
if (gnode != null) {
ICElement[] members= gnode.getMembers(false);
if (members != null) {
for (int i = 0; i < members.length; i++) {
ICElement member = members[i];
if (member == fSelectedMember) {
return true;
}
if (fMemberSignatureToSelect.equals(getLocalElementSignature(member))) {
return true;
}
}
}
}
return false;
}
public ICElement getSelectedMember() {
return fSelectedMember;
}
public boolean hasTrivialHierarchy() {
if (fRootNodes == null || fRootNodes.length == 0) {
return true;
}
return fRootNodes.length == 1 && !fRootNodes[0].hasChildren();
}
String getLocalElementSignature(ICElement element) {
if (element != null) {
try {
switch (element.getElementType()) {
case ICElement.C_METHOD:
case ICElement.C_METHOD_DECLARATION:
return ((IFunctionDeclaration) element).getSignature();
case ICElement.C_FIELD:
return element.getElementName();
}
} catch (CModelException e) {
CUIPlugin.log(e);
}
}
return null;
}
}