/*
* 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.resultset;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.text.IFindReplaceTarget;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.texteditor.FindReplaceAction;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.DBeaverPreferences;
import org.jkiss.dbeaver.core.CoreCommands;
import org.jkiss.dbeaver.core.CoreMessages;
import org.jkiss.dbeaver.core.DBeaverActivator;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.data.DBDAttributeBinding;
import org.jkiss.dbeaver.model.data.DBDDisplayFormat;
import org.jkiss.dbeaver.model.edit.DBEPersistAction;
import org.jkiss.dbeaver.model.runtime.AbstractJob;
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.ui.UIIcon;
import org.jkiss.dbeaver.ui.UIUtils;
import org.jkiss.dbeaver.ui.data.IValueController;
import org.jkiss.dbeaver.ui.data.managers.BaseValueManager;
import org.jkiss.dbeaver.ui.dialogs.sql.ViewSQLDialog;
import org.jkiss.dbeaver.ui.editors.MultiPageAbstractEditor;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.utils.CommonUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* ResultSetCommandHandler
*/
public class ResultSetCommandHandler extends AbstractHandler {
public static final String CMD_TOGGLE_PANELS = "org.jkiss.dbeaver.core.resultset.grid.togglePreview";
public static final String CMD_TOGGLE_MODE = "org.jkiss.dbeaver.core.resultset.toggleMode";
public static final String CMD_FOCUS_FILTER = "org.jkiss.dbeaver.core.resultset.focus.filter";
public static final String CMD_SWITCH_PRESENTATION = "org.jkiss.dbeaver.core.resultset.switchPresentation";
public static final String CMD_ROW_FIRST = "org.jkiss.dbeaver.core.resultset.row.first";
public static final String CMD_ROW_PREVIOUS = "org.jkiss.dbeaver.core.resultset.row.previous";
public static final String CMD_ROW_NEXT = "org.jkiss.dbeaver.core.resultset.row.next";
public static final String CMD_ROW_LAST = "org.jkiss.dbeaver.core.resultset.row.last";
public static final String CMD_FETCH_PAGE = "org.jkiss.dbeaver.core.resultset.fetch.page";
public static final String CMD_FETCH_ALL = "org.jkiss.dbeaver.core.resultset.fetch.all";
public static final String CMD_COUNT = "org.jkiss.dbeaver.core.resultset.count";
public static final String CMD_ROW_EDIT = "org.jkiss.dbeaver.core.resultset.row.edit";
public static final String CMD_ROW_EDIT_INLINE = "org.jkiss.dbeaver.core.resultset.row.edit.inline";
public static final String CMD_ROW_ADD = "org.jkiss.dbeaver.core.resultset.row.add";
public static final String CMD_ROW_COPY = "org.jkiss.dbeaver.core.resultset.row.copy";
public static final String CMD_ROW_DELETE = "org.jkiss.dbeaver.core.resultset.row.delete";
public static final String CMD_CELL_SET_NULL = "org.jkiss.dbeaver.core.resultset.cell.setNull";
public static final String CMD_CELL_RESET = "org.jkiss.dbeaver.core.resultset.cell.reset";
public static final String CMD_APPLY_CHANGES = "org.jkiss.dbeaver.core.resultset.applyChanges";
public static final String CMD_REJECT_CHANGES = "org.jkiss.dbeaver.core.resultset.rejectChanges";
public static final String CMD_GENERATE_SCRIPT = "org.jkiss.dbeaver.core.resultset.generateScript";
public static final String CMD_NAVIGATE_LINK = "org.jkiss.dbeaver.core.resultset.navigateLink";
public static final String CMD_FILTER_MENU = "org.jkiss.dbeaver.core.resultset.filterMenu";
public static final String CMD_COPY_COLUMN_NAMES = "org.jkiss.dbeaver.core.resultset.grid.copyColumnNames";
public static final String CMD_COPY_ROW_NAMES = "org.jkiss.dbeaver.core.resultset.grid.copyRowNames";
public static IResultSetController getActiveResultSet(IWorkbenchPart activePart) {
if (activePart instanceof IResultSetContainer) {
return ((IResultSetContainer) activePart).getResultSetController();
} else if (activePart instanceof MultiPageAbstractEditor) {
return getActiveResultSet(((MultiPageAbstractEditor) activePart).getActiveEditor());
} else if (activePart != null) {
return activePart.getAdapter(ResultSetViewer.class);
} else {
return null;
}
}
@Nullable
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
final ResultSetViewer rsv = (ResultSetViewer) getActiveResultSet(HandlerUtil.getActivePart(event));
if (rsv == null) {
return null;
}
String actionId = event.getCommand().getId();
IResultSetPresentation presentation = rsv.getActivePresentation();
switch (actionId) {
case IWorkbenchCommandConstants.FILE_REFRESH:
rsv.refreshData(null);
break;
case CMD_TOGGLE_MODE:
rsv.toggleMode();
break;
case CMD_TOGGLE_PANELS:
rsv.showPanels(!rsv.isPanelsVisible());
break;
case CMD_FOCUS_FILTER:
rsv.switchFilterFocus();
break;
case CMD_SWITCH_PRESENTATION:
rsv.switchPresentation();
break;
case CMD_ROW_PREVIOUS:
case ITextEditorActionDefinitionIds.WORD_PREVIOUS:
presentation.scrollToRow(IResultSetPresentation.RowPosition.PREVIOUS);
break;
case CMD_ROW_NEXT:
case ITextEditorActionDefinitionIds.WORD_NEXT:
presentation.scrollToRow(IResultSetPresentation.RowPosition.NEXT);
break;
case CMD_ROW_FIRST:
case ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS:
presentation.scrollToRow(IResultSetPresentation.RowPosition.FIRST);
break;
case CMD_ROW_LAST:
case ITextEditorActionDefinitionIds.SELECT_WORD_NEXT:
presentation.scrollToRow(IResultSetPresentation.RowPosition.LAST);
break;
case CMD_FETCH_PAGE:
rsv.readNextSegment();
break;
case CMD_FETCH_ALL:
rsv.readAllData();
break;
case CMD_ROW_EDIT:
if (presentation instanceof IResultSetEditor) {
((IResultSetEditor) presentation).openValueEditor(false);
}
break;
case CMD_ROW_EDIT_INLINE:
if (presentation instanceof IResultSetEditor) {
((IResultSetEditor) presentation).openValueEditor(true);
}
break;
case CMD_ROW_ADD:
case CMD_ROW_COPY:
boolean copy = actionId.equals(CMD_ROW_COPY);
boolean shiftPressed = event.getTrigger() instanceof Event && ((((Event)event.getTrigger()).stateMask & SWT.SHIFT) == SWT.SHIFT);
boolean insertAfter = rsv.getPreferenceStore().getBoolean(DBeaverPreferences.RS_EDIT_NEW_ROWS_AFTER);
if (shiftPressed) insertAfter = !insertAfter;
rsv.addNewRow(copy, insertAfter);
break;
case CMD_ROW_DELETE:
case IWorkbenchCommandConstants.EDIT_DELETE:
rsv.deleteSelectedRows();
break;
case CMD_CELL_SET_NULL:
case CMD_CELL_RESET: {
IResultSetSelection selection = rsv.getSelection();
for (Object cell : selection.toArray()) {
DBDAttributeBinding attr = selection.getElementAttribute(cell);
ResultSetRow row = selection.getElementRow(cell);
if (row != null && attr != null) {
ResultSetValueController valueController = new ResultSetValueController(
rsv,
attr,
row,
IValueController.EditType.NONE,
null);
if (actionId.equals(CMD_CELL_SET_NULL)) {
valueController.updateValue(
BaseValueManager.makeNullValue(valueController), false);
} else {
rsv.getModel().resetCellValue(attr, row);
}
}
}
rsv.redrawData(false, false);
rsv.updatePanelsContent(false);
break;
}
case CMD_APPLY_CHANGES:
rsv.applyChanges(null);
break;
case CMD_REJECT_CHANGES:
rsv.rejectChanges();
break;
case CMD_GENERATE_SCRIPT: {
try {
final List<DBEPersistAction> sqlScript = new ArrayList<>();
try {
DBeaverUI.runInProgressService(new DBRRunnableWithProgress() {
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
List<DBEPersistAction> script = rsv.generateChangesScript(monitor);
if (script != null) {
sqlScript.addAll(script);
}
}
});
} catch (InterruptedException e) {
// ignore
}
if (!sqlScript.isEmpty()) {
String scriptText = SQLUtils.generateScript(
rsv.getDataContainer() == null ? null : rsv.getDataContainer().getDataSource(),
sqlScript.toArray(new DBEPersistAction[sqlScript.size()]),
false);
scriptText =
SQLUtils.generateCommentLine(
rsv.getExecutionContext() == null ? null : rsv.getExecutionContext().getDataSource(),
"Actual parameter values may differ, what you see is a default string representation of values") +
scriptText;
ViewSQLDialog dialog = new ViewSQLDialog(
HandlerUtil.getActivePart(event).getSite(),
rsv.getExecutionContext(),
CoreMessages.editors_entity_dialog_preview_title,
UIIcon.SQL_PREVIEW,
scriptText);
dialog.open();
}
} catch (InvocationTargetException e) {
UIUtils.showErrorDialog(HandlerUtil.getActiveShell(event), "Script generation", "Can't generate changes script", e.getTargetException());
}
break;
}
case CMD_COPY_COLUMN_NAMES: {
StringBuilder buffer = new StringBuilder();
IResultSetSelection selection = rsv.getSelection();
Collection<DBDAttributeBinding> attrs = selection.isEmpty() ? rsv.getModel().getVisibleAttributes() : selection.getSelectedAttributes();
for (DBDAttributeBinding attr : attrs) {
if (buffer.length() > 0) {
buffer.append("\t");
}
String colName = attr.getLabel();
if (CommonUtils.isEmpty(colName)) {
colName = attr.getName();
}
buffer.append(colName);
}
ResultSetUtils.copyToClipboard(buffer.toString());
break;
}
case CMD_COPY_ROW_NAMES: {
StringBuilder buffer = new StringBuilder();
IResultSetSelection selection = rsv.getSelection();
for (ResultSetRow row : ((IResultSetSelection)selection).getSelectedRows()) {
if (buffer.length() > 0) {
buffer.append("\n");
}
buffer.append(row.getVisualNumber() + 1);
}
ResultSetUtils.copyToClipboard(buffer.toString());
break;
}
case IWorkbenchCommandConstants.EDIT_COPY:
ResultSetUtils.copyToClipboard(
presentation.copySelectionToString(
new ResultSetCopySettings(false, false, false, true, null, null, DBDDisplayFormat.EDIT)));
break;
case IWorkbenchCommandConstants.EDIT_PASTE:
case CoreCommands.CMD_PASTE_SPECIAL:
if (presentation instanceof IResultSetEditor) {
((IResultSetEditor) presentation).pasteFromClipboard(actionId.equals(CoreCommands.CMD_PASTE_SPECIAL));
}
break;
case IWorkbenchCommandConstants.EDIT_CUT:
ResultSetUtils.copyToClipboard(
presentation.copySelectionToString(
new ResultSetCopySettings(false, false, true, true, null, null, DBDDisplayFormat.EDIT))
);
break;
case IWorkbenchCommandConstants.FILE_PRINT:
presentation.printResultSet();
break;
case ITextEditorActionDefinitionIds.SMART_ENTER:
if (presentation instanceof IResultSetEditor) {
((IResultSetEditor) presentation).openValueEditor(false);
}
break;
case IWorkbenchCommandConstants.EDIT_FIND_AND_REPLACE:
FindReplaceAction action = new FindReplaceAction(
DBeaverActivator.getCoreResourceBundle(),
"Editor.FindReplace.",
HandlerUtil.getActiveShell(event),
rsv.getAdapter(IFindReplaceTarget.class));
action.run();
break;
case CMD_NAVIGATE_LINK:
final ResultSetRow row = rsv.getCurrentRow();
final DBDAttributeBinding attr = rsv.getActivePresentation().getCurrentAttribute();
if (row != null && attr != null) {
new AbstractJob("Navigate association") {
@Override
protected IStatus run(DBRProgressMonitor monitor) {
try {
rsv.navigateAssociation(monitor, attr, row, false);
} catch (DBException e) {
return GeneralUtils.makeExceptionStatus(e);
}
return Status.OK_STATUS;
}
}.schedule();
}
break;
case CMD_COUNT:
rsv.updateRowCount();
break;
case IWorkbenchCommandConstants.NAVIGATE_BACKWARD_HISTORY: {
final int hp = rsv.getHistoryPosition();
if (hp > 0) {
rsv.navigateHistory(hp - 1);
}
break;
}
case IWorkbenchCommandConstants.NAVIGATE_FORWARD_HISTORY: {
final int hp = rsv.getHistoryPosition();
if (hp < rsv.getHistorySize() - 1) {
rsv.navigateHistory(hp + 1);
}
break;
}
case ITextEditorActionDefinitionIds.LINE_GOTO: {
ResultSetRow currentRow = rsv.getCurrentRow();
final int rowCount = rsv.getModel().getRowCount();
if (rowCount <= 0) {
break;
}
GotoLineDialog d = new GotoLineDialog(
HandlerUtil.getActiveShell(event),
"Go to Row",
"Enter row number (1.." + rowCount + ")",
String.valueOf(currentRow == null ? 1 : currentRow.getVisualNumber() + 1),
new IInputValidator() {
@Override
public String isValid(String input) {
try {
int i = Integer.parseInt(input);
if (i <= 0 || rowCount < i) {
return "Row number is out of range";
}
} catch (NumberFormatException x) {
return "Not a number";
}
return null;
}
});
if (d.open() == Window.OK) {
int line = Integer.parseInt(d.getValue());
rsv.setCurrentRow(rsv.getModel().getRow(line - 1));
rsv.getActivePresentation().scrollToRow(IResultSetPresentation.RowPosition.CURRENT);
}
break;
}
case CMD_FILTER_MENU: {
rsv.showFiltersMenu();
break;
}
}
return null;
}
static class GotoLineDialog extends InputDialog {
private static final String DIALOG_ID = "ResultSetCommandHandler.GotoLineDialog";
public GotoLineDialog(Shell parent, String title, String message, String initialValue, IInputValidator validator) {
super(parent, title, message, initialValue, validator);
}
protected IDialogSettings getDialogBoundsSettings() {
return UIUtils.getDialogSettings(DIALOG_ID);
}
}
}