/*
* 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.actions.navigator;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchWindow;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.core.DBeaverCore;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.edit.DBECommand;
import org.jkiss.dbeaver.model.edit.DBECommandContext;
import org.jkiss.dbeaver.model.edit.DBEStructEditor;
import org.jkiss.dbeaver.model.navigator.DBNContainer;
import org.jkiss.dbeaver.model.navigator.DBNDatabaseFolder;
import org.jkiss.dbeaver.model.navigator.DBNDatabaseNode;
import org.jkiss.dbeaver.model.navigator.DBNModel;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.DBRRunnableWithProgress;
import org.jkiss.dbeaver.model.sql.SQLUtils;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.model.struct.DBSObjectReference;
import org.jkiss.dbeaver.registry.editor.EntityEditorsRegistry;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.dbeaver.ui.SimpleCommandContext;
import org.jkiss.dbeaver.ui.UIIcon;
import org.jkiss.dbeaver.ui.UIUtils;
import org.jkiss.dbeaver.ui.controls.folders.ITabbedFolderContainer;
import org.jkiss.dbeaver.ui.dialogs.sql.ViewSQLDialog;
import org.jkiss.dbeaver.ui.editors.IDatabaseEditor;
import org.jkiss.dbeaver.ui.editors.IDatabaseEditorInput;
import org.jkiss.dbeaver.ui.navigator.database.DatabaseNavigatorView;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public abstract class NavigatorHandlerObjectBase extends AbstractHandler {
private static final Log log = Log.getLog(NavigatorHandlerObjectBase.class);
static boolean updateUI = true;
protected static class CommandTarget {
private DBECommandContext context;
private IDatabaseEditor editor;
private CommandTarget()
{
}
private CommandTarget(DBECommandContext context)
{
this.context = context;
}
public CommandTarget(IDatabaseEditor editor)
{
this.editor = editor;
this.context = editor.getEditorInput().getCommandContext();
}
public DBECommandContext getContext()
{
return context;
}
public IDatabaseEditor getEditor()
{
return editor;
}
}
protected static CommandTarget getCommandTarget(
IWorkbenchWindow workbenchWindow,
DBNContainer container,
Class<?> childType,
boolean openEditor)
throws DBException
{
final Object parentObject = container.getValueObject();
DBSObject objectToSeek = null;
if (parentObject instanceof DBSObject) {
final DBEStructEditor parentStructEditor = EntityEditorsRegistry.getInstance().getObjectManager(parentObject.getClass(), DBEStructEditor.class);
if (parentStructEditor != null && RuntimeUtils.isTypeSupported(childType, parentStructEditor.getChildTypes())) {
objectToSeek = (DBSObject) parentObject;
}
}
if (objectToSeek != null) {
for (final IEditorReference editorRef : workbenchWindow.getActivePage().getEditorReferences()) {
final IEditorPart editor = editorRef.getEditor(false);
if (editor instanceof IDatabaseEditor) {
final IDatabaseEditorInput editorInput = ((IDatabaseEditor) editor).getEditorInput();
if (editorInput.getDatabaseObject() == objectToSeek) {
workbenchWindow.getActivePage().activate(editor);
switchEditorFolder(container, editor);
return new CommandTarget((IDatabaseEditor) editor);
}
}
}
if (openEditor && container instanceof DBNDatabaseNode) {
final IDatabaseEditor editor = (IDatabaseEditor) NavigatorHandlerObjectOpen.openEntityEditor(
(DBNDatabaseNode) container,
null,
workbenchWindow);
if (editor != null) {
switchEditorFolder(container, editor);
return new CommandTarget(editor);
}
}
}
if (container instanceof DBNDatabaseNode) {
// No editor found - create new command context
DBPDataSource dataSource = ((DBNDatabaseNode) container).getObject().getDataSource();
if (dataSource != null) {
return new CommandTarget(new SimpleCommandContext(dataSource.getDefaultContext(true), !openEditor));
}
}
return new CommandTarget();
}
private static void switchEditorFolder(DBNContainer container, IEditorPart editor)
{
if (editor instanceof ITabbedFolderContainer && container instanceof DBNDatabaseFolder) {
((ITabbedFolderContainer) editor).switchFolder(container.getChildrenType());
}
}
public static DBNDatabaseNode getNodeByObject(DBSObject object)
{
DBNModel model = DBeaverCore.getInstance().getNavigatorModel();
DBNDatabaseNode node = model.findNode(object);
if (node == null) {
NodeLoader nodeLoader = new NodeLoader(model, Collections.singleton(object));
try {
DBeaverUI.runInProgressService(nodeLoader);
} catch (InvocationTargetException e) {
log.warn("Can't load node for object '" + object.getName() + "'", e.getTargetException());
} catch (InterruptedException e) {
// do nothing
}
if (!nodeLoader.nodes.isEmpty()) {
node = nodeLoader.nodes.get(0);
}
}
return node;
}
public static Collection<DBNDatabaseNode> getNodesByObjects(Collection<Object> objects)
{
DBNModel model = DBeaverCore.getInstance().getNavigatorModel();
List<DBNDatabaseNode> result = new ArrayList<>();
List<Object> missingObjects = new ArrayList<>();
for (Object object : objects) {
if (object instanceof DBSObject) {
DBNDatabaseNode node = model.findNode((DBSObject) object);
if (node != null) {
result.add(node);
continue;
}
}
missingObjects.add(object);
}
if (!missingObjects.isEmpty()) {
NodeLoader nodeLoader = new NodeLoader(model, missingObjects);
try {
DBeaverUI.runInProgressService(nodeLoader);
} catch (InvocationTargetException e) {
log.warn("Can't load node for objects " + missingObjects.size(), e.getTargetException());
} catch (InterruptedException e) {
// do nothing
}
result.addAll(nodeLoader.nodes);
}
return result;
}
protected static boolean showScript(IWorkbenchWindow workbenchWindow, DBECommandContext commandContext, String dialogTitle)
{
Collection<? extends DBECommand> commands = commandContext.getFinalCommands();
StringBuilder script = new StringBuilder();
for (DBECommand command : commands) {
script.append(SQLUtils.generateScript(commandContext.getExecutionContext().getDataSource(), command.getPersistActions(), false));
}
DatabaseNavigatorView view = UIUtils.findView(workbenchWindow, DatabaseNavigatorView.class);
if (view != null) {
ViewSQLDialog dialog = new ViewSQLDialog(
view.getSite(),
commandContext.getExecutionContext(),
dialogTitle,
UIIcon.SQL_PREVIEW,
script.toString());
dialog.setShowSaveButton(true);
return dialog.open() == IDialogConstants.PROCEED_ID;
} else {
return false;
}
}
private static class NodeLoader implements DBRRunnableWithProgress {
private final DBNModel model;
private final Collection<? extends Object> objects;
private List<DBNDatabaseNode> nodes;
public NodeLoader(DBNModel model, Collection<? extends Object> objects)
{
this.model = model;
this.objects = objects;
this.nodes = new ArrayList<>(objects.size());
}
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException
{
for (Object object : objects) {
DBSObject structObject;
if (object instanceof DBSObject) {
structObject = (DBSObject) object;
} else if (object instanceof DBSObjectReference) {
try {
structObject = ((DBSObjectReference) object).resolveObject(monitor);
} catch (DBException e) {
log.error("Can't resolve object reference", e);
continue;
}
} else {
log.warn("Unsupported object type: " + object);
continue;
}
DBNDatabaseNode node = model.getNodeByObject(monitor, structObject, true);
if (node != null) {
nodes.add(node);
}
}
}
}
protected static class ObjectSaver implements DBRRunnableWithProgress {
private final DBECommandContext commander;
public ObjectSaver(DBECommandContext commandContext)
{
this.commander = commandContext;
}
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException
{
try {
commander.saveChanges(monitor);
} catch (DBException e) {
throw new InvocationTargetException(e);
}
}
}
}