/*
* Copyright (C) 2007 SQL Explorer Development Team http://sourceforge.net/projects/eclipsesql
*
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package net.sourceforge.sqlexplorer.plugin.editors;
import net.sourceforge.sqlexplorer.IConstants;
import net.sourceforge.sqlexplorer.dbproduct.Session;
import net.sourceforge.sqlexplorer.plugin.SQLExplorerPlugin;
import net.sourceforge.sqlexplorer.sessiontree.model.utility.Dictionary;
import net.sourceforge.sqlexplorer.sqleditor.SQLTextViewer;
import net.sourceforge.sqlexplorer.sqleditor.actions.ExecSQLAction;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IURIEditorInput;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.talend.core.GlobalServiceRegister;
import org.talend.core.ITDQRepositoryService;
import org.talend.core.model.properties.Item;
/**
* TextEditor specialisation; encapsulates functionality specific to editing SQL.
*
* Virtually all of this code came from SQLEditor, which used to be derived directly from TextEditor; SQLEditor now
* combines the text editor (here, SQLTextEditor) and the result and messages panes in a single editor, hence this was
* separated out for clarity
*
* Note that MouseClickListener was also moved to a top-level, package-private class for readability
*
* @modified John Spackman
*
*/
public class SQLTextEditor extends TextEditor {
static int i = 0;
private SQLEditor editor;
private MouseClickListener mcl;
private IPartListener partListener;
/* package */SQLTextViewer sqlTextViewer;
private boolean _enableContentAssist = SQLExplorerPlugin.getDefault().getPluginPreferences()
.getBoolean(IConstants.SQL_ASSIST);
private IPreferenceStore store;
// ADD xqliu 2010-03-23 feature 10675
private static final String DEFAULT_FILE_EXTENSION = ".sql";
// TODO should use the file version property
private static final String DEFAULT_VERSION_STRING = "_0.1";
public SQLTextEditor(SQLEditor editor) {
super();
this.editor = editor;
mcl = new MouseClickListener(editor);
store = SQLExplorerPlugin.getDefault().getPreferenceStore();
setPreferenceStore(SQLExplorerPlugin.getDefault().getPreferenceStore());
}
@Override
protected boolean isLineNumberRulerVisible() {
return true;
}
@Override
protected boolean isOverviewRulerVisible() {
return true;
}
@Override
protected boolean isPrefQuickDiffAlwaysOn() {
return true;
}
@Override
public boolean isChangeInformationShowing() {
return true;
}
@Override
public IProgressMonitor getProgressMonitor() {
return super.getProgressMonitor();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#performSaveAs(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected void performSaveAs(IProgressMonitor progressMonitor) {
// PTODO qzhang correct save the sql file. for bug 3860.
Shell shell = getSite().getShell();
final IEditorInput input = getEditorInput();
IDocumentProvider provider = getDocumentProvider();
IEditorInput newInput;
if (input instanceof IURIEditorInput && !(input instanceof IFileEditorInput)) {
super.performSaveAs(progressMonitor);
return;
}
ILabelProvider lp = new WorkbenchLabelProvider();
ITreeContentProvider cp = new WorkbenchContentProvider();
FolderSelectionDialog dialog = new FolderSelectionDialog(shell, lp, cp);
if (dialog.open() == Window.CANCEL) {
if (progressMonitor != null) {
progressMonitor.setCanceled(true);
}
return;
}
Object elements = dialog.getResult()[0];
// ADD xqliu 2010-03-08 feature 10675
IResource elem = (IResource) elements;
if (elem instanceof IFolder) {
IPath filePath = ((IFolder) elem).getFullPath();
filePath = filePath.append(dialog.getFileName() + DEFAULT_FILE_EXTENSION);
if (filePath == null) {
if (progressMonitor != null) {
progressMonitor.setCanceled(true);
}
return;
}
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IFile file = workspace.getRoot().getFile(filePath);
newInput = new FileEditorInput(file);
if (provider == null) {
// editor has programmatically been closed while the dialog was open
return;
}
boolean success = false;
try {
provider.aboutToChange(newInput);
// MOD qiongli 2011-4-21 bug 20205.after creating property file,file name is changed(contain version
// info),so reset'newInput'.
file = createIFile(file, getViewer().getDocument().get());
newInput = new FileEditorInput(file);
success = true;
} catch (CoreException x) {
final IStatus status = x.getStatus();
if (status == null || status.getSeverity() != IStatus.CANCEL) {
String title = "The file save failure.";
String msg = "The file save failure.";
MessageDialog.openError(shell, title, msg);
}
} finally {
provider.changed(newInput);
if (success) {
setInput(newInput);
}
}
if (progressMonitor != null) {
progressMonitor.setCanceled(!success);
}
}
}
/**
* DOC qzhang Comment method "createIFile".
*
* @param monitor
* @param file
* @param content
* @throws CoreException
*/
private IFile createIFile(IFile file, String content) throws CoreException {
// MOD qiongli 2011-4-21.bug 20205 .should create sql file and property.use extension of service mechanism.
if (GlobalServiceRegister.getDefault().isServiceRegistered(ITDQRepositoryService.class)) {
ITDQRepositoryService service = (ITDQRepositoryService) GlobalServiceRegister.getDefault().getService(
ITDQRepositoryService.class);
if (service != null) {
String fName = StringUtils.removeEnd(StringUtils.removeEnd(file.getName(), DEFAULT_FILE_EXTENSION),
DEFAULT_VERSION_STRING);
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IPath rootPath = new Path("TDQ_Libraries/Source Files");
Item item = service.createFile(content,
file.getProjectRelativePath().removeLastSegments(1).makeRelativeTo(rootPath), fName,
file.getFileExtension());
// get the correct path(contain version info) for newInput file in editor.
IPath location = file.getLocation();
if (item != null && item.getProperty() != null && location != null) {
location = location.removeLastSegments(1);
StringBuffer strb = new StringBuffer();
strb.append(location.toString());
String version = item.getProperty().getVersion() == null ? "" : "_" + item.getProperty().getVersion();
strb.append(Path.SEPARATOR).append(fName).append(version).append(DEFAULT_FILE_EXTENSION);
location = Path.fromOSString(strb.toString());
file = workspace.getRoot().getFileForLocation(location);
}
}
}
return file;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.texteditor.AbstractTextEditor#createActions()
*/
@Override
protected void createActions() {
super.createActions();
if (!_enableContentAssist) {
return;
}
Action action = new Action("Auto-Completion") {
@Override
public void run() {
sqlTextViewer.showAssistance();
}
};
// This action definition is associated with the accelerator Ctrl+Space
action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
setAction("ContentAssistProposal", action);
}
@Override
public void createPartControl(Composite parent) {
super.createPartControl(parent);
PlatformUI.getWorkbench().getHelpSystem()
.setHelp(getSourceViewer().getTextWidget(), SQLExplorerPlugin.PLUGIN_ID + ".SQLEditor");
Object adapter = getAdapter(org.eclipse.swt.widgets.Control.class);
if (adapter instanceof StyledText) {
StyledText text = (StyledText) adapter;
text.setWordWrap(SQLExplorerPlugin.getDefault().getPluginPreferences().getBoolean(IConstants.WORD_WRAP));
FontData[] fData = PreferenceConverter.getFontDataArray(store, IConstants.FONT);
if (fData.length > 0) {
JFaceResources.getFontRegistry().put(fData[0].toString(), fData);
text.setFont(JFaceResources.getFontRegistry().get(fData[0].toString()));
}
}
}
@Override
protected ISourceViewer createSourceViewer(final Composite parent, IVerticalRuler ruler, int style) {
parent.setLayout(new FillLayout());
final Composite myParent = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = layout.marginWidth = layout.horizontalSpacing = layout.verticalSpacing = 0;
myParent.setLayout(layout);
// create divider line
Composite div1 = new Composite(myParent, SWT.NONE);
GridData lgid = new GridData();
lgid.grabExcessHorizontalSpace = true;
lgid.horizontalAlignment = GridData.FILL;
lgid.heightHint = 1;
lgid.verticalIndent = 1;
div1.setLayoutData(lgid);
div1.setBackground(editor.getSite().getShell().getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
// create text viewer
GridData gid = new GridData();
gid.grabExcessHorizontalSpace = gid.grabExcessVerticalSpace = true;
gid.horizontalAlignment = gid.verticalAlignment = GridData.FILL;
Dictionary dictionary = null;
if (editor.getSession() != null && _enableContentAssist) {
dictionary = editor.getSession().getUser().getMetaDataSession().getDictionary();
}
sqlTextViewer = new SQLTextViewer(myParent, style, store, dictionary, ruler);
sqlTextViewer.getControl().setLayoutData(gid);
// create bottom divider line
Composite div2 = new Composite(myParent, SWT.NONE);
lgid = new GridData();
lgid.grabExcessHorizontalSpace = true;
lgid.horizontalAlignment = GridData.FILL;
lgid.heightHint = 1;
lgid.verticalIndent = 0;
div2.setLayoutData(lgid);
div2.setBackground(editor.getSite().getShell().getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
final SQLEditor thisEditor = editor;
sqlTextViewer.getTextWidget().addVerifyKeyListener(new VerifyKeyListener() {
private ExecSQLAction _execSQLAction = new ExecSQLAction(thisEditor);
@Override
public void verifyKey(VerifyEvent event) {
if (event.stateMask == SWT.CTRL && event.keyCode == 13) {
event.doit = false;
_execSQLAction.run();
}
}
});
sqlTextViewer.getTextWidget().addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
SQLTextEditor.this.editor.getEditorSite().getPage().activate(SQLTextEditor.this.editor.getEditorSite().getPart());
}
});
myParent.layout();
IDocument dc = new Document();
sqlTextViewer.setDocument(dc);
mcl.install(sqlTextViewer);
return sqlTextViewer;
}
public void setNewDictionary(final Dictionary dictionary) {
if (editor.getSite() != null && editor.getSite().getShell() != null && editor.getSite().getShell().getDisplay() != null) {
editor.getSite().getShell().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
if (sqlTextViewer != null && !editor.getTitleImage().isDisposed()) {
sqlTextViewer.setNewDictionary(dictionary);
}
}
});
}
}
public void onEditorSessionChanged(Session session) {
if (session != null && _enableContentAssist) {
setNewDictionary(editor.getSession().getUser().getMetaDataSession().getDictionary());
} else {
setNewDictionary(null);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.IWorkbenchPart#dispose()
*/
@Override
public void dispose() {
if (partListener != null) {
editor.getEditorSite().getPage().removePartListener(partListener);
}
mcl.uninstall();
super.dispose();
}
ISourceViewer getViewer() {
return getSourceViewer();
}
}