/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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 org.jkiss.dbeaver.ui.search;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.search.ui.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.part.Page;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.core.CoreMessages;
import org.jkiss.dbeaver.core.DBeaverCore;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.DBPNamedObject;
import org.jkiss.dbeaver.model.navigator.DBNContainer;
import org.jkiss.dbeaver.model.navigator.DBNNode;
import org.jkiss.dbeaver.model.navigator.DBNResource;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
import org.jkiss.dbeaver.ui.LoadingJob;
import org.jkiss.dbeaver.ui.controls.TreeContentProvider;
import org.jkiss.dbeaver.ui.controls.itemlist.NodeListControl;
import org.jkiss.dbeaver.ui.navigator.INavigatorModelView;
import org.jkiss.utils.CommonUtils;
import java.util.*;
public abstract class AbstractSearchResultsPage <OBJECT_TYPE> extends Page implements ISearchResultPage,INavigatorModelView {
private String id;
private ISearchResult searchResult;
private Object uiState;
private ISearchResultViewPart viewPart;
private ISearchResultListener resultListener;
private SearchResultsControl itemList;
public AbstractSearchResultsPage() {
this.resultListener = new ISearchResultListener() {
@Override
public void searchResultChanged(SearchResultEvent e)
{
List objects = null;
if (e instanceof AbstractSearchResult.DatabaseSearchResultEvent) {
objects = ((AbstractSearchResult.DatabaseSearchResultEvent) e).getObjects();
} else if (e.getSearchResult() instanceof AbstractSearchResult) {
final AbstractSearchResult result = (AbstractSearchResult) e.getSearchResult();
objects = result.getObjects();
}
if (objects != null) {
final List newObjects = objects;
DBeaverUI.syncExec(new Runnable() {
@Override
public void run() {
populateObjects(new VoidProgressMonitor(), newObjects);
}
});
}
}
};
}
@Override
public void createControl(Composite parent)
{
itemList = createResultControl(parent);
itemList.createProgressPanel();
itemList.setInfo(CoreMessages.dialog_search_objects_item_list_info);
itemList.setFitWidth(true);
itemList.setLayoutData(new GridData(GridData.FILL_BOTH));
getSite().setSelectionProvider(itemList.getSelectionProvider());
}
@Override
public void dispose() {
super.dispose();
}
protected SearchResultsControl createResultControl(Composite parent) {
return new SearchResultsControl(parent);
}
@Override
public Control getControl()
{
return itemList;
}
@Override
public void setFocus()
{
if (itemList != null && !itemList.isDisposed()) {
itemList.setFocus();
}
}
public void populateObjects(DBRProgressMonitor monitor, Collection<OBJECT_TYPE> objects)
{
if (itemList != null && !itemList.isDisposed()) {
List<DBNNode> nodes = new ArrayList<>(objects.size());
for (OBJECT_TYPE object : objects) {
nodes.add(getNodeFromObject(object));
}
TreeViewer itemsViewer = (TreeViewer) itemList.getItemsViewer();
Collection<DBNNode> oldNodes = itemList.getListData();
List<DBNNode> newNodes = new ArrayList<>();
if (!CommonUtils.isEmpty(oldNodes)) {
newNodes.addAll(oldNodes);
}
newNodes.addAll(nodes);
((ResultsContentProvider)itemsViewer.getContentProvider()).rebuildObjectTree(newNodes);
itemList.appendListData(nodes);
itemsViewer.expandAll();
}
}
protected abstract DBNNode getNodeFromObject(OBJECT_TYPE object);
public void clearObjects()
{
itemList.clearListData();
}
@Override
public DBNNode getRootNode()
{
return itemList.getRootNode();
}
@Nullable
@Override
public Viewer getNavigatorViewer()
{
return itemList.getNavigatorViewer();
}
@Override
public Object getUIState()
{
return uiState;
}
@Override
public void setInput(ISearchResult search, Object uiState)
{
if (this.searchResult != null) {
this.searchResult.removeListener(this.resultListener);
}
this.searchResult = search;
this.uiState = uiState;
if (this.searchResult != null) {
this.searchResult.addListener(this.resultListener);
}
if (this.searchResult == null) {
clearObjects();
}
}
@Override
public void setViewPart(ISearchResultViewPart part)
{
this.viewPart = part;
}
@Override
public void restoreState(IMemento memento)
{
}
@Override
public void saveState(IMemento memento)
{
}
@Override
public void setID(String id)
{
this.id = id;
}
@Override
public String getID()
{
return this.id;
}
@Override
public String getLabel()
{
return searchResult == null ? "" : searchResult.getLabel();
}
protected class SearchResultsControl extends NodeListControl {
public SearchResultsControl(Composite resultsGroup)
{
super(resultsGroup, SWT.SHEET, getSite(),
DBeaverCore.getInstance().getNavigatorModel().getRoot(),
new ResultsContentProvider());
}
@Override
protected void fillCustomActions(IContributionManager contributionManager)
{
}
@Override
protected Class<?>[] getListBaseTypes(Collection<DBNNode> items)
{
return new Class<?>[] {DBPNamedObject.class};
}
@Override
protected LoadingJob<Collection<DBNNode>> createLoadService()
{
// No load service
return null;
}
}
private static class ResultsNode {
DBNNode node;
ResultsNode parent;
final List<ResultsNode> children = new ArrayList<>();
public ResultsNode(DBNNode node, ResultsNode parent)
{
this.node = node;
this.parent = parent;
}
DBNNode[] getChildrenNodes()
{
DBNNode[] nodes = new DBNNode[children.size()];
for (int i = 0; i < children.size(); i++) {
nodes[i] = children.get(i).node;
}
return nodes;
}
}
private class ResultsContentProvider extends TreeContentProvider {
private ResultsNode rootResults;
private Map<DBNNode,ResultsNode> nodeMap;
private ResultsContentProvider() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
{
if (newInput instanceof Collection) {
rebuildObjectTree((Collection<DBNNode>) newInput);
}
}
@Override
public Object getParent(Object element)
{
if (element instanceof DBNNode) {
ResultsNode results = nodeMap.get(element);
if (results != null && results.parent != null) {
return results.parent.node;
}
}
return null;
}
@Override
public boolean hasChildren(Object parentElement)
{
if (parentElement instanceof DBNNode) {
ResultsNode results = nodeMap.get(parentElement);
return results != null && !results.children.isEmpty();
}
return false;
}
@Override
public Object[] getChildren(Object parentElement)
{
if (parentElement instanceof DBNNode) {
ResultsNode results = nodeMap.get(parentElement);
if (results != null) {
return results.getChildrenNodes();
}
}
return null;
}
@Override
public Object[] getElements(Object inputElement)
{
return rootResults.getChildrenNodes();
}
private void rebuildObjectTree(Collection<DBNNode> nodeList)
{
rootResults = new ResultsNode(getRootNode(), null);
nodeMap = new IdentityHashMap<>();
final List<DBNNode> allParents = new ArrayList<>();
for (DBNNode node : nodeList) {
// Collect parent nodes
allParents.clear();
for (DBNNode parent = node.getParentNode(); parent != null && parent != getRootNode(); parent = parent.getParentNode()) {
if (parent instanceof DBNContainer || parent instanceof DBNResource) {
continue;
}
allParents.add(0, parent);
}
// Construct hierarchy
ResultsNode curParentResults = rootResults;
for (DBNNode parent : allParents) {
ResultsNode parentResults = nodeMap.get(parent);
if (parentResults == null) {
parentResults = new ResultsNode(parent, curParentResults);
nodeMap.put(parent, parentResults);
curParentResults.children.add(parentResults);
}
curParentResults = parentResults;
}
// Make leaf
ResultsNode leaf = new ResultsNode(node, curParentResults);
nodeMap.put(node, leaf);
curParentResults.children.add(leaf);
}
}
}
}