improved parser string handling
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.quantum.sql / src / com / quantum / view / SQLQueryView.java
1 package com.quantum.view;
2
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;
8
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;
30
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;
43
44 public class SQLQueryView extends ViewPart {
45         private ExecuteAction executeAction;
46         private ImportQueryAction importQueryAction;
47         private ExportQueryAction exportQueryAction;
48         private Label statusImage;
49         private Label status;
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() {
63                 super();
64         }
65         public void setFocus() {
66                 
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();
73                 }
74                 if (bookmarkNode != null)
75                         bookmark = bookmarkNode.getBookmark();
76                 if (bookmark != null) {         
77                         title = bookmark.getName() + " (" + title + ")";
78                         setTitle( title );
79                         try {
80                                 con = bookmark.getConnection();
81                         } catch (NotConnectedException e) {
82                                 // Doesn't matter, "con" remains null
83                         }
84                 }
85                 
86                 updateAutoCommitState(bookmark, con);
87
88                 widget.setFocus();
89
90         }
91         public static SQLQueryView getInstance() {
92                 return (SQLQueryView) QuantumPlugin.getDefault().getView("com.quantum.view.sqlqueryview");
93
94         }
95
96         public void createPartControl(org.eclipse.swt.widgets.Composite parent) {
97                 initActions();
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) {
114                         }
115                         public void widgetSelected(SelectionEvent e) {
116                                 executeAction.run();
117                         }
118                 });
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) {
125                         }
126                         public void widgetSelected(SelectionEvent e) {
127                                 importQueryAction.run();
128                         }
129                 });
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) {
135                         }
136                         public void widgetSelected(SelectionEvent e) {
137                                 exportQueryAction.run();
138                         }
139                 });
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) {
145                         }
146                         public void widgetSelected(SelectionEvent e) {
147                                 setQuery(""); //$NON-NLS-1$
148                         }
149                 });
150
151                 item = new ToolItem(toolbar, SWT.SEPARATOR);
152
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) {
158                         }
159                         public void widgetSelected(SelectionEvent event) {
160                 try {
161                                 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
162                                 if (node != null) MultiSQLServer.getInstance().commit(
163                         node.getBookmark().getConnection());
164                 } catch (NotConnectedException e) {
165                     e.printStackTrace();
166                 }
167                         }
168                 });
169                 
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) {
175                         }
176                         public void widgetSelected(SelectionEvent event) {
177                 try {
178                     BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
179                     if (node != null) MultiSQLServer.getInstance().rollback(
180                         node.getBookmark().getConnection());
181                 } catch (NotConnectedException e) {
182                     e.printStackTrace();
183                 }
184                         }
185                 });
186                 
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) {
192                         }
193                         public void widgetSelected(SelectionEvent event) {
194                                 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
195                                 if (node == null) return;
196                                 Connection con = null; 
197                                 try { 
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) {
204                         //Doesn't matter
205                 }
206                 // Update the bookmark and the buttons
207                                 updateAutoCommitState(node.getBookmark(), con);
208                                 
209                         }
210                 });
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);
217                 } else {
218                         commitItem.setEnabled(true);
219                         rollbackItem.setEnabled(true);
220                 }
221                 widget = new StyledText(main, SWT.H_SCROLL | SWT.V_SCROLL);
222
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);
228
229                 widget.setEditable(true);
230                 widget.addExtendedModifyListener(modifyListener);
231
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);
238
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);
244                 
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);
251
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);
258
259                 progress = new ProgressBar(bottomStatus, SWT.HORIZONTAL);
260
261                 status.setText(Messages.getString("sqlqueryview.done")); //$NON-NLS-1$
262                 statusImage.setImage(QuantumPlugin.getImage("success.gif")); //$NON-NLS-1$
263                 progress.setMinimum(0);
264         
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"
270         });
271         keyBindingService.registerAction(this.executeAction);
272         }
273
274         /**
275          * Sets the state of the "Commit", "Rollback" and "autoCommit" buttons
276          * to reflect the situation in the connection
277          */
278         protected void updateAutoCommitState(Bookmark bookmark, Connection con) {
279                 boolean autoCommit = true;
280                 // Calculate the state of the autoCommit option
281                 if (con != null)
282                 {
283                         // If we have a connection, the autoCommit state is that of the connection
284                         try {
285                                 autoCommit = con.getAutoCommit();
286                         } catch (SQLException e) {
287                                 // Doesn't matter, we take default
288                         }
289                 } else {
290                         // if no connection, we try the autoCommit of the bookmark, or else the default
291                         if (bookmark != null) autoCommit = bookmark.isAutoCommit();
292                 }
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);
300                 } else {
301                         commitItem.setEnabled(true);
302                         rollbackItem.setEnabled(true);
303                 }
304         }
305         public void setProgress(int increment, int max) {
306                 progress.setMaximum(max);
307                 progress.setSelection(increment);
308         }
309         
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);
317         }
318
319         public void setStatus(String text) {
320                 statusImage.setImage(null);
321                 status.setText(text);
322         }
323
324         public void setStatus(Image img, String text) {
325                 statusImage.setImage(img);
326                 status.setText(text);
327         }
328         
329         public String getQuery() {
330                 return widget.getText();
331         }
332         
333         public void setQuery(String text) {
334                 widget.setText(text);
335         }
336         
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",
361         "YESNO" };
362         
363         SyntaxHighlighter textUpdater = new SyntaxHighlighter();
364         
365         private class UpdateRequest {
366                 public UpdateRequest(String text, int start, int length) {
367                         this.text = text;
368                         this.start = start;
369                         this.length = length;
370                 }
371                 public String text;
372                 public int start;
373                 public int length;
374         }
375         
376         private class SyntaxHighlighter extends Thread {
377                 private boolean running = true;
378                 private LinkedList requests = new LinkedList();
379                 public SyntaxHighlighter() {
380                         super();
381                         setPriority(Thread.MIN_PRIORITY);
382                         start();
383                 }
384                 public synchronized void updateText(String text, int start, int length) {
385                         requests.add(new UpdateRequest(text, start, length));
386                         notify();
387                 }
388                 public synchronized void shutdown() {
389                         running = false;
390                         interrupt();
391                 }
392                 public void run() {
393                         while (running) {
394                                 try {
395                                         synchronized (this) {
396                                                 if (requests.size() <= 0) {
397                                                         wait();
398                                                 } else {
399                                                         Thread.sleep(10);
400                                                 }
401                                         }
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;
412                                         int max = 0;
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])) {
434                                                                                 keyword = true;
435                                                                         }
436                                                                 }
437                                                                 if (keyword) {
438                                                                         styleRange.fontStyle = SWT.BOLD;
439                                                                         styleRange.foreground = KEYWORD;
440                                                                 } else {
441                                                                         styleRange.foreground = DEFAULT;
442                                                                 }
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);
453                                                         } else {
454                                                                 styles.addElement(styleRange);
455                                                         }
456                                                 }
457                                         }
458                                         StyleRange[] ranges = new StyleRange[styles.size()];
459                                         for (int k = 0; k < ranges.length; k++) {
460                                                 ranges[k] = (StyleRange) styles.elementAt(k);
461                                         }
462                                         if (max >= 0 && ranges.length > 0) {
463                                                 setStyles(ranges, min, max - min);
464                                         }
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
472                                 }
473                         }
474                 }
475         }
476         public void setStyles(final StyleRange[] styles, final int start, final int length) {
477                 getViewSite().getShell().getDisplay().asyncExec(new Runnable() {
478                         public void run() {
479                                 try {
480                                         for (int i = 0; i < styles.length; i++) {
481                                                 widget.setStyleRange(styles[i]);
482                                         }
483                                 } catch (Throwable t) {
484                                         System.out.println("Error with styles: " + t.getClass().toString()); //$NON-NLS-1$
485                                         // ignore any errors
486                                 }
487                         }
488                 });
489         }
490         
491         ExtendedModifyListener modifyListener = new ExtendedModifyListener() {
492                 public void modifyText(ExtendedModifyEvent event) {
493                         textUpdater.updateText(getQuery(), event.start, event.length);
494                 }
495         };
496                 
497         private Action cutAction = new Action() {
498                 public void run() {
499                         widget.cut();
500                 }
501         };
502         private Action copyAction = new Action() {
503                 public void run() {
504                         widget.copy();
505                 }
506         };
507         private Action pasteAction = new Action() {
508                 public void run() {
509                         widget.paste();
510                 }
511         };
512         private Action selectAllAction = new Action() {
513                 public void run() {
514                         widget.selectAll();
515                 }
516         };
517 }