/*
* 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.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.commands.IElementUpdater;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.menus.UIElement;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.DBeaverPreferences;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.core.CoreMessages;
import org.jkiss.dbeaver.core.DBeaverActivator;
import org.jkiss.dbeaver.model.edit.DBEObjectMaker;
import org.jkiss.dbeaver.model.navigator.*;
import org.jkiss.dbeaver.model.runtime.DBRRunnableWithProgress;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.registry.editor.EntityEditorsRegistry;
import org.jkiss.dbeaver.runtime.TasksJob;
import org.jkiss.dbeaver.ui.DBeaverIcons;
import org.jkiss.dbeaver.ui.UIIcon;
import org.jkiss.dbeaver.ui.UIUtils;
import org.jkiss.dbeaver.ui.dialogs.ConfirmationDialog;
import org.jkiss.dbeaver.ui.editors.IDatabaseEditor;
import org.jkiss.dbeaver.ui.editors.IDatabaseEditorInput;
import java.util.*;
public class NavigatorHandlerObjectDelete extends NavigatorHandlerObjectBase implements IElementUpdater {
private static final Log log = Log.getLog(NavigatorHandlerObjectDelete.class);
private IStructuredSelection structSelection;
private Boolean deleteAll;
private List<DBRRunnableWithProgress> tasksToExecute = new ArrayList<>();
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
this.structSelection = null;
this.deleteAll = null;
this.tasksToExecute.clear();
final IWorkbenchWindow activeWorkbenchWindow = HandlerUtil.getActiveWorkbenchWindow(event);
final ISelection selection = HandlerUtil.getCurrentSelection(event);
if (selection instanceof IStructuredSelection) {
structSelection = (IStructuredSelection)selection;
for (Iterator<?> iter = structSelection.iterator(); iter.hasNext(); ) {
Object element = iter.next();
if (element instanceof DBNDatabaseNode) {
deleteObject(activeWorkbenchWindow, (DBNDatabaseNode)element);
} else if (element instanceof DBNResource) {
deleteResource(activeWorkbenchWindow, (DBNResource)element);
} else if (element instanceof DBNLocalFolder) {
deleteLocalFolder(activeWorkbenchWindow, (DBNLocalFolder) element);
} else {
log.warn("Don't know how to delete element '" + element + "'"); //$NON-NLS-1$ //$NON-NLS-2$
}
if (deleteAll != null && !deleteAll) {
break;
}
}
}
if (!tasksToExecute.isEmpty()) {
TasksJob.runTasks(tasksToExecute.size() > 1 ? "Delete " + tasksToExecute.size() + " objects" : "Delete object", tasksToExecute);
tasksToExecute.clear();
}
return null;
}
private void deleteLocalFolder(IWorkbenchWindow workbenchWindow, DBNLocalFolder localFolder)
{
ConfirmResult confirmResult = confirmObjectDelete(workbenchWindow, localFolder, false);
if (confirmResult == ConfirmResult.NO) {
return;
}
localFolder.getDataSourceRegistry().removeFolder(localFolder.getFolder(), false);
DBNModel.updateConfigAndRefreshDatabases(localFolder);
}
private boolean deleteResource(IWorkbenchWindow workbenchWindow, final DBNResource resourceNode)
{
ConfirmResult confirmResult = confirmObjectDelete(workbenchWindow, resourceNode, false);
if (confirmResult == ConfirmResult.NO) {
return false;
}
final IResource resource = resourceNode.getResource();
try {
if (resource instanceof IFolder) {
((IFolder)resource).delete(true, false, new NullProgressMonitor());
} else if (resource instanceof IProject) {
// Delete project (with all contents)
final boolean deleteContent = UIUtils.confirmAction(workbenchWindow.getShell(), "Delete project", "Delete project '" + resource.getName() + "' contents?");
((IProject) resource).delete(deleteContent, true, new NullProgressMonitor());
} else if (resource != null) {
resource.delete(true, new NullProgressMonitor());
}
} catch (CoreException e) {
log.error(e);
return false;
}
return true;
}
private boolean deleteObject(IWorkbenchWindow workbenchWindow, DBNDatabaseNode node)
{
try {
if (!(node.getParentNode() instanceof DBNContainer)) {
throw new DBException("Node '" + node + "' doesn't have a container");
}
final DBNContainer container = (DBNContainer) node.getParentNode();
// Try to delete object using object manager
DBSObject object = node.getObject();
if (object == null) {
throw new DBException("Can't delete node with null object");
}
DBEObjectMaker objectMaker = EntityEditorsRegistry.getInstance().getObjectManager(object.getClass(), DBEObjectMaker.class);
if (objectMaker == null) {
throw new DBException("Object maker not found for type '" + object.getClass().getName() + "'"); //$NON-NLS-2$
}
Map<String, Object> deleteOptions = null;
CommandTarget commandTarget = getCommandTarget(
workbenchWindow,
container,
object.getClass(),
false);
ConfirmResult confirmResult = ConfirmResult.YES;
if (!object.isPersisted() || commandTarget.getEditor() != null) {
// Not a real object delete because it's not persisted
// There should be command context somewhere
if (deleteNewObject(workbenchWindow, node)) {
return true;
}
// No direct editor host found for this object -
// try to find corresponding command context
// and execute command within it
} else {
// Persisted object - confirm delete
// Show "View script" only if we are not in some editor (because it have its own "View script" button)
confirmResult = confirmObjectDelete(workbenchWindow, node, commandTarget.getContext() != null && commandTarget.getEditor() == null );
if (confirmResult == ConfirmResult.NO) {
return false;
}
}
objectMaker.deleteObject(commandTarget.getContext(), node.getObject(), deleteOptions);
if (confirmResult == ConfirmResult.DETAILS) {
if (!showScript(workbenchWindow, commandTarget.getContext(), CoreMessages.actions_navigator_delete_script)) {
commandTarget.getContext().resetChanges();
return false;
}
}
if (commandTarget.getEditor() == null && commandTarget.getContext() != null) {
// Persist object deletion - only if there is no host editor and we have a command context
ObjectSaver deleter = new ObjectSaver(commandTarget.getContext());
// DBeaverUI.runInProgressDialog(deleter);
tasksToExecute.add(deleter);
}
} catch (Throwable e) {
UIUtils.showErrorDialog(workbenchWindow.getShell(), CoreMessages.actions_navigator_error_dialog_delete_object_title, "Can't delete object '" + node.getNodeName() + "'", e);
return false;
}
return true;
}
private boolean deleteNewObject(IWorkbenchWindow workbenchWindow, DBNDatabaseNode node) throws DBException
{
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() == node.getObject()) {
ConfirmResult confirmResult = confirmObjectDelete(workbenchWindow, node, false);
if (confirmResult == ConfirmResult.NO) {
return true;
}
// Just close editor
// It should dismiss new object and remove navigator node
workbenchWindow.getActivePage().closeEditor(editor, false);
return true;
}
}
}
return false;
}
enum ConfirmResult {
YES,
NO,
DETAILS,
}
private ConfirmResult confirmObjectDelete(final IWorkbenchWindow workbenchWindow, final DBNNode node, final boolean viewScript)
{
if (deleteAll != null) {
return deleteAll ? ConfirmResult.YES : ConfirmResult.NO;
}
ResourceBundle bundle = DBeaverActivator.getCoreResourceBundle();
String objectType = node instanceof DBNLocalFolder ? DBeaverPreferences.CONFIRM_LOCAL_FOLDER_DELETE : DBeaverPreferences.CONFIRM_ENTITY_DELETE;
String titleKey = ConfirmationDialog.RES_CONFIRM_PREFIX + objectType + "_" + ConfirmationDialog.RES_KEY_TITLE; //$NON-NLS-1$
String messageKey = ConfirmationDialog.RES_CONFIRM_PREFIX + objectType + "_" + ConfirmationDialog.RES_KEY_MESSAGE; //$NON-NLS-1$
String nodeTypeName = node.getNodeType();
MessageDialog dialog = new MessageDialog(
workbenchWindow.getShell(),
UIUtils.formatMessage(bundle.getString(titleKey), nodeTypeName, node.getNodeName()),
DBeaverIcons.getImage(UIIcon.REJECT),
UIUtils.formatMessage(bundle.getString(messageKey), nodeTypeName.toLowerCase(), node.getNodeName()),
MessageDialog.CONFIRM, null, 0)
{
@Override
protected void createButtonsForButtonBar(Composite parent)
{
createButton(parent, IDialogConstants.YES_ID, IDialogConstants.YES_LABEL, true);
createButton(parent, IDialogConstants.NO_ID, IDialogConstants.NO_LABEL, false);
if (structSelection.size() > 1) {
createButton(parent, IDialogConstants.YES_TO_ALL_ID, IDialogConstants.YES_TO_ALL_LABEL, false);
createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
}
if (viewScript) {
createButton(parent, IDialogConstants.DETAILS_ID, CoreMessages.actions_navigator_view_script_button, false);
}
}
};
int result = dialog.open();
switch (result) {
case IDialogConstants.YES_ID:
return ConfirmResult.YES;
case IDialogConstants.YES_TO_ALL_ID:
deleteAll = true;
return ConfirmResult.YES;
case IDialogConstants.NO_ID:
return ConfirmResult.NO;
case IDialogConstants.CANCEL_ID:
case -1:
deleteAll = false;
return ConfirmResult.NO;
case IDialogConstants.DETAILS_ID:
return ConfirmResult.DETAILS;
default:
log.warn("Unsupported confirmation dialog result: " + result); //$NON-NLS-1$
return ConfirmResult.NO;
}
}
@Override
public void updateElement(UIElement element, Map parameters)
{
if (!updateUI) {
return;
}
/*
final ISelectionProvider selectionProvider = UIUtils.getSelectionProvider(element.getServiceLocator());
if (selectionProvider != null) {
ISelection selection = selectionProvider.getSelection();
if (selection instanceof IStructuredSelection && ((IStructuredSelection) selection).size() > 1) {
element.setText(CoreMessages.actions_navigator_delete_objects);
} else {
DBNNode node = NavigatorUtils.getSelectedNode(selection);
if (node != null) {
element.setText(CoreMessages.actions_navigator_delete_ + " " + node.getNodeType() + " '" + node.getNodeName() + "'");
}
}
}
*/
}
}