/* * 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.sql; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IContributionManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.text.*; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.PartInitException; import org.eclipse.ui.part.MultiPageEditorSite; import org.eclipse.ui.texteditor.IDocumentProvider; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.core.CoreCommands; import org.jkiss.dbeaver.core.DBeaverUI; import org.jkiss.dbeaver.model.exec.DBCExecutionContext; import org.jkiss.dbeaver.model.exec.compile.DBCCompileLog; import org.jkiss.dbeaver.model.exec.compile.DBCSourceHost; 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.runtime.TasksJob; import org.jkiss.dbeaver.ui.*; import org.jkiss.dbeaver.ui.controls.ObjectCompilerLogViewer; import org.jkiss.dbeaver.ui.controls.ProgressPageControl; import org.jkiss.dbeaver.ui.controls.folders.ITabbedFolderEditorSite; import org.jkiss.dbeaver.ui.editors.IDatabaseEditorInput; import org.jkiss.dbeaver.ui.editors.entity.EntityEditor; import org.jkiss.dbeaver.ui.editors.text.BaseTextDocumentProvider; import org.jkiss.dbeaver.utils.RuntimeUtils; import java.lang.reflect.InvocationTargetException; /** * SQLEditorNested */ public abstract class SQLEditorNested<T extends DBSObject> extends SQLEditorBase implements IActiveWorkbenchPart, IRefreshablePart, DBCSourceHost { private EditorPageControl pageControl; private ObjectCompilerLogViewer compileLog; private Control editorControl; private SashForm editorSash; public SQLEditorNested() { super(); setDocumentProvider(new ObjectDocumentProvider()); //setHasVerticalRuler(false); } @Override public IDatabaseEditorInput getEditorInput() { return (IDatabaseEditorInput)super.getEditorInput(); } @Override public T getSourceObject() { IDatabaseEditorInput editorInput = getEditorInput(); if (editorInput == null) { return null; } return (T) editorInput.getDatabaseObject(); } @Override public DBCExecutionContext getExecutionContext() { IDatabaseEditorInput editorInput = getEditorInput(); if (editorInput == null) { return null; } return editorInput.getExecutionContext(); } @Override public void createPartControl(Composite parent) { pageControl = new EditorPageControl(parent, SWT.SHEET); boolean hasCompiler = getCompileCommandId() != null; if (hasCompiler) { editorSash = new SashForm(pageControl.createContentContainer(), SWT.VERTICAL | SWT.SMOOTH); super.createPartControl(editorSash); editorControl = editorSash.getChildren()[0]; compileLog = new ObjectCompilerLogViewer(editorSash, false); } else { super.createPartControl(pageControl.createContentContainer()); } // Create new or substitute progress control pageControl.createOrSubstituteProgressPanel(getSite()); pageControl.setInfo("Source"); if (hasCompiler) { editorSash.setWeights(new int[]{70, 30}); editorSash.setMaximizedControl(editorControl); } // Use focus to activate page control final Control editorControl = getEditorControl(); assert editorControl != null; editorControl.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { if (pageControl != null && !pageControl.isDisposed()) { pageControl.activate(true); } } @Override public void focusLost(FocusEvent e) { if (pageControl != null && !pageControl.isDisposed()) { pageControl.activate(false); } } }); } @Override public void doSave(final IProgressMonitor progressMonitor) { DBeaverUI.syncExec(new Runnable() { @Override public void run() { SQLEditorNested.super.doSave(progressMonitor); } }); } @Override public void activatePart() { } @Override public void deactivatePart() { } @Override public void refreshPart(Object source, boolean force) { // Check if we are in saving process // If so then no refresh needed (source text was updated during save) IEditorSite editorSite = getEditorSite(); if (editorSite instanceof MultiPageEditorSite && ((MultiPageEditorSite) editorSite).getMultiPageEditor() instanceof EntityEditor && ((EntityEditor) ((MultiPageEditorSite) editorSite).getMultiPageEditor()).isSaveInProgress()) { return; } final IDocumentProvider documentProvider = getDocumentProvider(); if (documentProvider instanceof SQLEditorNested.ObjectDocumentProvider) { ((SQLEditorNested.ObjectDocumentProvider) documentProvider).sourceText = null; } if (force) { try { super.init(editorSite, getEditorInput()); //setFocus(); } catch (PartInitException e) { log.error(e); } } } protected String getCompileCommandId() { return null; } public boolean isDocumentLoaded() { final IDocumentProvider documentProvider = getDocumentProvider(); if (documentProvider instanceof SQLEditorNested.ObjectDocumentProvider) { return ((SQLEditorNested.ObjectDocumentProvider) documentProvider).sourceLoaded; } return true; } private class ObjectDocumentProvider extends BaseTextDocumentProvider { private String sourceText; private boolean sourceLoaded; @Override public boolean isReadOnly(Object element) { return SQLEditorNested.this.isReadOnly(); } @Override public boolean isModifiable(Object element) { return !SQLEditorNested.this.isReadOnly(); } @Override protected IDocument createDocument(Object element) throws CoreException { final Document document = new Document(); if (sourceText == null) { document.set(SQLUtils.generateCommentLine(getDataSource(), "Loading '" + getEditorInput().getName() + "' source...")); TasksJob.runTask("Read source", new DBRRunnableWithProgress() { @Override public void run(final DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { sourceText = getSourceText(monitor); if (sourceText == null) { sourceText = SQLUtils.generateCommentLine(getDataSource(), "Empty source"); } } catch (Throwable e) { sourceText = "/* ERROR WHILE READING SOURCE:\n\n" + e.getMessage() + "\n*/"; throw new InvocationTargetException(e); } finally { if (!isDisposed()) { DBeaverUI.syncExec(new Runnable() { @Override public void run() { resetDocumentContents(monitor); } }); } } } }); } else { // Set text document.set(sourceText); sourceLoaded = true; } return document; } private void resetDocumentContents(DBRProgressMonitor monitor) { try { doResetDocument(getEditorInput(), RuntimeUtils.getNestedMonitor(monitor)); // Reset undo queue if (getSourceViewer() instanceof ITextViewerExtension6) { ((ITextViewerExtension6) getSourceViewer()).getUndoManager().reset(); } // Load syntax reloadSyntaxRules(); } catch (CoreException e) { log.error(e); } } @Override protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException { setSourceText(RuntimeUtils.makeMonitor(monitor), document.get()); } } @Override public DBCCompileLog getCompileLog() { return compileLog; } @Override public void setCompileInfo(String message, boolean error) { pageControl.setInfo(message); } @Override public void positionSource(int line, int position) { try { final IRegion lineInfo = getTextViewer().getDocument().getLineInformation(line - 1); final int offset = lineInfo.getOffset() + position - 1; super.selectAndReveal(offset, 0); //textEditor.setFocus(); } catch (BadLocationException e) { log.warn(e); // do nothing } } @Override public void showCompileLog() { editorSash.setMaximizedControl(null); compileLog.layoutLog(); } protected abstract String getSourceText(DBRProgressMonitor monitor) throws DBException; protected abstract void setSourceText(DBRProgressMonitor monitor, String sourceText); protected void contributeEditorCommands(IContributionManager toolBarManager) { toolBarManager.add(ActionUtils.makeCommandContribution(getSite().getWorkbenchWindow(), CoreCommands.CMD_OPEN_FILE)); toolBarManager.add(ActionUtils.makeCommandContribution(getSite().getWorkbenchWindow(), CoreCommands.CMD_SAVE_FILE)); String compileCommandId = getCompileCommandId(); if (compileCommandId != null) { toolBarManager.add(new Separator()); toolBarManager.add(ActionUtils.makeCommandContribution(getSite().getWorkbenchWindow(), compileCommandId)); toolBarManager.add(new ViewLogAction()); } } @Override public void doSaveAs() { saveToExternalFile(); } private class EditorPageControl extends ProgressPageControl { public EditorPageControl(Composite parent, int style) { super(parent, style); } @Override protected void fillCustomActions(IContributionManager contributionManager) { contributeEditorCommands(contributionManager); } } public class ViewLogAction extends Action { public ViewLogAction() { super("View compile log", DBeaverIcons.getImageDescriptor(UIIcon.COMPILE_LOG)); //$NON-NLS-2$ } @Override public void run() { if (getTextViewer().getControl().isDisposed()) { return; } if (editorSash.getMaximizedControl() == null) { editorSash.setMaximizedControl(editorControl); } else { showCompileLog(); } } } }