/*
* 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.controls.itemlist;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.part.MultiPageEditorSite;
import org.jkiss.dbeaver.core.CoreCommands;
import org.jkiss.dbeaver.model.edit.DBEObjectReorderer;
import org.jkiss.dbeaver.model.navigator.DBNDatabaseFolder;
import org.jkiss.dbeaver.model.navigator.DBNDatabaseNode;
import org.jkiss.dbeaver.model.navigator.DBNNode;
import org.jkiss.dbeaver.model.navigator.meta.DBXTreeNode;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.load.DatabaseLoadService;
import org.jkiss.dbeaver.model.sql.SQLUtils;
import org.jkiss.dbeaver.model.struct.DBSWrapper;
import org.jkiss.dbeaver.registry.editor.EntityEditorsRegistry;
import org.jkiss.dbeaver.runtime.properties.ObjectPropertyDescriptor;
import org.jkiss.dbeaver.ui.*;
import org.jkiss.dbeaver.ui.actions.navigator.NavigatorHandlerFilterConfig;
import org.jkiss.dbeaver.ui.editors.entity.EntityEditor;
import org.jkiss.dbeaver.ui.navigator.NavigatorUtils;
import org.jkiss.utils.ArrayUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
* ItemListControl
*/
public class ItemListControl extends NodeListControl
{
private ISearchExecutor searcher;
private Color searchHighlightColor;
private Color disabledCellColor;
private Font normalFont;
private Font boldFont;
public ItemListControl(
Composite parent,
int style,
final IWorkbenchSite workbenchSite,
DBNNode node,
DBXTreeNode metaNode)
{
super(parent, style, workbenchSite, node, metaNode);
this.searcher = new SearcherFilter();
this.searchHighlightColor = new Color(parent.getDisplay(), 170, 255, 170);
this.disabledCellColor = parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW);
this.normalFont = parent.getFont();
this.boldFont = UIUtils.makeBoldFont(normalFont);
}
@Override
protected void fillCustomActions(IContributionManager contributionManager)
{
super.fillCustomActions(contributionManager);
final DBNNode rootNode = getRootNode();
if (rootNode instanceof DBNDatabaseFolder && ((DBNDatabaseFolder) rootNode).getItemsMeta() != null) {
contributionManager.add(new Action(
"Filter settings",
DBeaverIcons.getImageDescriptor(UIIcon.FILTER))
{
@Override
public void run()
{
NavigatorHandlerFilterConfig.configureFilters(getShell(), rootNode);
}
});
}
{
Action configColumnsAction = new Action(
"Configure columns",
DBeaverIcons.getImageDescriptor(UIIcon.CONFIGURATION)) {
@Override
public void run() {
columnController.configureColumns();
}
};
configColumnsAction.setDescription("Configure columns visibility");
contributionManager.add(configColumnsAction);
}
IWorkbenchSite workbenchSite = getWorkbenchSite();
if (workbenchSite != null) {
contributionManager.add(ActionUtils.makeCommandContribution(workbenchSite, IWorkbenchCommandConstants.FILE_REFRESH));
}
if (rootNode instanceof DBNDatabaseNode) {
contributionManager.add(new Separator());
contributionManager.add(ActionUtils.makeCommandContribution(
workbenchSite,
CoreCommands.CMD_OBJECT_OPEN));
contributionManager.add(ActionUtils.makeCommandContribution(
workbenchSite,
CoreCommands.CMD_OBJECT_CREATE));
contributionManager.add(ActionUtils.makeCommandContribution(
workbenchSite,
CoreCommands.CMD_OBJECT_DELETE));
}
if (rootNode instanceof DBNDatabaseNode && rootNode.isPersisted()) {
boolean hasReorder = false;
List<Class<?>> childrenTypes = ((DBNDatabaseNode) rootNode).getChildrenTypes(null);
for (Class<?> chilType : childrenTypes) {
if (EntityEditorsRegistry.getInstance().getObjectManager(chilType, DBEObjectReorderer.class) != null) {
hasReorder = true;
break;
}
}
if (hasReorder) {
contributionManager.add(new Separator());
contributionManager.add(ActionUtils.makeCommandContribution(
workbenchSite,
CoreCommands.CMD_OBJECT_MOVE_UP));
contributionManager.add(ActionUtils.makeCommandContribution(
workbenchSite,
CoreCommands.CMD_OBJECT_MOVE_DOWN));
}
}
if (workbenchSite instanceof MultiPageEditorSite) {
final MultiPageEditorPart editor = ((MultiPageEditorSite) workbenchSite).getMultiPageEditor();
if (editor instanceof EntityEditor) {
contributionManager.add(new Separator());
contributionManager.add(ActionUtils.makeCommandContribution(
workbenchSite,
IWorkbenchCommandConstants.FILE_SAVE,
null,
UIIcon.SAVE,
null,
true));
contributionManager.add(ActionUtils.makeCommandContribution(
workbenchSite,
IWorkbenchCommandConstants.FILE_REVERT,
null,
UIIcon.RESET,
null,
true));
}
}
}
@Override
public void disposeControl()
{
// if (objectEditorHandler != null) {
// objectEditorHandler.dispose();
// objectEditorHandler = null;
// }
UIUtils.dispose(searchHighlightColor);
UIUtils.dispose(disabledCellColor);
UIUtils.dispose(boldFont);
super.disposeControl();
}
@Override
protected ISearchExecutor getSearchRunner()
{
return searcher;
}
@Override
protected LoadingJob<Collection<DBNNode>> createLoadService()
{
return LoadingJob.createService(
new ItemLoadService(getNodeMeta()),
new ObjectsLoadVisualizer());
}
@Override
protected EditingSupport makeEditingSupport(ObjectColumn objectColumn)
{
return new CellEditingSupport(objectColumn);
}
@Override
protected CellLabelProvider getColumnLabelProvider(ObjectColumn objectColumn)
{
return new ItemColorProvider(objectColumn);
}
private class ItemLoadService extends DatabaseLoadService<Collection<DBNNode>> {
private DBXTreeNode metaNode;
protected ItemLoadService(DBXTreeNode metaNode)
{
super("Loading items", getRootNode() instanceof DBSWrapper ? (DBSWrapper)getRootNode() : null);
this.metaNode = metaNode;
}
@Override
public Collection<DBNNode> evaluate(DBRProgressMonitor monitor)
throws InvocationTargetException, InterruptedException
{
try {
List<DBNNode> items = new ArrayList<>();
DBNNode[] children = NavigatorUtils.getNodeChildrenFiltered(monitor, getRootNode(), false);
if (ArrayUtils.isEmpty(children)) {
return items;
}
for (DBNNode item : children) {
if (monitor.isCanceled()) {
break;
}
if (metaNode != null) {
if (!(item instanceof DBNDatabaseNode)) {
continue;
}
if (((DBNDatabaseNode)item).getMeta() != metaNode) {
continue;
}
}
items.add(item);
}
return items;
} catch (Throwable ex) {
throw new InvocationTargetException(ex);
}
}
}
private class CellEditingSupport extends EditingSupport {
private ObjectColumn objectColumn;
public CellEditingSupport(ObjectColumn objectColumn)
{
super(getItemsViewer());
this.objectColumn = objectColumn;
}
@Override
protected CellEditor getCellEditor(Object element)
{
DBNNode object = (DBNNode) element;
// Set cur list object to let property see it in createPropertyEditor
setCurListObject(object);
final ObjectPropertyDescriptor property = objectColumn.getProperty(getObjectValue(object));
if (property != null && property.isEditable(getObjectValue(object))) {
setFocusCell(object, objectColumn);
return UIUtils.createPropertyEditor(getWorkbenchSite(), getControl(), property.getSource(), property);
}
return null;
}
@Override
protected boolean canEdit(Object element)
{
DBNNode object = (DBNNode) element;
final ObjectPropertyDescriptor property = objectColumn.getProperty(getObjectValue(object));
return property != null && property.isEditable(getObjectValue(object));
}
@Override
protected Object getValue(Object element)
{
DBNNode object = (DBNNode) element;
final ObjectPropertyDescriptor property = objectColumn.getProperty(getObjectValue(object));
if (property != null) {
return getListPropertySource().getPropertyValue(null, getObjectValue(object), property);
}
return null;
}
@Override
protected void setValue(Object element, Object value)
{
DBNNode object = (DBNNode) element;
final ObjectPropertyDescriptor property = objectColumn.getProperty(getObjectValue(object));
try {
if (property != null) {
getListPropertySource().setPropertyValue(null, getObjectValue(object), property, value);
if (value instanceof Boolean) {
// Redraw control to let it repaint checkbox
getItemsViewer().getControl().redraw();
}
}
} catch (Exception e) {
UIUtils.showErrorDialog(null, "Error setting property value", "Error setting property '" + property.getId() + "' value", e);
}
}
}
private class SearcherFilter implements ISearchExecutor {
@Override
public boolean performSearch(String searchString, int options) {
try {
SearchFilter searchFilter = new SearchFilter(
searchString,
(options & SEARCH_CASE_SENSITIVE) != 0);
getItemsViewer().setFilters(new ViewerFilter[]{searchFilter});
return true;
} catch (PatternSyntaxException e) {
log.error(e.getMessage());
return false;
}
}
@Override
public void cancelSearch() {
getItemsViewer().setFilters(new ViewerFilter[]{});
}
}
private class SearchFilter extends ViewerFilter {
final Pattern pattern;
public SearchFilter(String searchString, boolean caseSensitiveSearch) throws PatternSyntaxException {
pattern = Pattern.compile(SQLUtils.makeLikePattern(searchString), caseSensitiveSearch ? 0 : Pattern.CASE_INSENSITIVE);
}
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (element instanceof DBNNode) {
return pattern.matcher(((DBNNode) element).getName()).find();
}
return false;
}
}
private class SearcherHighligther extends ObjectSearcher<DBNNode> {
@Override
protected void setInfo(String message)
{
ItemListControl.this.setInfo(message);
}
@Override
protected Collection<DBNNode> getContent()
{
return (Collection<DBNNode>) getItemsViewer().getInput();
}
@Override
protected void selectObject(DBNNode object)
{
getItemsViewer().setSelection(object == null ? new StructuredSelection() : new StructuredSelection(object));
}
@Override
protected void updateObject(DBNNode object)
{
getItemsViewer().update(object, null);
}
@Override
protected void revealObject(DBNNode object)
{
getItemsViewer().reveal(object);
}
}
private class ItemColorProvider extends ObjectColumnLabelProvider {
ItemColorProvider(ObjectColumn objectColumn)
{
super(objectColumn);
}
@Override
public Font getFont(Object element)
{
final Object object = getObjectValue((DBNNode) element);
return objectColumn.isNameColumn(object) && NavigatorUtils.isDefaultElement(element) ? boldFont : normalFont;
}
@Override
public Color getForeground(Object element)
{
return null;
}
@Override
public Color getBackground(Object element)
{
DBNNode node = (DBNNode) element;
if (node.isDisposed()) {
return null;
}
if (searcher instanceof SearcherHighligther && ((SearcherHighligther) searcher).hasObject(node)) {
return searchHighlightColor;
}
if (isNewObject(node)) {
final Object objectValue = getObjectValue(node);
final ObjectPropertyDescriptor prop = objectColumn.getProperty(getObjectValue(node));
if (prop != null && !prop.isEditable(objectValue)) {
return disabledCellColor;
}
}
return null;
}
}
private class PackColumnsAction extends Action {
public PackColumnsAction() {
super("Pack columns", DBeaverIcons.getImageDescriptor(UIIcon.TREE_EXPAND));
}
@Override
public void run()
{
ColumnViewer itemsViewer = getItemsViewer();
if (itemsViewer instanceof TreeViewer) {
UIUtils.packColumns(((TreeViewer) itemsViewer).getTree());
} else {
UIUtils.packColumns(((TableViewer) itemsViewer).getTable());
}
}
}
}