package com.quantum.view; import java.sql.SQLException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; import java.util.Vector; import com.quantum.ImageStore; import com.quantum.Messages; import com.quantum.PluginPreferences; import com.quantum.QuantumPlugin; import com.quantum.actions.ExecuteAction; import com.quantum.actions.ExportQueryAction; import com.quantum.actions.ImportQueryAction; import com.quantum.editors.ColorManager; import com.quantum.model.Bookmark; import com.quantum.model.BookmarkCollection; import com.quantum.model.NotConnectedException; import com.quantum.sql.MultiSQLServer; import com.quantum.sql.SQLGrammar; import com.quantum.sql.parser.SQLLexx; import com.quantum.sql.parser.Token; import com.quantum.ui.dialog.ExceptionDisplayDialog; import com.quantum.ui.dialog.SQLExceptionDialog; import com.quantum.util.versioning.VersioningHelper; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ExtendedModifyEvent; import org.eclipse.swt.custom.ExtendedModifyListener; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.part.ViewPart; public class SQLQueryView extends ViewPart { private class ClearAction extends Action { public ClearAction() { setImageDescriptor(ImageStore.getImageDescriptor(ImageStore.CLEAR)); setToolTipText(Messages.getString("sqlqueryview.clear")); } public void run() { setQuery(""); } } private class AutoCommitPreferenceAction extends Action { public AutoCommitPreferenceAction() { super(Messages.getString("SQLQueryView.AutoCommit")); setToolTipText(Messages.getString("SQLQueryView.AutoCommit")); setImageDescriptor(ImageStore.getImageDescriptor(ImageStore.AUTOCOMMIT)); } public void run() { setAutoCommitPreference(isChecked()); } } private class RollbackAction extends Action { public RollbackAction() { setText(Messages.getString("SQLQueryView.RollBack")); setToolTipText(Messages.getString("SQLQueryView.RollBack")); } public void run() { Bookmark[] bookmarks = BookmarkCollection.getInstance().getBookmarks(); for (int i = 0, length = bookmarks == null ? 0 : bookmarks.length; i < length; i++) { try { if (bookmarks[i].isConnected() && !bookmarks[i].getConnection().getAutoCommit()) { MultiSQLServer.getInstance().rollback(bookmarks[i].getConnection()); } } catch (SQLException e) { SQLExceptionDialog.openException(getSite().getShell(), bookmarks[i], e); } catch (NotConnectedException e) { ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e); } } } } private class CommitAction extends Action { public CommitAction() { setText(Messages.getString("SQLQueryView.Commit")); setToolTipText(Messages.getString("SQLQueryView.Commit")); } public void run() { Bookmark[] bookmarks = BookmarkCollection.getInstance().getBookmarks(); for (int i = 0, length = bookmarks == null ? 0 : bookmarks.length; i < length; i++) { try { if (bookmarks[i].isConnected() && !bookmarks[i].getConnection().getAutoCommit()) { MultiSQLServer.getInstance().commit(bookmarks[i].getConnection()); } } catch (SQLException e) { SQLExceptionDialog.openException(getSite().getShell(), bookmarks[i], e); } catch (NotConnectedException e) { ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e); } } } } public class LabelProviderImpl implements ILabelProvider { public Image getImage(Object element) { return ImageStore.getImage(ImageStore.BOOKMARK); } public String getText(Object element) { if (element instanceof Bookmark) { return ((Bookmark) element).getName(); } else { return null; } } public void addListener(ILabelProviderListener listener) { } public void dispose() { } public boolean isLabelProperty(Object element, String property) { return false; } public void removeListener(ILabelProviderListener listener) { } } public class ContentProviderImpl implements IStructuredContentProvider { public Object[] getElements(Object inputElement) { if (inputElement instanceof BookmarkCollection) { return ((BookmarkCollection) inputElement).getBookmarks(); } else { return null; } } public void dispose() { } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } } private ExecuteAction executeAction; private ImportQueryAction importQueryAction; private ExportQueryAction exportQueryAction; private StyledText widget; private AutoCommitPreferenceAction autoCommitPreferenceAction; private RollbackAction rollbackAction; private CommitAction commitAction; private boolean autoCommitPreference = true; private IPropertyChangeListener listener; private ColorManager colorManager = new ColorManager(); private SyntaxHighlighter textUpdater = new SyntaxHighlighter(this.colorManager); public SQLQueryView() { super(); this.listener = new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { setFont(); } }; QuantumPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(listener); } public void dispose() { QuantumPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this.listener); this.colorManager.dispose(); super.dispose(); } public static SQLQueryView getInstance() { return (SQLQueryView) QuantumPlugin.getDefault().getView("com.quantum.view.sqlqueryview"); } public void createPartControl(org.eclipse.swt.widgets.Composite parent) { initActions(); initializeColours(parent); GridLayout layout = new GridLayout(1, false); layout.horizontalSpacing = 0; layout.verticalSpacing = 0; layout.marginHeight = 0; layout.marginWidth = 0; parent.setLayout(layout); parent.setLayoutData(new GridData(GridData.FILL_BOTH)); widget = new StyledText(parent, SWT.H_SCROLL | SWT.V_SCROLL); setFont(); IActionBars bars = this.getViewSite().getActionBars(); bars.setGlobalActionHandler(IWorkbenchActionConstants.CUT, cutAction); bars.setGlobalActionHandler(IWorkbenchActionConstants.COPY, copyAction); bars.setGlobalActionHandler(IWorkbenchActionConstants.PASTE, pasteAction); bars.setGlobalActionHandler(IWorkbenchActionConstants.SELECT_ALL, selectAllAction); widget.setEditable(true); widget.addExtendedModifyListener(modifyListener); widget.setLayoutData(new GridData(GridData.FILL_BOTH)); VersioningHelper.registerActionToKeyBindingService(getSite(), new String[] { "org.eclipse.ui.globalScope", "com.quantum.view.sql" }, this.executeAction); } /** * @param widget2 */ private void setFont() { FontData font = PreferenceConverter.getFontData( QuantumPlugin.getDefault().getPreferenceStore(), "quantum.font"); //$NON-NLS-1$ if (font != null && this.widget != null) { this.widget.setFont(new Font(Display.getCurrent(), font)); } } /** * @param parent */ private void initializeColours(Composite parent) { IPreferenceStore store = QuantumPlugin.getDefault().getPreferenceStore(); parent.setBackground(this.colorManager.getColor( PreferenceConverter.getColor(store, PluginPreferences.BACKGROUND_COLOR))); this.textUpdater.initializeColours(); } private void initActions() { IToolBarManager toolBar = getViewSite().getActionBars().getToolBarManager(); executeAction = new ExecuteAction(this); toolBar.add(this.executeAction); toolBar.add(new ClearAction()); IActionBars actionBars = getViewSite().getActionBars(); this.importQueryAction = new ImportQueryAction(); this.importQueryAction.init(this); actionBars.getMenuManager().add(this.importQueryAction); this.exportQueryAction = new ExportQueryAction(); this.exportQueryAction.init(this); actionBars.getMenuManager().add(this.exportQueryAction); actionBars.getMenuManager().add(new Separator()); this.autoCommitPreferenceAction = new AutoCommitPreferenceAction(); this.autoCommitPreferenceAction.setChecked(this.autoCommitPreference); actionBars.getMenuManager().add(this.autoCommitPreferenceAction); this.rollbackAction = new RollbackAction(); actionBars.getMenuManager().add(this.rollbackAction); this.commitAction = new CommitAction(); actionBars.getMenuManager().add(this.commitAction); } public String getQuery() { return widget.getText(); } public void setQuery(String text) { widget.setText(text); } private class UpdateRequest { public UpdateRequest(String text, int start, int length) { this.text = text; this.start = start; this.length = length; } public String text; public int start; public int length; } private class SyntaxHighlighter extends Thread { private Color STRING_LITERAL; private Color KEYWORD; private Color COMMENT; private Color NUMERIC; private Color DEFAULT; private boolean running = true; private LinkedList requests = new LinkedList(); private final ColorManager colorManager; public SyntaxHighlighter(ColorManager colorManager) { super(); this.colorManager = colorManager; setPriority(Thread.MIN_PRIORITY); start(); } public void initializeColours() { IPreferenceStore store = QuantumPlugin.getDefault().getPreferenceStore(); this.DEFAULT = this.colorManager.getColor( PreferenceConverter.getColor(store, PluginPreferences.TEXT_COLOR)); this.KEYWORD = this.colorManager.getColor( PreferenceConverter.getColor(store, PluginPreferences.KEYWORD_COLOR)); this.STRING_LITERAL = this.colorManager.getColor( PreferenceConverter.getColor(store, PluginPreferences.STRING_COLOR)); this.COMMENT = this.colorManager.getColor( PreferenceConverter.getColor(store, PluginPreferences.COMMENT_COLOR)); this.NUMERIC = this.colorManager.getColor( PreferenceConverter.getColor(store, PluginPreferences.NUMERIC_COLOR)); } public synchronized void updateText(String text, int start, int length) { requests.add(new UpdateRequest(text, start, length)); notify(); } public void run() { while (running) { try { synchronized (this) { if (requests.size() <= 0) { wait(); } else { Thread.sleep(10); } } UpdateRequest request = (UpdateRequest) requests.removeFirst(); String text = request.text.toUpperCase(); //int dirtyStart = request.start; //int dirtyEnd = request.start + request.length; StyleRange styleRange; List tokens = SQLLexx.parse(text); List styles = new ArrayList(); int min = Integer.MAX_VALUE; int max = 0; for (int i = 0; i < tokens.size(); i++) { Token t = (Token) tokens.get(i); String value = t.getValue(); int start = t.getStart(); int length = t.getEnd() - t.getStart(); styleRange = new StyleRange(); styleRange.start = start; styleRange.length = value.length(); styleRange.fontStyle = SWT.NULL; styleRange.foreground = DEFAULT; //boolean upper = start <= dirtyEnd && start >= dirtyStart; //boolean lower = ((start + length) >= dirtyStart && (start + length) <= dirtyEnd); //boolean both = (start <= dirtyStart && (start + length) >= dirtyEnd); //if (upper || lower || both) { if (true) { // Let's update the whole text, as some comment changes can alter everything min = Math.min(start, min); max = Math.max(max, start + length); if (t.getType() == Token.IDENTIFIER) { boolean keyword = false; for (int index = 0; index < SQLGrammar.KEYWORDS.length; index++) { if (value.equals(SQLGrammar.KEYWORDS[index])) { keyword = true; } } if (keyword) { styleRange.fontStyle = SWT.BOLD; styleRange.foreground = KEYWORD; } else { styleRange.foreground = DEFAULT; } styles.add(styleRange); } else if (t.getType() == Token.COMMENT) { styleRange.foreground = COMMENT; styles.add(styleRange); } else if (t.getType() == Token.LITERAL) { styleRange.foreground = STRING_LITERAL; styles.add(styleRange); } else if (t.getType() == Token.NUMERIC) { styleRange.foreground = NUMERIC; styles.add(styleRange); } else { styles.add(styleRange); } } } StyleRange[] ranges = (StyleRange[]) styles.toArray(new StyleRange[styles.size()]); if (max >= 0 && ranges.length > 0) { setStyles(ranges, min, max - min); } } catch (NoSuchElementException e) { // ignore a missing request } catch (InterruptedException e) { // ignore any interruptions } } } } public void setStyles(final StyleRange[] styles, final int start, final int length) { getViewSite().getShell().getDisplay().asyncExec(new Runnable() { public void run() { try { for (int i = 0; i < styles.length; i++) { widget.setStyleRange(styles[i]); } } catch (Throwable t) { System.out.println("Error with styles: " + t.getClass().toString()); //$NON-NLS-1$ // ignore any errors } } }); } ExtendedModifyListener modifyListener = new ExtendedModifyListener() { public void modifyText(ExtendedModifyEvent event) { textUpdater.updateText(getQuery(), event.start, event.length); } }; private Action cutAction = new Action() { public void run() { widget.cut(); } }; private Action copyAction = new Action() { public void run() { widget.copy(); } }; private Action pasteAction = new Action() { public void run() { widget.paste(); } }; private Action selectAllAction = new Action() { public void run() { widget.selectAll(); } }; public void setFocus() { } public boolean isAutoCommitPreference() { return this.autoCommitPreference; } public void setAutoCommitPreference(boolean autoCommitPreference) { this.autoCommitPreference = autoCommitPreference; } }