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.swt.SWT;
11 import org.eclipse.swt.custom.ExtendedModifyEvent;
12 import org.eclipse.swt.custom.ExtendedModifyListener;
13 import org.eclipse.swt.custom.StyleRange;
14 import org.eclipse.swt.custom.StyledText;
15 import org.eclipse.swt.events.SelectionEvent;
16 import org.eclipse.swt.events.SelectionListener;
17 import org.eclipse.swt.graphics.Color;
18 import org.eclipse.swt.graphics.Image;
19 import org.eclipse.swt.layout.GridData;
20 import org.eclipse.swt.layout.GridLayout;
21 import org.eclipse.swt.widgets.Composite;
22 import org.eclipse.swt.widgets.Label;
23 import org.eclipse.swt.widgets.ProgressBar;
24 import org.eclipse.swt.widgets.ToolBar;
25 import org.eclipse.swt.widgets.ToolItem;
26 import org.eclipse.ui.IActionBars;
27 import org.eclipse.ui.IKeyBindingService;
28 import org.eclipse.ui.IWorkbenchActionConstants;
29 import org.eclipse.ui.part.ViewPart;
31 import com.quantum.Messages;
32 import com.quantum.QuantumPlugin;
33 import com.quantum.actions.ExecuteAction;
34 import com.quantum.actions.ExportQueryAction;
35 import com.quantum.actions.ImportQueryAction;
36 import com.quantum.model.Bookmark;
37 import com.quantum.model.NotConnectedException;
38 import com.quantum.sql.MultiSQLServer;
39 import com.quantum.sql.parser.SQLLexx;
40 import com.quantum.sql.parser.Token;
41 import com.quantum.view.bookmark.BookmarkNode;
42 import com.quantum.view.bookmark.BookmarkView;
44 public class SQLQueryView extends ViewPart {
45 private ExecuteAction executeAction;
46 private ImportQueryAction importQueryAction;
47 private ExportQueryAction exportQueryAction;
48 private Label statusImage;
50 private ProgressBar progress;
51 private StyledText widget;
52 private ToolItem autoCommitItem;
53 private ToolItem commitItem;
54 private ToolItem rollbackItem;
55 private Color STRING_LITERAL;
56 private Color KEYWORD;
57 private Color COMMENT;
58 private Color NUMERIC;
59 private Color DEFAULT;
60 private long parseTime = 0;
61 private long fullTime = 0;
62 public SQLQueryView() {
65 public void setFocus() {
67 String title = "Quantum SQL Query Editor";
68 BookmarkNode bookmarkNode = null;
69 Bookmark bookmark = null;
70 Connection con = null;
71 if (BookmarkView.getInstance() != null ) {
72 bookmarkNode = BookmarkView.getInstance().getCurrentBookmark();
74 if (bookmarkNode != null)
75 bookmark = bookmarkNode.getBookmark();
76 if (bookmark != null) {
77 title = bookmark.getName() + " (" + title + ")";
80 con = bookmark.getConnection();
81 } catch (NotConnectedException e) {
82 // Doesn't matter, "con" remains null
86 updateAutoCommitState(bookmark, con);
91 public static SQLQueryView getInstance() {
92 return (SQLQueryView) QuantumPlugin.getDefault().getView("com.quantum.view.sqlqueryview");
96 public void createPartControl(org.eclipse.swt.widgets.Composite parent) {
98 KEYWORD = new Color(parent.getShell().getDisplay(), 126, 0, 75);
99 STRING_LITERAL = new Color(parent.getShell().getDisplay(), 0, 0, 255);
100 COMMENT = new Color(parent.getShell().getDisplay(), 88, 148, 64);
101 NUMERIC = new Color(parent.getShell().getDisplay(), 255, 0, 0);
102 DEFAULT = new Color(parent.getShell().getDisplay(), 0, 0, 0);
103 Composite main = new Composite(parent, SWT.NONE);
104 GridLayout layout = new GridLayout(1, false);
105 layout.horizontalSpacing = 0;
106 layout.verticalSpacing = 0;
107 main.setLayout(layout);
108 ToolBar toolbar = new ToolBar(main, SWT.HORIZONTAL);
109 ToolItem item = new ToolItem(toolbar, SWT.PUSH);
110 item.setImage(QuantumPlugin.getImage("play.gif")); //$NON-NLS-1$
111 item.setToolTipText(Messages.getString("sqlqueryview.executeQuery")); //$NON-NLS-1$
112 item.addSelectionListener(new SelectionListener() {
113 public void widgetDefaultSelected(SelectionEvent e) {
115 public void widgetSelected(SelectionEvent e) {
119 item = new ToolItem(toolbar, SWT.SEPARATOR);
120 item = new ToolItem(toolbar, SWT.PUSH);
121 item.setImage(QuantumPlugin.getImage("import.gif")); //$NON-NLS-1$
122 item.setToolTipText(Messages.getString("sqlqueryview.importQuery")); //$NON-NLS-1$
123 item.addSelectionListener(new SelectionListener() {
124 public void widgetDefaultSelected(SelectionEvent e) {
126 public void widgetSelected(SelectionEvent e) {
127 importQueryAction.run();
130 item = new ToolItem(toolbar, SWT.PUSH);
131 item.setImage(QuantumPlugin.getImage("export.gif")); //$NON-NLS-1$
132 item.setToolTipText(Messages.getString("sqlqueryview.exportQuery")); //$NON-NLS-1$
133 item.addSelectionListener(new SelectionListener() {
134 public void widgetDefaultSelected(SelectionEvent e) {
136 public void widgetSelected(SelectionEvent e) {
137 exportQueryAction.run();
140 item = new ToolItem(toolbar, SWT.PUSH);
141 item.setImage(QuantumPlugin.getImage("clear.gif")); //$NON-NLS-1$
142 item.setToolTipText(Messages.getString("sqlqueryview.clear")); //$NON-NLS-1$
143 item.addSelectionListener(new SelectionListener() {
144 public void widgetDefaultSelected(SelectionEvent e) {
146 public void widgetSelected(SelectionEvent e) {
147 setQuery(""); //$NON-NLS-1$
151 item = new ToolItem(toolbar, SWT.SEPARATOR);
153 commitItem = new ToolItem(toolbar, SWT.PUSH);
154 commitItem.setImage(QuantumPlugin.getImage("commit.gif")); //$NON-NLS-1$
155 commitItem.setToolTipText(Messages.getString("SQLQueryView.Commit")); //$NON-NLS-1$
156 commitItem.addSelectionListener(new SelectionListener() {
157 public void widgetDefaultSelected(SelectionEvent e) {
159 public void widgetSelected(SelectionEvent event) {
161 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
162 if (node != null) MultiSQLServer.getInstance().commit(
163 node.getBookmark().getConnection());
164 } catch (NotConnectedException e) {
170 rollbackItem = new ToolItem(toolbar, SWT.PUSH);
171 rollbackItem.setImage(QuantumPlugin.getImage("rollback.gif")); //$NON-NLS-1$
172 rollbackItem.setToolTipText(Messages.getString("SQLQueryView.RollBack")); //$NON-NLS-1$
173 rollbackItem.addSelectionListener(new SelectionListener() {
174 public void widgetDefaultSelected(SelectionEvent event) {
176 public void widgetSelected(SelectionEvent event) {
178 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
179 if (node != null) MultiSQLServer.getInstance().rollback(
180 node.getBookmark().getConnection());
181 } catch (NotConnectedException e) {
187 autoCommitItem = new ToolItem(toolbar, SWT.CHECK);
188 autoCommitItem.setImage(QuantumPlugin.getImage("autocommit.gif")); //$NON-NLS-1$
189 autoCommitItem.setToolTipText(Messages.getString("SQLQueryView.AutoCommit")); //$NON-NLS-1$
190 autoCommitItem.addSelectionListener(new SelectionListener() {
191 public void widgetDefaultSelected(SelectionEvent e) {
193 public void widgetSelected(SelectionEvent event) {
194 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
195 if (node == null) return;
196 Connection con = null;
198 // Get the connection
199 con = node.getBookmark().getConnection();
200 // If connected (else will throw exception and jump out) switchs the state of the
201 // autoCommit option of the JDBC driver
202 MultiSQLServer.getInstance().setAutoCommit( con, autoCommitItem.getSelection());
203 } catch (NotConnectedException e) {
206 // Update the bookmark and the buttons
207 updateAutoCommitState(node.getBookmark(), con);
211 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
212 if (node == null) autoCommitItem.setSelection(true);
213 else autoCommitItem.setSelection(node.getBookmark().isAutoCommit());
214 if (autoCommitItem.getSelection()) {
215 commitItem.setEnabled(false);
216 rollbackItem.setEnabled(false);
218 commitItem.setEnabled(true);
219 rollbackItem.setEnabled(true);
221 widget = new StyledText(main, SWT.H_SCROLL | SWT.V_SCROLL);
223 IActionBars bars = this.getViewSite().getActionBars();
224 bars.setGlobalActionHandler(IWorkbenchActionConstants.CUT, cutAction);
225 bars.setGlobalActionHandler(IWorkbenchActionConstants.COPY, copyAction);
226 bars.setGlobalActionHandler(IWorkbenchActionConstants.PASTE, pasteAction);
227 bars.setGlobalActionHandler(IWorkbenchActionConstants.SELECT_ALL, selectAllAction);
229 widget.setEditable(true);
230 widget.addExtendedModifyListener(modifyListener);
232 GridData gridData = new GridData();
233 gridData.horizontalAlignment = GridData.FILL;
234 gridData.verticalAlignment = GridData.FILL;
235 gridData.grabExcessHorizontalSpace = true;
236 gridData.grabExcessVerticalSpace = true;
237 widget.setLayoutData(gridData);
239 Composite bottomStatus = new Composite(main, SWT.NONE);
240 gridData = new GridData();
241 gridData.horizontalAlignment = GridData.FILL;
242 gridData.grabExcessHorizontalSpace = true;
243 bottomStatus.setLayoutData(gridData);
245 GridLayout horizontal = new GridLayout(3, false);
246 layout.horizontalSpacing = 0;
247 layout.verticalSpacing = 0;
248 layout.marginHeight = 0;
249 layout.marginWidth = 0;
250 bottomStatus.setLayout(horizontal);
252 statusImage = new Label(bottomStatus, SWT.NONE);
253 status = new Label(bottomStatus, SWT.NONE);
254 gridData = new GridData();
255 gridData.horizontalAlignment = GridData.FILL;
256 gridData.grabExcessHorizontalSpace = true;
257 status.setLayoutData(gridData);
259 progress = new ProgressBar(bottomStatus, SWT.HORIZONTAL);
261 status.setText(Messages.getString("sqlqueryview.done")); //$NON-NLS-1$
262 statusImage.setImage(QuantumPlugin.getImage("success.gif")); //$NON-NLS-1$
263 progress.setMinimum(0);
265 IKeyBindingService keyBindingService = getSite().getKeyBindingService();
266 // TODO: check the version numbers for this method
267 keyBindingService.setScopes(new String[] {
268 "org.eclipse.ui.globalScope",
269 "com.quantum.view.sql"
271 keyBindingService.registerAction(this.executeAction);
275 * Sets the state of the "Commit", "Rollback" and "autoCommit" buttons
276 * to reflect the situation in the connection
278 protected void updateAutoCommitState(Bookmark bookmark, Connection con) {
279 boolean autoCommit = true;
280 // Calculate the state of the autoCommit option
283 // If we have a connection, the autoCommit state is that of the connection
285 autoCommit = con.getAutoCommit();
286 } catch (SQLException e) {
287 // Doesn't matter, we take default
290 // if no connection, we try the autoCommit of the bookmark, or else the default
291 if (bookmark != null) autoCommit = bookmark.isAutoCommit();
293 // Set the autoCommit state of the bookmark to the calculated
294 if (bookmark != null) bookmark.setAutoCommit(autoCommit);
295 // Set the state of the buttons to the correct autoCommit state
296 autoCommitItem.setSelection(autoCommit);
297 if (autoCommitItem.getSelection()) {
298 commitItem.setEnabled(false);
299 rollbackItem.setEnabled(false);
301 commitItem.setEnabled(true);
302 rollbackItem.setEnabled(true);
305 public void setProgress(int increment, int max) {
306 progress.setMaximum(max);
307 progress.setSelection(increment);
310 private void initActions() {
311 executeAction = new ExecuteAction();
312 executeAction.init(this);
313 importQueryAction = new ImportQueryAction();
314 importQueryAction.init(this);
315 exportQueryAction = new ExportQueryAction();
316 exportQueryAction.init(this);
319 public void setStatus(String text) {
320 statusImage.setImage(null);
321 status.setText(text);
324 public void setStatus(Image img, String text) {
325 statusImage.setImage(img);
326 status.setText(text);
329 public String getQuery() {
330 return widget.getText();
333 public void setQuery(String text) {
334 widget.setText(text);
337 private String[] keywords = {
338 "ADD", "ALL", "ALTER", "AND", "ANY",
339 "AS", "ASC", "AUTOINCREMENT", "AVA", "BETWEEN",
340 "BINARY", "BIT", "BOOLEAN", "BY", "CREATE",
341 "BYTE", "CHAR", "CHARACTER", "COLUMN", "CONSTRAINT",
342 "COUNT", "COUNTER", "CURRENCY", "DATABASE", "DATE",
343 "DATETIME", "DELETE", "DESC", "DISALLOW", "DISTINCT",
344 "DISTINCTROW", "DOUBLE", "DROP", "EXISTS", "FROM",
345 "FLOAT", "FLOAT4", "FLOAT8", "FOREIGN", "GENERAL",
346 "GROUP", "GUID", "HAVING", "INNER", "INSERT",
347 "IGNORE", "IMP", "IN", "INDEX", "INT",
348 "INTEGER", "INTEGER1", "INTEGER2", "INTEGER4", "INTO",
349 "IS", "JOIN", "KEY", "LEFT", "LEVEL",
350 "LIKE", "LOGICAL", "LONG", "LONGBINARY", "LONGTEXT",
351 "MAX", "MEMO", "MIN", "MOD", "MONEY",
352 "NOT", "NULL", "NUMBER", "NUMERIC", "OLEOBJECT",
353 "ON", "PIVOT", "OPTION", "PRIMARY", "ORDER",
354 "OUTER", "OWNERACCESS", "PARAMETERS", "PERCENT", "REAL",
355 "REFERENCES", "RIGHT", "SELECT", "SET", "SHORT",
356 "SINGLE", "SMALLINT", "SOME", "STDEV", "STDEVP",
357 "STRING", "SUM", "TABLE", "TABLEID", "TEXT",
358 "TIME", "TIMESTAMP", "TOP", "TRANSFORM", "UNION",
359 "UNIQUE", "UPDATE", "VALUE", "VALUES", "VAR",
360 "VARBINARY", "VARCHAR", "VARP", "WHERE", "WITH",
363 SyntaxHighlighter textUpdater = new SyntaxHighlighter();
365 private class UpdateRequest {
366 public UpdateRequest(String text, int start, int length) {
369 this.length = length;
376 private class SyntaxHighlighter extends Thread {
377 private boolean running = true;
378 private LinkedList requests = new LinkedList();
379 public SyntaxHighlighter() {
381 setPriority(Thread.MIN_PRIORITY);
384 public synchronized void updateText(String text, int start, int length) {
385 requests.add(new UpdateRequest(text, start, length));
388 public synchronized void shutdown() {
395 synchronized (this) {
396 if (requests.size() <= 0) {
402 UpdateRequest request = (UpdateRequest) requests.removeFirst();
403 String text = request.text.toUpperCase();
404 //int dirtyStart = request.start;
405 //int dirtyEnd = request.start + request.length;
406 StyleRange styleRange;
407 long startTime = System.currentTimeMillis();
408 Vector tokens = SQLLexx.parse(text);
409 long subTime = System.currentTimeMillis();
410 Vector styles = new Vector();
411 int min = Integer.MAX_VALUE;
413 for (int i = 0; i < tokens.size(); i++) {
414 Token t = (Token) tokens.elementAt(i);
415 String value = t.getValue();
416 int start = t.getStart();
417 int length = t.getEnd() - t.getStart();
418 styleRange = new StyleRange();
419 styleRange.start = start;
420 styleRange.length = value.length();
421 styleRange.fontStyle = SWT.NULL;
422 styleRange.foreground = DEFAULT;
423 //boolean upper = start <= dirtyEnd && start >= dirtyStart;
424 //boolean lower = ((start + length) >= dirtyStart && (start + length) <= dirtyEnd);
425 //boolean both = (start <= dirtyStart && (start + length) >= dirtyEnd);
426 //if (upper || lower || both) {
427 if (true) { // Let's update the whole text, as some comment changes can alter everything
428 min = Math.min(start, min);
429 max = Math.max(max, start + length);
430 if (t.getType() == Token.IDENTIFIER) {
431 boolean keyword = false;
432 for (int index = 0; index < keywords.length; index++) {
433 if (value.equals(keywords[index])) {
438 styleRange.fontStyle = SWT.BOLD;
439 styleRange.foreground = KEYWORD;
441 styleRange.foreground = DEFAULT;
443 styles.addElement(styleRange);
444 } else if (t.getType() == Token.COMMENT) {
445 styleRange.foreground = COMMENT;
446 styles.addElement(styleRange);
447 } else if (t.getType() == Token.LITERAL) {
448 styleRange.foreground = STRING_LITERAL;
449 styles.addElement(styleRange);
450 } else if (t.getType() == Token.NUMERIC) {
451 styleRange.foreground = NUMERIC;
452 styles.addElement(styleRange);
454 styles.addElement(styleRange);
458 StyleRange[] ranges = new StyleRange[styles.size()];
459 for (int k = 0; k < ranges.length; k++) {
460 ranges[k] = (StyleRange) styles.elementAt(k);
462 if (max >= 0 && ranges.length > 0) {
463 setStyles(ranges, min, max - min);
465 long endTime = System.currentTimeMillis();
466 parseTime = subTime - startTime;
467 fullTime = endTime - startTime;
468 } catch (NoSuchElementException e) {
469 // ignore a missing request
470 } catch (InterruptedException e) {
471 // ignore any interruptions
476 public void setStyles(final StyleRange[] styles, final int start, final int length) {
477 getViewSite().getShell().getDisplay().asyncExec(new Runnable() {
480 for (int i = 0; i < styles.length; i++) {
481 widget.setStyleRange(styles[i]);
483 } catch (Throwable t) {
484 System.out.println("Error with styles: " + t.getClass().toString()); //$NON-NLS-1$
491 ExtendedModifyListener modifyListener = new ExtendedModifyListener() {
492 public void modifyText(ExtendedModifyEvent event) {
493 textUpdater.updateText(getQuery(), event.start, event.length);
497 private Action cutAction = new Action() {
502 private Action copyAction = new Action() {
507 private Action pasteAction = new Action() {
512 private Action selectAllAction = new Action() {