/*
* 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.editors.text;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IUndoManager;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ST;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.DBRRunnableWithProgress;
import org.jkiss.dbeaver.ui.ICommentsSupport;
import org.jkiss.dbeaver.ui.ISingleControlEditor;
import org.jkiss.dbeaver.ui.UIUtils;
import org.jkiss.dbeaver.ui.dialogs.DialogUtils;
import org.jkiss.dbeaver.ui.editors.EditorUtils;
import org.jkiss.dbeaver.ui.editors.INonPersistentEditorInput;
import org.jkiss.dbeaver.ui.editors.SubEditorSite;
import org.jkiss.dbeaver.ui.editors.content.ContentEditorInput;
import org.jkiss.dbeaver.utils.ContentUtils;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.utils.IOUtils;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
/**
* Abstract text editor.
* Contains some common dbeaver text editor adaptions.
*/
public abstract class BaseTextEditor extends AbstractDecoratedTextEditor implements ISingleControlEditor {
public static final String TEXT_EDITOR_CONTEXT = "org.eclipse.ui.textEditorScope";
public static final String GROUP_SQL_PREFERENCES = "sql.preferences";
public static final String GROUP_SQL_ADDITIONS = "sql.additions";
public static final String GROUP_SQL_EXTRAS = "sql.extras";
private static Map<String, Integer> ACTION_TRANSLATE_MAP;
public static Map<String, Integer> getActionMap()
{
if (ACTION_TRANSLATE_MAP == null) {
ACTION_TRANSLATE_MAP = new HashMap<>();
for (IdMapEntry entry : ACTION_MAP) {
ACTION_TRANSLATE_MAP.put(entry.getActionId(), entry.getAction());
}
}
return ACTION_TRANSLATE_MAP;
}
public static BaseTextEditor getTextEditor(IEditorPart editor)
{
if (editor == null) {
return null;
}
if (editor instanceof BaseTextEditor) {
return (BaseTextEditor) editor;
}
return editor.getAdapter(BaseTextEditor.class);
}
// protected ScriptPositionColumn getScriptColumn()
// {
// return fScriptColumn;
// }
@Override
protected void doSetInput(IEditorInput input) throws CoreException {
if (input != getEditorInput()) {
releaseEditorInput();
}
super.doSetInput(input);
}
@Override
public void dispose()
{
releaseEditorInput();
// fLineColumn = null;
super.dispose();
}
public void releaseEditorInput() {
IEditorInput editorInput = getEditorInput();
if (editorInput instanceof ContentEditorInput) {
((ContentEditorInput) editorInput).release();
}
}
@Nullable
public Document getDocument()
{
IDocumentProvider provider = getDocumentProvider();
return provider == null ? null : (Document)provider.getDocument(getEditorInput());
}
@Nullable
@Override
public StyledText getEditorControl() {
final TextViewer textViewer = getTextViewer();
return textViewer == null ? null : textViewer.getTextWidget();
}
@Override
public void createPartControl(Composite parent)
{
//setPreferenceStore(new PreferenceStoreDelegate(DBeaverCore.getGlobalPreferenceStore()));
super.createPartControl(parent);
if (getSite() instanceof SubEditorSite) {
// SWT.DEL shortcut is disabled in AbstractTextEditor.createNavigationActions
// Dunno why (there is a weird explanations about bug closed in 2004)
// but it blocks DEL button in nested editors
getTextViewer().getTextWidget().setKeyBinding(SWT.DEL, ST.DELETE_NEXT);
// Disable parent text editor key-bindings
// This works when text editor is embedded in another text editor (e.g. SQL editor)
// Commented because in fact this doesn't work. Owner editor still hooks/suppresses all extra commands
//UIUtils.enableHostEditorKeyBindingsSupport(((SubEditorSite) getSite()).getParentSite(), getTextViewer().getTextWidget());
}
}
@Override
protected void editorContextMenuAboutToShow(IMenuManager menu)
{
//super.editorContextMenuAboutToShow(menu);
menu.add(new Separator(ITextEditorActionConstants.GROUP_UNDO));
menu.add(new GroupMarker(ITextEditorActionConstants.GROUP_SAVE));
menu.add(new Separator(ITextEditorActionConstants.GROUP_COPY));
menu.add(new Separator(ITextEditorActionConstants.GROUP_PRINT));
menu.add(new Separator(ITextEditorActionConstants.GROUP_EDIT));
menu.add(new Separator(ITextEditorActionConstants.GROUP_FIND));
menu.add(new Separator(IWorkbenchActionConstants.GROUP_ADD));
menu.add(new Separator(ITextEditorActionConstants.GROUP_REST));
menu.add(new Separator());
menu.add(new GroupMarker(GROUP_SQL_ADDITIONS));
menu.add(new GroupMarker(GROUP_SQL_EXTRAS));
menu.add(new Separator());
menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
menu.add(new Separator());
menu.add(new GroupMarker(GROUP_SQL_PREFERENCES));
if (isEditable()) {
addAction(menu, ITextEditorActionConstants.GROUP_UNDO, ITextEditorActionConstants.UNDO);
addAction(menu, ITextEditorActionConstants.GROUP_SAVE, ITextEditorActionConstants.SAVE);
addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.CUT);
addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.COPY);
addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.PASTE);
IAction action= getAction(ITextEditorActionConstants.QUICK_ASSIST);
if (action != null && action.isEnabled()) {
addAction(menu, ITextEditorActionConstants.GROUP_EDIT, ITextEditorActionConstants.QUICK_ASSIST);
}
} else {
addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.COPY);
}
IAction preferencesAction = getAction(ITextEditorActionConstants.CONTEXT_PREFERENCES);
if (preferencesAction != null) {
menu.appendToGroup(GROUP_SQL_PREFERENCES, preferencesAction);
}
}
@Nullable
public TextViewer getTextViewer()
{
return (TextViewer) getSourceViewer();
}
@Nullable
public SourceViewer getViewer()
{
return (SourceViewer) super.getSourceViewer();
}
public void enableUndoManager(boolean enable)
{
TextViewer textViewer = getTextViewer();
final IUndoManager undoManager = textViewer.getUndoManager();
if (undoManager != null) {
if (!enable) {
undoManager.disconnect();
} else {
undoManager.connect(textViewer);
}
}
}
public void handleActivate()
{
safelySanityCheckState(getEditorInput());
}
@Nullable
public ICommentsSupport getCommentsSupport()
{
return null;
}
protected boolean isReadOnly()
{
return false;
}
public void loadFromExternalFile()
{
final File loadFile = DialogUtils.openFile(getSite().getShell(), new String[]{"*.sql", "*.txt", "*", "*.*"});
if (loadFile == null) {
return;
}
String newContent = null;
try {
try (Reader reader = new InputStreamReader(
new FileInputStream(loadFile),
GeneralUtils.DEFAULT_FILE_CHARSET))
{
StringWriter buffer = new StringWriter();
IOUtils.copyText(reader, buffer);
newContent = buffer.toString();
}
}
catch (IOException e) {
UIUtils.showErrorDialog(
getSite().getShell(),
"Can't load file",
"Can't load file '" + loadFile.getAbsolutePath() + "' - " + e.getMessage());
}
if (newContent != null) {
Document document = getDocument();
if (document != null) {
document.set(newContent);
}
}
}
public void saveToExternalFile()
{
IEditorInput editorInput = getEditorInput();
IFile curFile = EditorUtils.getFileFromInput(editorInput);
String fileName = curFile == null ? null : curFile.getName();
final Document document = getDocument();
final File saveFile = DialogUtils.selectFileForSave(getSite().getShell(), "Save SQL script", new String[]{"*.sql", "*.txt", "*", "*.*"}, fileName);
if (document == null || saveFile == null) {
return;
}
try {
DBeaverUI.runInProgressService(new DBRRunnableWithProgress() {
@Override
public void run(final DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException
{
try {
StringReader cr = new StringReader(document.get());
ContentUtils.saveContentToFile(cr, saveFile, GeneralUtils.UTF8_ENCODING, monitor);
} catch (Exception e) {
throw new InvocationTargetException(e);
}
}
});
} catch (InterruptedException e) {
// do nothing
} catch (InvocationTargetException e) {
UIUtils.showErrorDialog(getSite().getShell(), "Save failed", null, e.getTargetException());
}
afterSaveToFile(saveFile);
}
protected void afterSaveToFile(File saveFile) {
}
@Nullable
public int[] getCurrentLines()
{
return null;
}
protected boolean isNonPersistentEditor() {
return getEditorInput() instanceof INonPersistentEditorInput;
}
}