package com.quantum.view; import java.sql.Connection; import java.sql.SQLException; import java.util.LinkedList; import java.util.NoSuchElementException; import java.util.Vector; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.Separator; 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.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IKeyBindingService; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.part.ViewPart; import com.quantum.Messages; import com.quantum.QuantumPlugin; import com.quantum.actions.ExecuteAction; import com.quantum.actions.ExportQueryAction; import com.quantum.actions.ImportQueryAction; import com.quantum.model.Bookmark; import com.quantum.model.NotConnectedException; import com.quantum.sql.MultiSQLServer; import com.quantum.sql.parser.SQLLexx; import com.quantum.sql.parser.Token; import com.quantum.util.versioning.VersioningHelper; import com.quantum.view.bookmark.BookmarkNode; import com.quantum.view.bookmark.BookmarkView; public class SQLQueryView extends ViewPart { private class ClearAction extends Action { public ClearAction() { setImageDescriptor(QuantumPlugin.getImageDescriptor("clear.gif")); setToolTipText(Messages.getString("sqlqueryview.clear")); } public void run() { setQuery(""); } } private class AutoCommitPreferenceAction extends Action { public AutoCommitPreferenceAction() { super(Messages.getString("SQLQueryView.AutoCommit"), SWT.CHECK); setToolTipText(Messages.getString("SQLQueryView.AutoCommit")); setImageDescriptor(QuantumPlugin.getImageDescriptor("autocommit.gif")); } public void run() { Connection connection = null; try { // Get the connection connection = getBookmark().getConnection(); // If connected (else will throw exception and jump out) switchs the state of the // autoCommit option of the JDBC driver MultiSQLServer.getInstance().setAutoCommit( connection, isChecked()); } catch (NotConnectedException e) { //Doesn't matter } // Update the bookmark and the buttons updateAutoCommitState(getBookmark(), connection); } } private ExecuteAction executeAction; private ImportQueryAction importQueryAction; private ExportQueryAction exportQueryAction; private StyledText widget; private ToolItem autoCommitItem; private ToolItem commitItem; private ToolItem rollbackItem; private Color STRING_LITERAL; private Color KEYWORD; private Color COMMENT; private Color NUMERIC; private Color DEFAULT; private AutoCommitPreferenceAction autoCommitPreferenceAction; public SQLQueryView() { super(); } public void setFocus() { String title = "Quantum SQL Query Editor"; Bookmark bookmark = null; Connection con = null; if (BookmarkView.getInstance() != null ) { bookmark = getBookmark(); } if (bookmark != null) { title = bookmark.getName() + " (" + title + ")"; VersioningHelper.setPartName(this, title); // setPartName("fred"); try { con = bookmark.getConnection(); } catch (NotConnectedException e) { // Doesn't matter, "con" remains null } } updateAutoCommitState(bookmark, con); widget.setFocus(); } /** * @return */ private Bookmark getBookmark() { if (BookmarkView.getInstance() != null ) { BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark(); return node == null ? null : node.getBookmark(); } else { return null; } } public static SQLQueryView getInstance() { return (SQLQueryView) QuantumPlugin.getDefault().getView("com.quantum.view.sqlqueryview"); } public void createPartControl(org.eclipse.swt.widgets.Composite parent) { initActions(); KEYWORD = new Color(parent.getShell().getDisplay(), 126, 0, 75); STRING_LITERAL = new Color(parent.getShell().getDisplay(), 0, 0, 255); COMMENT = new Color(parent.getShell().getDisplay(), 88, 148, 64); NUMERIC = new Color(parent.getShell().getDisplay(), 255, 0, 0); DEFAULT = new Color(parent.getShell().getDisplay(), 0, 0, 0); Composite main = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(1, false); layout.horizontalSpacing = 0; layout.verticalSpacing = 0; main.setLayout(layout); ToolBar toolbar = new ToolBar(main, SWT.HORIZONTAL); commitItem = new ToolItem(toolbar, SWT.PUSH); commitItem.setImage(QuantumPlugin.getImage("commit.gif")); //$NON-NLS-1$ commitItem.setToolTipText(Messages.getString("SQLQueryView.Commit")); //$NON-NLS-1$ commitItem.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { } public void widgetSelected(SelectionEvent event) { try { BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark(); if (node != null) MultiSQLServer.getInstance().commit( node.getBookmark().getConnection()); } catch (NotConnectedException e) { e.printStackTrace(); } } }); rollbackItem = new ToolItem(toolbar, SWT.PUSH); rollbackItem.setImage(QuantumPlugin.getImage("rollback.gif")); //$NON-NLS-1$ rollbackItem.setToolTipText(Messages.getString("SQLQueryView.RollBack")); //$NON-NLS-1$ rollbackItem.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent event) { } public void widgetSelected(SelectionEvent event) { try { BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark(); if (node != null) MultiSQLServer.getInstance().rollback( node.getBookmark().getConnection()); } catch (NotConnectedException e) { e.printStackTrace(); } } }); autoCommitItem = new ToolItem(toolbar, SWT.CHECK); autoCommitItem.setImage(QuantumPlugin.getImage("autocommit.gif")); //$NON-NLS-1$ autoCommitItem.setToolTipText(Messages.getString("SQLQueryView.AutoCommit")); //$NON-NLS-1$ autoCommitItem.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { } public void widgetSelected(SelectionEvent event) { BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark(); if (node == null) return; Connection con = null; try { // Get the connection con = node.getBookmark().getConnection(); // If connected (else will throw exception and jump out) switchs the state of the // autoCommit option of the JDBC driver MultiSQLServer.getInstance().setAutoCommit( con, autoCommitItem.getSelection()); } catch (NotConnectedException e) { //Doesn't matter } // Update the bookmark and the buttons updateAutoCommitState(node.getBookmark(), con); } }); // TODO: BCH -- this is causing some problems during start-up Bookmark bookmark = null; try { bookmark = getBookmark(); } catch (NullPointerException e) { } if (bookmark == null) { autoCommitItem.setSelection(true); } else { autoCommitItem.setSelection(bookmark.isAutoCommit()); } if (autoCommitItem.getSelection()) { commitItem.setEnabled(false); rollbackItem.setEnabled(false); } else { commitItem.setEnabled(true); rollbackItem.setEnabled(true); } widget = new StyledText(main, SWT.H_SCROLL | SWT.V_SCROLL); 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); GridData gridData = new GridData(); gridData.horizontalAlignment = GridData.FILL; gridData.verticalAlignment = GridData.FILL; gridData.grabExcessHorizontalSpace = true; gridData.grabExcessVerticalSpace = true; widget.setLayoutData(gridData); IKeyBindingService keyBindingService = getSite().getKeyBindingService(); // TODO: check the version numbers for this method keyBindingService.setScopes(new String[] { "org.eclipse.ui.globalScope", "com.quantum.view.sql" }); keyBindingService.registerAction(this.executeAction); } /** * Sets the state of the "Commit", "Rollback" and "autoCommit" buttons * to reflect the situation in the connection */ protected void updateAutoCommitState(Bookmark bookmark, Connection connection) { boolean autoCommit = true; // Calculate the state of the autoCommit option if (connection != null) { // If we have a connection, the autoCommit state is that of the connection try { autoCommit = connection.getAutoCommit(); } catch (SQLException e) { // Doesn't matter, we take default } } else { // if no connection, we try the autoCommit of the bookmark, or else the default if (bookmark != null) autoCommit = bookmark.isAutoCommit(); } // Set the autoCommit state of the bookmark to the calculated if (bookmark != null) bookmark.setAutoCommit(autoCommit); // Set the state of the buttons to the correct autoCommit state autoCommitItem.setSelection(autoCommit); this.autoCommitPreferenceAction.setChecked(autoCommit); if (autoCommitItem.getSelection()) { commitItem.setEnabled(false); rollbackItem.setEnabled(false); } else { commitItem.setEnabled(true); rollbackItem.setEnabled(true); } } private void initActions() { executeAction = new ExecuteAction(); executeAction.init(this); IToolBarManager toolBar = getViewSite().getActionBars().getToolBarManager(); toolBar.add(this.executeAction); // toolBar.add(this.importQueryAction); // toolBar.add(this.exportQueryAction); 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(); actionBars.getMenuManager().add(this.autoCommitPreferenceAction); } public String getQuery() { return widget.getText(); } public void setQuery(String text) { widget.setText(text); } private String[] keywords = { "ADD", "ALL", "ALTER", "AND", "ANY", "AS", "ASC", "AUTOINCREMENT", "AVA", "BETWEEN", "BINARY", "BIT", "BOOLEAN", "BY", "CREATE", "BYTE", "CHAR", "CHARACTER", "COLUMN", "CONSTRAINT", "COUNT", "COUNTER", "CURRENCY", "DATABASE", "DATE", "DATETIME", "DELETE", "DESC", "DISALLOW", "DISTINCT", "DISTINCTROW", "DOUBLE", "DROP", "EXISTS", "FROM", "FLOAT", "FLOAT4", "FLOAT8", "FOREIGN", "GENERAL", "GROUP", "GUID", "HAVING", "INNER", "INSERT", "IGNORE", "IMP", "IN", "INDEX", "INT", "INTEGER", "INTEGER1", "INTEGER2", "INTEGER4", "INTO", "IS", "JOIN", "KEY", "LEFT", "LEVEL", "LIKE", "LOGICAL", "LONG", "LONGBINARY", "LONGTEXT", "MAX", "MEMO", "MIN", "MOD", "MONEY", "NOT", "NULL", "NUMBER", "NUMERIC", "OLEOBJECT", "ON", "PIVOT", "OPTION", "PRIMARY", "ORDER", "OUTER", "OWNERACCESS", "PARAMETERS", "PERCENT", "REAL", "REFERENCES", "RIGHT", "SELECT", "SET", "SHORT", "SINGLE", "SMALLINT", "SOME", "STDEV", "STDEVP", "STRING", "SUM", "TABLE", "TABLEID", "TEXT", "TIME", "TIMESTAMP", "TOP", "TRANSFORM", "UNION", "UNIQUE", "UPDATE", "VALUE", "VALUES", "VAR", "VARBINARY", "VARCHAR", "VARP", "WHERE", "WITH", "YESNO" }; SyntaxHighlighter textUpdater = new SyntaxHighlighter(); 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 boolean running = true; private LinkedList requests = new LinkedList(); public SyntaxHighlighter() { super(); setPriority(Thread.MIN_PRIORITY); start(); } public synchronized void updateText(String text, int start, int length) { requests.add(new UpdateRequest(text, start, length)); notify(); } public synchronized void shutdown() { running = false; interrupt(); } 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; Vector tokens = SQLLexx.parse(text); Vector styles = new Vector(); int min = Integer.MAX_VALUE; int max = 0; for (int i = 0; i < tokens.size(); i++) { Token t = (Token) tokens.elementAt(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 < keywords.length; index++) { if (value.equals(keywords[index])) { keyword = true; } } if (keyword) { styleRange.fontStyle = SWT.BOLD; styleRange.foreground = KEYWORD; } else { styleRange.foreground = DEFAULT; } styles.addElement(styleRange); } else if (t.getType() == Token.COMMENT) { styleRange.foreground = COMMENT; styles.addElement(styleRange); } else if (t.getType() == Token.LITERAL) { styleRange.foreground = STRING_LITERAL; styles.addElement(styleRange); } else if (t.getType() == Token.NUMERIC) { styleRange.foreground = NUMERIC; styles.addElement(styleRange); } else { styles.addElement(styleRange); } } } StyleRange[] ranges = new StyleRange[styles.size()]; for (int k = 0; k < ranges.length; k++) { ranges[k] = (StyleRange) styles.elementAt(k); } 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(); } }; }