AadlSearchResultPage.java
/**
* Copyright (c) 2004-2025 Carnegie Mellon University and others. (see Contributors file).
* All Rights Reserved.
*
* NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE
* OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT
* MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
* SPDX-License-Identifier: EPL-2.0
*
* Created, in part, with funding and support from the United States Government. (see Acknowledgments file).
*
* This program includes and/or can make use of certain third party source code, object code, documentation and other
* files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system
* configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and
* conditions contained in any such Third Party Software or separate license file distributed with such Third Party
* Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici-
* aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li-
* censes only apply to the Third Party Software and not any other portion of this program or this program as a whole.
*/
package org.osate.ui.search;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.search.ui.ISearchResult;
import org.eclipse.search.ui.ISearchResultListener;
import org.eclipse.search.ui.ISearchResultPage;
import org.eclipse.search.ui.ISearchResultViewPart;
import org.eclipse.search.ui.SearchResultEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.IReferenceDescription;
import org.eclipse.xtext.ui.editor.IURIEditorOpener;
import org.osate.aadl2.Classifier;
import org.osate.aadl2.NamedElement;
import org.osate.aadl2.modelsupport.util.AadlUtil;
import org.osate.aadl2.parsesupport.AObject;
import org.osate.search.AadlSearchResult;
import org.osate.search.AadlSearchResultEvent;
import org.osate.search.FoundDeclarationEvent;
import org.osate.search.FoundReferenceEvent;
import org.osate.xtext.aadl2.ui.internal.Aadl2Activator;
import com.google.inject.Inject;
import com.google.inject.Injector;
public final class AadlSearchResultPage implements ISearchResultListener, ISearchResultPage {
@Inject
private IURIEditorOpener editorOpener;
private AadlSearchResult searchResult;
private IPageSite pageSite;
private String id;
private ISearchResultViewPart viewPart;
private Composite root;
private TreeViewer treeViewer;
private final Map<URI, List<Object>> results = new TreeMap<URI, List<Object>>((uri1, uri2) -> {
final String[] segments1 = uri1.segments();
final String[] segments2 = uri2.segments();
final int length1 = segments1.length;
final int length2 = segments2.length;
final int max = Math.min(length1, length2);
for (int i = 0; i < max; i++) {
final int compareResult = String.CASE_INSENSITIVE_ORDER.compare(segments1[i], segments2[i]);
if (compareResult != 0) {
return compareResult;
}
}
// If we are here, then all the segments are equal: shortest goes first
return length1 - length2;
});
public AadlSearchResultPage() {
// XXX Stole this from AadlNavigatorActionProvider, not sure if this is correct
final Injector injector = Aadl2Activator.getInstance().getInjector(Aadl2Activator.ORG_OSATE_XTEXT_AADL2_AADL2);
editorOpener = injector.getInstance(IURIEditorOpener.class);
}
@Override
public IPageSite getSite() {
return pageSite;
}
@Override
public void init(final IPageSite site) throws PartInitException {
pageSite = site;
}
@Override
public void createControl(final Composite parent) {
root = new Composite(parent, SWT.NULL);
final Tree tree = new Tree(root, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
tree.setLayoutData(new GridData(GridData.FILL_BOTH));
tree.setLinesVisible(false);
tree.setHeaderVisible(false);
tree.setFont(parent.getFont());
final TreeColumn column = new TreeColumn(tree, SWT.LEFT);
final TreeColumnLayout treeLayout = new TreeColumnLayout();
treeLayout.setColumnData(column, new ColumnWeightData(1, true));
root.setLayout(treeLayout);
treeViewer = new TreeViewer(tree);
treeViewer.setLabelProvider(new TreeLabelProvider());
treeViewer.setContentProvider(new TreeContentProvider());
treeViewer.setInput(results);
treeViewer.addDoubleClickListener(event -> {
openURI(event);
});
}
@Override
public void dispose() {
// nothind to do
}
@Override
public Control getControl() {
return root;
}
@Override
public void setActionBars(IActionBars actionBars) {
// nothing to do
}
@Override
public void setFocus() {
root.setFocus();
}
@Override
public Object getUIState() {
return null;
}
@Override
public void setInput(final ISearchResult search, final Object uiState) {
if (search == null) {
// clean up old search
if (searchResult != null) {
searchResult.removeListener(this);
searchResult = null;
}
results.clear();
} else {
final AadlSearchResult aadlSearchResult = (AadlSearchResult) search;
searchResult = aadlSearchResult;
aadlSearchResult.addListener(this);
aadlSearchResult.getFoundDeclarations().forEach(objDesc -> addDeclaration(objDesc));
aadlSearchResult.getFoundReferences().forEach(refDesc -> addReference(refDesc));
Display.getDefault().asyncExec(() -> treeViewer.refresh());
}
}
@Override
public void setViewPart(final ISearchResultViewPart part) {
viewPart = part;
}
@Override
public void restoreState(IMemento memento) {
// TODO Auto-generated method stub
}
@Override
public void saveState(final IMemento memento) {
// nothing to do
}
@Override
public void setID(final String id) {
this.id = id;
}
@Override
public String getID() {
return id;
}
@Override
public String getLabel() {
return (searchResult == null) ? "No search result" : searchResult.getLabel();
}
@Override
public void searchResultChanged(final SearchResultEvent e) {
if (e instanceof AadlSearchResultEvent) {
if (e instanceof FoundDeclarationEvent) {
final IEObjectDescription objDesc = ((FoundDeclarationEvent) e).getObjectDescription();
addDeclaration(objDesc);
} else if (e instanceof FoundReferenceEvent) {
final IReferenceDescription refDesc = ((FoundReferenceEvent) e).getReferenceDescription();
addReference(refDesc);
}
Display.getDefault().asyncExec(() -> {
viewPart.updateLabel();
treeViewer.refresh();
});
}
}
private void addReference(final IReferenceDescription refDesc) {
addResult(refDesc.getSourceEObjectUri(), refDesc);
}
private void addDeclaration(final IEObjectDescription objDesc) {
addResult(objDesc.getEObjectURI(), objDesc);
}
private void addResult(final URI uri, final Object obj) {
List<Object> list = results.get(uri);
if (list == null) {
list = new ArrayList<Object>();
results.put(uri, list);
}
list.add(obj);
}
// Called in the UI thread
private final void openURI(final DoubleClickEvent event) {
final IStructuredSelection selected = (IStructuredSelection) event.getSelection();
final Object selectedNode = selected.getFirstElement();
if (selectedNode instanceof IEObjectDescription) {
editorOpener.open(((IEObjectDescription) selectedNode).getEObjectURI(), true);
} else if (selectedNode instanceof IReferenceDescription) {
final IReferenceDescription refDesc = (IReferenceDescription) selectedNode;
editorOpener.open(refDesc.getSourceEObjectUri(), refDesc.getEReference(), refDesc.getIndexInList(), true);
} else {
if (treeViewer.isExpandable(selectedNode)) {
if (treeViewer.getExpandedState(selectedNode)) {
treeViewer.collapseToLevel(selectedNode, 1);
} else {
treeViewer.expandToLevel(selectedNode, 1);
}
}
}
}
private final class TreeContentProvider implements ITreeContentProvider {
@SuppressWarnings("rawtypes")
@Override
public Object[] getElements(final Object inputElement) {
return ((Map) inputElement).keySet().toArray();
}
@SuppressWarnings("rawtypes")
@Override
public Object[] getChildren(final Object parentElement) {
return ((List) results.get(parentElement)).toArray();
}
@Override
public Object getParent(final Object element) {
if (element instanceof IEObjectDescription) {
return ((IEObjectDescription) element).getEObjectURI();
} else if (element instanceof IReferenceDescription) {
return ((IReferenceDescription) element).getSourceEObjectUri();
} else {
return null;
}
}
@Override
public boolean hasChildren(final Object element) {
if (element instanceof URI) {
return true;
}
return false;
}
}
private final class TreeLabelProvider extends LabelProvider {
@Override
public Image getImage(final Object element) {
// TODO Get some images
return null;
}
private String getContainerName(final AObject aObject) {
final Classifier classifier = AadlUtil.getContainingClassifier(aObject);
if (classifier != null) {
return " in " + classifier.getName();
} else {
return "";
}
}
@Override
public String getText(final Object element) {
if (element instanceof URI) {
final String[] segments = ((URI) element).segments();
final StringBuilder sb = new StringBuilder();
for (final String segment : segments) {
sb.append('/');
sb.append(segment);
}
return sb.toString();
} else if (element instanceof IEObjectDescription) {
final IEObjectDescription objDesc = (IEObjectDescription) element;
return "Declaration of " + objDesc.getName().toString("::");
} else if (element instanceof IReferenceDescription) {
final IReferenceDescription refDesc = (IReferenceDescription) element;
final URI targetEObjectUri = refDesc.getTargetEObjectUri();
final URI sourceEObjectUri = refDesc.getSourceEObjectUri();
final NamedElement namedElement = (NamedElement) searchResult.getResourceSet()
.getEObject(targetEObjectUri, true);
final AObject srcObject = (AObject) searchResult.getResourceSet().getEObject(sourceEObjectUri, true);
return "Reference to " + namedElement.getName() + getContainerName(srcObject);
} else {
return null;
}
}
}
}