1 package com.quantum.view;
3 import java.sql.Connection;
4 import java.sql.SQLException;
5 import java.util.LinkedList;
6 import java.util.NoSuchElementException;
7 import java.util.Vector;
9 import org.eclipse.jface.action.Action;
10 import org.eclipse.jface.action.IToolBarManager;
11 import org.eclipse.jface.action.Separator;
12 import org.eclipse.swt.SWT;
13 import org.eclipse.swt.custom.ExtendedModifyEvent;
14 import org.eclipse.swt.custom.ExtendedModifyListener;
15 import org.eclipse.swt.custom.StyleRange;
16 import org.eclipse.swt.custom.StyledText;
17 import org.eclipse.swt.events.SelectionEvent;
18 import org.eclipse.swt.events.SelectionListener;
19 import org.eclipse.swt.graphics.Color;
20 import org.eclipse.swt.layout.GridData;
21 import org.eclipse.swt.layout.GridLayout;
22 import org.eclipse.swt.widgets.Composite;
23 import org.eclipse.swt.widgets.ToolBar;
24 import org.eclipse.swt.widgets.ToolItem;
25 import org.eclipse.ui.IActionBars;
26 import org.eclipse.ui.IKeyBindingService;
27 import org.eclipse.ui.IWorkbenchActionConstants;
28 import org.eclipse.ui.part.ViewPart;
30 import com.quantum.Messages;
31 import com.quantum.QuantumPlugin;
32 import com.quantum.actions.ExecuteAction;
33 import com.quantum.actions.ExportQueryAction;
34 import com.quantum.actions.ImportQueryAction;
35 import com.quantum.model.Bookmark;
36 import com.quantum.model.NotConnectedException;
37 import com.quantum.sql.MultiSQLServer;
38 import com.quantum.sql.parser.SQLLexx;
39 import com.quantum.sql.parser.Token;
40 import com.quantum.util.versioning.VersioningHelper;
41 import com.quantum.view.bookmark.BookmarkNode;
42 import com.quantum.view.bookmark.BookmarkView;
44 public class SQLQueryView extends ViewPart {
45 private class ClearAction extends Action {
47 public ClearAction() {
48 setImageDescriptor(QuantumPlugin.getImageDescriptor("clear.gif"));
49 setToolTipText(Messages.getString("sqlqueryview.clear"));
57 private class AutoCommitPreferenceAction extends Action {
59 public AutoCommitPreferenceAction() {
60 super(Messages.getString("SQLQueryView.AutoCommit"), SWT.CHECK);
61 setToolTipText(Messages.getString("SQLQueryView.AutoCommit"));
62 setImageDescriptor(QuantumPlugin.getImageDescriptor("autocommit.gif"));
66 Connection connection = null;
69 connection = getBookmark().getConnection();
70 // If connected (else will throw exception and jump out) switchs the state of the
71 // autoCommit option of the JDBC driver
72 MultiSQLServer.getInstance().setAutoCommit( connection, isChecked());
73 } catch (NotConnectedException e) {
76 // Update the bookmark and the buttons
77 updateAutoCommitState(getBookmark(), connection);
82 private ExecuteAction executeAction;
83 private ImportQueryAction importQueryAction;
84 private ExportQueryAction exportQueryAction;
85 private StyledText widget;
86 private ToolItem autoCommitItem;
87 private ToolItem commitItem;
88 private ToolItem rollbackItem;
89 private Color STRING_LITERAL;
90 private Color KEYWORD;
91 private Color COMMENT;
92 private Color NUMERIC;
93 private Color DEFAULT;
94 private AutoCommitPreferenceAction autoCommitPreferenceAction;
96 public SQLQueryView() {
99 public void setFocus() {
101 String title = "Quantum SQL Query Editor";
102 Bookmark bookmark = null;
103 Connection con = null;
104 if (BookmarkView.getInstance() != null ) {
105 bookmark = getBookmark();
107 if (bookmark != null) {
108 title = bookmark.getName() + " (" + title + ")";
109 VersioningHelper.setPartName(this, title);
110 // setPartName("fred");
112 con = bookmark.getConnection();
113 } catch (NotConnectedException e) {
114 // Doesn't matter, "con" remains null
118 updateAutoCommitState(bookmark, con);
126 private Bookmark getBookmark() {
127 if (BookmarkView.getInstance() != null ) {
128 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
129 return node == null ? null : node.getBookmark();
134 public static SQLQueryView getInstance() {
135 return (SQLQueryView) QuantumPlugin.getDefault().getView("com.quantum.view.sqlqueryview");
139 public void createPartControl(org.eclipse.swt.widgets.Composite parent) {
142 KEYWORD = new Color(parent.getShell().getDisplay(), 126, 0, 75);
143 STRING_LITERAL = new Color(parent.getShell().getDisplay(), 0, 0, 255);
144 COMMENT = new Color(parent.getShell().getDisplay(), 88, 148, 64);
145 NUMERIC = new Color(parent.getShell().getDisplay(), 255, 0, 0);
146 DEFAULT = new Color(parent.getShell().getDisplay(), 0, 0, 0);
147 Composite main = new Composite(parent, SWT.NONE);
148 GridLayout layout = new GridLayout(1, false);
149 layout.horizontalSpacing = 0;
150 layout.verticalSpacing = 0;
151 main.setLayout(layout);
152 ToolBar toolbar = new ToolBar(main, SWT.HORIZONTAL);
154 commitItem = new ToolItem(toolbar, SWT.PUSH);
155 commitItem.setImage(QuantumPlugin.getImage("commit.gif")); //$NON-NLS-1$
156 commitItem.setToolTipText(Messages.getString("SQLQueryView.Commit")); //$NON-NLS-1$
157 commitItem.addSelectionListener(new SelectionListener() {
158 public void widgetDefaultSelected(SelectionEvent e) {
160 public void widgetSelected(SelectionEvent event) {
162 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
163 if (node != null) MultiSQLServer.getInstance().commit(
164 node.getBookmark().getConnection());
165 } catch (NotConnectedException e) {
171 rollbackItem = new ToolItem(toolbar, SWT.PUSH);
172 rollbackItem.setImage(QuantumPlugin.getImage("rollback.gif")); //$NON-NLS-1$
173 rollbackItem.setToolTipText(Messages.getString("SQLQueryView.RollBack")); //$NON-NLS-1$
174 rollbackItem.addSelectionListener(new SelectionListener() {
175 public void widgetDefaultSelected(SelectionEvent event) {
177 public void widgetSelected(SelectionEvent event) {
179 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
180 if (node != null) MultiSQLServer.getInstance().rollback(
181 node.getBookmark().getConnection());
182 } catch (NotConnectedException e) {
188 autoCommitItem = new ToolItem(toolbar, SWT.CHECK);
189 autoCommitItem.setImage(QuantumPlugin.getImage("autocommit.gif")); //$NON-NLS-1$
190 autoCommitItem.setToolTipText(Messages.getString("SQLQueryView.AutoCommit")); //$NON-NLS-1$
191 autoCommitItem.addSelectionListener(new SelectionListener() {
192 public void widgetDefaultSelected(SelectionEvent e) {
194 public void widgetSelected(SelectionEvent event) {
195 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
196 if (node == null) return;
197 Connection con = null;
199 // Get the connection
200 con = node.getBookmark().getConnection();
201 // If connected (else will throw exception and jump out) switchs the state of the
202 // autoCommit option of the JDBC driver
203 MultiSQLServer.getInstance().setAutoCommit( con, autoCommitItem.getSelection());
204 } catch (NotConnectedException e) {
207 // Update the bookmark and the buttons
208 updateAutoCommitState(node.getBookmark(), con);
213 // TODO: BCH -- this is causing some problems during start-up
214 Bookmark bookmark = null;
216 bookmark = getBookmark();
217 } catch (NullPointerException e) {
220 if (bookmark == null) {
221 autoCommitItem.setSelection(true);
223 autoCommitItem.setSelection(bookmark.isAutoCommit());
225 if (autoCommitItem.getSelection()) {
226 commitItem.setEnabled(false);
227 rollbackItem.setEnabled(false);
229 commitItem.setEnabled(true);
230 rollbackItem.setEnabled(true);
232 widget = new StyledText(main, SWT.H_SCROLL | SWT.V_SCROLL);
234 IActionBars bars = this.getViewSite().getActionBars();
235 bars.setGlobalActionHandler(IWorkbenchActionConstants.CUT, cutAction);
236 bars.setGlobalActionHandler(IWorkbenchActionConstants.COPY, copyAction);
237 bars.setGlobalActionHandler(IWorkbenchActionConstants.PASTE, pasteAction);
238 bars.setGlobalActionHandler(IWorkbenchActionConstants.SELECT_ALL, selectAllAction);
240 widget.setEditable(true);
241 widget.addExtendedModifyListener(modifyListener);
243 GridData gridData = new GridData();
244 gridData.horizontalAlignment = GridData.FILL;
245 gridData.verticalAlignment = GridData.FILL;
246 gridData.grabExcessHorizontalSpace = true;
247 gridData.grabExcessVerticalSpace = true;
248 widget.setLayoutData(gridData);
250 IKeyBindingService keyBindingService = getSite().getKeyBindingService();
251 // TODO: check the version numbers for this method
252 keyBindingService.setScopes(new String[] {
253 "org.eclipse.ui.globalScope",
254 "com.quantum.view.sql"
256 keyBindingService.registerAction(this.executeAction);
260 * Sets the state of the "Commit", "Rollback" and "autoCommit" buttons
261 * to reflect the situation in the connection
263 protected void updateAutoCommitState(Bookmark bookmark, Connection connection) {
264 boolean autoCommit = true;
265 // Calculate the state of the autoCommit option
266 if (connection != null)
268 // If we have a connection, the autoCommit state is that of the connection
270 autoCommit = connection.getAutoCommit();
271 } catch (SQLException e) {
272 // Doesn't matter, we take default
275 // if no connection, we try the autoCommit of the bookmark, or else the default
276 if (bookmark != null) autoCommit = bookmark.isAutoCommit();
278 // Set the autoCommit state of the bookmark to the calculated
279 if (bookmark != null) bookmark.setAutoCommit(autoCommit);
280 // Set the state of the buttons to the correct autoCommit state
281 autoCommitItem.setSelection(autoCommit);
282 this.autoCommitPreferenceAction.setChecked(autoCommit);
283 if (autoCommitItem.getSelection()) {
284 commitItem.setEnabled(false);
285 rollbackItem.setEnabled(false);
287 commitItem.setEnabled(true);
288 rollbackItem.setEnabled(true);
291 private void initActions() {
293 executeAction = new ExecuteAction();
294 executeAction.init(this);
296 IToolBarManager toolBar = getViewSite().getActionBars().getToolBarManager();
297 toolBar.add(this.executeAction);
298 // toolBar.add(this.importQueryAction);
299 // toolBar.add(this.exportQueryAction);
301 toolBar.add(new ClearAction());
303 IActionBars actionBars = getViewSite().getActionBars();
304 this.importQueryAction = new ImportQueryAction();
305 this.importQueryAction.init(this);
306 actionBars.getMenuManager().add(this.importQueryAction);
307 this.exportQueryAction = new ExportQueryAction();
308 this.exportQueryAction.init(this);
309 actionBars.getMenuManager().add(this.exportQueryAction);
310 actionBars.getMenuManager().add(new Separator());
311 this.autoCommitPreferenceAction = new AutoCommitPreferenceAction();
312 actionBars.getMenuManager().add(this.autoCommitPreferenceAction);
315 public String getQuery() {
316 return widget.getText();
319 public void setQuery(String text) {
320 widget.setText(text);
323 private String[] keywords = {
324 "ADD", "ALL", "ALTER", "AND", "ANY",
325 "AS", "ASC", "AUTOINCREMENT", "AVA", "BETWEEN",
326 "BINARY", "BIT", "BOOLEAN", "BY", "CREATE",
327 "BYTE", "CHAR", "CHARACTER", "COLUMN", "CONSTRAINT",
328 "COUNT", "COUNTER", "CURRENCY", "DATABASE", "DATE",
329 "DATETIME", "DELETE", "DESC", "DISALLOW", "DISTINCT",
330 "DISTINCTROW", "DOUBLE", "DROP", "EXISTS", "FROM",
331 "FLOAT", "FLOAT4", "FLOAT8", "FOREIGN", "GENERAL",
332 "GROUP", "GUID", "HAVING", "INNER", "INSERT",
333 "IGNORE", "IMP", "IN", "INDEX", "INT",
334 "INTEGER", "INTEGER1", "INTEGER2", "INTEGER4", "INTO",
335 "IS", "JOIN", "KEY", "LEFT", "LEVEL",
336 "LIKE", "LOGICAL", "LONG", "LONGBINARY", "LONGTEXT",
337 "MAX", "MEMO", "MIN", "MOD", "MONEY",
338 "NOT", "NULL", "NUMBER", "NUMERIC", "OLEOBJECT",
339 "ON", "PIVOT", "OPTION", "PRIMARY", "ORDER",
340 "OUTER", "OWNERACCESS", "PARAMETERS", "PERCENT", "REAL",
341 "REFERENCES", "RIGHT", "SELECT", "SET", "SHORT",
342 "SINGLE", "SMALLINT", "SOME", "STDEV", "STDEVP",
343 "STRING", "SUM", "TABLE", "TABLEID", "TEXT",
344 "TIME", "TIMESTAMP", "TOP", "TRANSFORM", "UNION",
345 "UNIQUE", "UPDATE", "VALUE", "VALUES", "VAR",
346 "VARBINARY", "VARCHAR", "VARP", "WHERE", "WITH",
349 SyntaxHighlighter textUpdater = new SyntaxHighlighter();
351 private class UpdateRequest {
352 public UpdateRequest(String text, int start, int length) {
355 this.length = length;
362 private class SyntaxHighlighter extends Thread {
363 private boolean running = true;
364 private LinkedList requests = new LinkedList();
365 public SyntaxHighlighter() {
367 setPriority(Thread.MIN_PRIORITY);
370 public synchronized void updateText(String text, int start, int length) {
371 requests.add(new UpdateRequest(text, start, length));
374 public synchronized void shutdown() {
381 synchronized (this) {
382 if (requests.size() <= 0) {
388 UpdateRequest request = (UpdateRequest) requests.removeFirst();
389 String text = request.text.toUpperCase();
390 //int dirtyStart = request.start;
391 //int dirtyEnd = request.start + request.length;
392 StyleRange styleRange;
393 Vector tokens = SQLLexx.parse(text);
394 Vector styles = new Vector();
395 int min = Integer.MAX_VALUE;
397 for (int i = 0; i < tokens.size(); i++) {
398 Token t = (Token) tokens.elementAt(i);
399 String value = t.getValue();
400 int start = t.getStart();
401 int length = t.getEnd() - t.getStart();
402 styleRange = new StyleRange();
403 styleRange.start = start;
404 styleRange.length = value.length();
405 styleRange.fontStyle = SWT.NULL;
406 styleRange.foreground = DEFAULT;
407 //boolean upper = start <= dirtyEnd && start >= dirtyStart;
408 //boolean lower = ((start + length) >= dirtyStart && (start + length) <= dirtyEnd);
409 //boolean both = (start <= dirtyStart && (start + length) >= dirtyEnd);
410 //if (upper || lower || both) {
411 if (true) { // Let's update the whole text, as some comment changes can alter everything
412 min = Math.min(start, min);
413 max = Math.max(max, start + length);
414 if (t.getType() == Token.IDENTIFIER) {
415 boolean keyword = false;
416 for (int index = 0; index < keywords.length; index++) {
417 if (value.equals(keywords[index])) {
422 styleRange.fontStyle = SWT.BOLD;
423 styleRange.foreground = KEYWORD;
425 styleRange.foreground = DEFAULT;
427 styles.addElement(styleRange);
428 } else if (t.getType() == Token.COMMENT) {
429 styleRange.foreground = COMMENT;
430 styles.addElement(styleRange);
431 } else if (t.getType() == Token.LITERAL) {
432 styleRange.foreground = STRING_LITERAL;
433 styles.addElement(styleRange);
434 } else if (t.getType() == Token.NUMERIC) {
435 styleRange.foreground = NUMERIC;
436 styles.addElement(styleRange);
438 styles.addElement(styleRange);
442 StyleRange[] ranges = new StyleRange[styles.size()];
443 for (int k = 0; k < ranges.length; k++) {
444 ranges[k] = (StyleRange) styles.elementAt(k);
446 if (max >= 0 && ranges.length > 0) {
447 setStyles(ranges, min, max - min);
449 } catch (NoSuchElementException e) {
450 // ignore a missing request
451 } catch (InterruptedException e) {
452 // ignore any interruptions
457 public void setStyles(final StyleRange[] styles, final int start, final int length) {
458 getViewSite().getShell().getDisplay().asyncExec(new Runnable() {
461 for (int i = 0; i < styles.length; i++) {
462 widget.setStyleRange(styles[i]);
464 } catch (Throwable t) {
465 System.out.println("Error with styles: " + t.getClass().toString()); //$NON-NLS-1$
472 ExtendedModifyListener modifyListener = new ExtendedModifyListener() {
473 public void modifyText(ExtendedModifyEvent event) {
474 textUpdater.updateText(getQuery(), event.start, event.length);
478 private Action cutAction = new Action() {
483 private Action copyAction = new Action() {
488 private Action pasteAction = new Action() {
493 private Action selectAllAction = new Action() {