Improved calculation of function/methods sourceEnd for code folding
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.sql / src / net / sourceforge / phpdt / sql / view / SQLQueryView.java
1 package net.sourceforge.phpdt.sql.view;
2
3 import java.util.LinkedList;
4 import java.util.NoSuchElementException;
5 import java.util.Vector;
6
7 import org.eclipse.jface.action.Action;
8 import org.eclipse.swt.SWT;
9 import org.eclipse.swt.custom.ExtendedModifyEvent;
10 import org.eclipse.swt.custom.ExtendedModifyListener;
11 import org.eclipse.swt.custom.StyleRange;
12 import org.eclipse.swt.custom.StyledText;
13 import org.eclipse.swt.dnd.Clipboard;
14 import org.eclipse.swt.events.SelectionEvent;
15 import org.eclipse.swt.events.SelectionListener;
16 import org.eclipse.swt.graphics.Color;
17 import org.eclipse.swt.graphics.Image;
18 import org.eclipse.swt.layout.GridData;
19 import org.eclipse.swt.layout.GridLayout;
20 import org.eclipse.swt.widgets.Composite;
21 import org.eclipse.swt.widgets.Label;
22 import org.eclipse.swt.widgets.ProgressBar;
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.IWorkbenchActionConstants;
27 import org.eclipse.ui.part.ViewPart;
28
29 import net.sourceforge.phpdt.sql.IConstants;
30 import net.sourceforge.phpdt.sql.Messages;
31 import net.sourceforge.phpdt.sql.PHPEclipseSQLPlugin;
32 import net.sourceforge.phpdt.sql.actions.ExecuteAction;
33 import net.sourceforge.phpdt.sql.actions.ExportQueryAction;
34 import net.sourceforge.phpdt.sql.actions.GeneratePHPAction;
35 import net.sourceforge.phpdt.sql.actions.ImportQueryAction;
36 import net.sourceforge.phpdt.sql.sql.MultiSQLServer;
37 import net.sourceforge.phpdt.sql.sql.parser.SQLLexx;
38 import net.sourceforge.phpdt.sql.sql.parser.Token;
39 import net.sourceforge.phpdt.sql.view.bookmark.BookmarkNode;
40
41 public class SQLQueryView extends ViewPart implements IConstants {
42         ExecuteAction executeAction;
43         ImportQueryAction importQueryAction;
44         ExportQueryAction exportQueryAction;
45         GeneratePHPAction generatePHPAction;
46         private Clipboard clip;
47         private Label statusImage;
48         private Label status;
49         private ProgressBar progress;
50         private static SQLQueryView instance = null;
51         private StyledText widget;
52         private Color STRING_LITERAL;
53         private Color KEYWORD;
54         private Color COMMENT;
55         private Color NUMERIC;
56         private Color DEFAULT;
57         private long parseTime = 0;
58         private long fullTime = 0;
59         public SQLQueryView() {
60                 super();
61         }
62         public void setFocus() {
63                 widget.setFocus();
64         }
65         public static SQLQueryView getInstance() {
66                 return instance;
67         }
68
69         public void createPartControl(org.eclipse.swt.widgets.Composite parent) {
70                 instance = this;
71                 initActions();
72                 KEYWORD = new Color(parent.getShell().getDisplay(), 126, 0, 75);
73                 STRING_LITERAL = new Color(parent.getShell().getDisplay(), 0, 0, 255);
74                 COMMENT = new Color(parent.getShell().getDisplay(), 88, 148, 64);
75                 NUMERIC = new Color(parent.getShell().getDisplay(), 255, 0, 0);
76             DEFAULT = new Color(parent.getShell().getDisplay(), 0, 0, 0);
77                 clip = new Clipboard(getSite().getShell().getDisplay());
78                 Composite main = new Composite(parent, SWT.NONE);
79                 GridLayout layout = new GridLayout(1, false);
80                 layout.horizontalSpacing = 0;
81                 layout.verticalSpacing = 0;
82                 main.setLayout(layout);
83                 ToolBar toolbar = new ToolBar(main, SWT.HORIZONTAL);
84                 ToolItem item = new ToolItem(toolbar, SWT.PUSH);
85                 item.setImage(PHPEclipseSQLPlugin.getImage("play.gif")); //$NON-NLS-1$
86                 item.setToolTipText(Messages.getString("sqlqueryview.executeQuery")); //$NON-NLS-1$
87                 item.addSelectionListener(new SelectionListener() {
88                         public void widgetDefaultSelected(SelectionEvent e) {
89                         }
90                         public void widgetSelected(SelectionEvent e) {
91                                 executeAction.run();
92                         }
93                 });
94                 item = new ToolItem(toolbar, SWT.SEPARATOR);
95                 item = new ToolItem(toolbar, SWT.PUSH);
96                 item.setImage(PHPEclipseSQLPlugin.getImage("import.gif")); //$NON-NLS-1$
97                 item.setToolTipText(Messages.getString("sqlqueryview.importQuery")); //$NON-NLS-1$
98                 item.addSelectionListener(new SelectionListener() {
99                         public void widgetDefaultSelected(SelectionEvent e) {
100                         }
101                         public void widgetSelected(SelectionEvent e) {
102                                 importQueryAction.run();
103                         }
104                 });
105                 item = new ToolItem(toolbar, SWT.PUSH);
106                 item.setImage(PHPEclipseSQLPlugin.getImage("export.gif")); //$NON-NLS-1$
107                 item.setToolTipText(Messages.getString("sqlqueryview.exportQuery")); //$NON-NLS-1$
108                 item.addSelectionListener(new SelectionListener() {
109                         public void widgetDefaultSelected(SelectionEvent e) {
110                         }
111                         public void widgetSelected(SelectionEvent e) {
112                                 exportQueryAction.run();
113                         }
114                 });
115                 item = new ToolItem(toolbar, SWT.PUSH);
116                 item.setImage(PHPEclipseSQLPlugin.getImage("php.gif")); //$NON-NLS-1$
117                 item.setToolTipText(Messages.getString("sqlqueryview.generatePHP")); //$NON-NLS-1$
118                 item.addSelectionListener(new SelectionListener() {
119                         public void widgetDefaultSelected(SelectionEvent e) {
120                         }
121                         public void widgetSelected(SelectionEvent e) {
122                                 generatePHPAction.run();
123                         }
124                 });             
125                 item = new ToolItem(toolbar, SWT.PUSH);
126                 item.setImage(PHPEclipseSQLPlugin.getImage("clear.gif")); //$NON-NLS-1$
127                 item.setToolTipText(Messages.getString("sqlqueryview.clear")); //$NON-NLS-1$
128                 item.addSelectionListener(new SelectionListener() {
129                         public void widgetDefaultSelected(SelectionEvent e) {
130                         }
131                         public void widgetSelected(SelectionEvent e) {
132                                 setQuery(""); //$NON-NLS-1$
133                         }
134                 });
135
136                 item = new ToolItem(toolbar, SWT.SEPARATOR);
137
138                 item = new ToolItem(toolbar, SWT.PUSH);
139                 final ToolItem commit = item;
140                 item.setImage(PHPEclipseSQLPlugin.getImage("commit.gif")); //$NON-NLS-1$
141                 item.setToolTipText(Messages.getString("SQLQueryView.Commit")); //$NON-NLS-1$
142                 item.addSelectionListener(new SelectionListener() {
143                         public void widgetDefaultSelected(SelectionEvent e) {
144                         }
145                         public void widgetSelected(SelectionEvent e) {
146                                 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
147                                 MultiSQLServer.getInstance().commit(node.getConnection());
148                         }
149                 });
150                 item.setEnabled(false);
151                 
152                 item = new ToolItem(toolbar, SWT.PUSH);
153                 final ToolItem rollback = item;
154                 item.setImage(PHPEclipseSQLPlugin.getImage("rollback.gif")); //$NON-NLS-1$
155                 item.setToolTipText(Messages.getString("SQLQueryView.RollBack")); //$NON-NLS-1$
156                 item.addSelectionListener(new SelectionListener() {
157                         public void widgetDefaultSelected(SelectionEvent e) {
158                         }
159                         public void widgetSelected(SelectionEvent e) {
160                                 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
161                                 MultiSQLServer.getInstance().rollback(node.getConnection());
162                         }
163                 });
164                 item.setEnabled(false);
165                 
166                 item = new ToolItem(toolbar, SWT.CHECK);
167                 final ToolItem autocommit = item;
168                 item.setImage(PHPEclipseSQLPlugin.getImage("autocommit.gif")); //$NON-NLS-1$
169                 item.setToolTipText(Messages.getString("SQLQueryView.AutoCommit")); //$NON-NLS-1$
170                 item.addSelectionListener(new SelectionListener() {
171                         public void widgetDefaultSelected(SelectionEvent e) {
172                         }
173                         public void widgetSelected(SelectionEvent e) {
174                                 BookmarkNode node = BookmarkView.getInstance().getCurrentBookmark();
175                                 
176                                 MultiSQLServer.getInstance().setAutoCommit(node.getConnection(), autocommit.getSelection());
177                                 if (autocommit.getSelection()) {
178                                         commit.setEnabled(false);
179                                         rollback.setEnabled(false);
180                                 } else {
181                                         commit.setEnabled(true);
182                                         rollback.setEnabled(true);
183                                 }
184                         }
185                 });
186                 item.setSelection(true);
187                 
188                 widget = new StyledText(main, SWT.H_SCROLL | SWT.V_SCROLL);
189
190                 IActionBars bars = this.getViewSite().getActionBars();
191                 bars.setGlobalActionHandler(IWorkbenchActionConstants.CUT, cutAction);
192                 bars.setGlobalActionHandler(IWorkbenchActionConstants.COPY, copyAction);
193                 bars.setGlobalActionHandler(IWorkbenchActionConstants.PASTE, pasteAction);
194                 bars.setGlobalActionHandler(IWorkbenchActionConstants.SELECT_ALL, selectAllAction);
195
196                 widget.setEditable(true);
197                 widget.addExtendedModifyListener(modifyListener);
198
199                 GridData gridData = new GridData();
200                 gridData.horizontalAlignment = GridData.FILL;
201                 gridData.verticalAlignment = GridData.FILL;
202                 gridData.grabExcessHorizontalSpace = true;
203                 gridData.grabExcessVerticalSpace = true;
204                 widget.setLayoutData(gridData);
205
206                 Composite bottomStatus = new Composite(main, SWT.NONE);
207                 gridData = new GridData();
208                 gridData.horizontalAlignment = GridData.FILL;
209                 gridData.grabExcessHorizontalSpace = true;
210                 bottomStatus.setLayoutData(gridData);
211                 
212                 GridLayout horizontal = new GridLayout(3, false);
213                 layout.horizontalSpacing = 0;
214                 layout.verticalSpacing = 0;
215                 layout.marginHeight = 0;
216                 layout.marginWidth = 0;
217                 bottomStatus.setLayout(horizontal);
218
219                 statusImage = new Label(bottomStatus, SWT.NONE);
220                 status = new Label(bottomStatus, SWT.NONE);
221                 gridData = new GridData();
222                 gridData.horizontalAlignment = GridData.FILL;
223                 gridData.grabExcessHorizontalSpace = true;
224                 status.setLayoutData(gridData);
225
226                 progress = new ProgressBar(bottomStatus, SWT.HORIZONTAL);
227
228                 status.setText(Messages.getString("sqlqueryview.done")); //$NON-NLS-1$
229                 statusImage.setImage(PHPEclipseSQLPlugin.getImage("success.gif")); //$NON-NLS-1$
230                 progress.setMinimum(0);
231         }
232
233         public void setProgress(int increment, int max) {
234                 progress.setMaximum(max);
235                 progress.setSelection(increment);
236         }
237         
238         private void initActions() {
239                 executeAction = new ExecuteAction();
240                 executeAction.init(this);
241                 importQueryAction = new ImportQueryAction();
242                 importQueryAction.init(this);
243                 exportQueryAction = new ExportQueryAction();
244                 exportQueryAction.init(this);
245                 generatePHPAction = new GeneratePHPAction();
246                 generatePHPAction.init(this);
247         }
248
249         public void setStatus(String text) {
250                 statusImage.setImage(null);
251                 status.setText(text);
252         }
253
254         public void setStatus(Image img, String text) {
255                 statusImage.setImage(img);
256                 status.setText(text);
257         }
258         
259         public String getQuery() {
260                 return widget.getText();
261         }
262         
263         public void setQuery(String text) {
264                 widget.setText(text);
265         }
266         
267         private String[] keywords = {"SELECT", "DROP", "FROM",  //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
268                 "INSERT", "INTO", "VALUES", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
269                 "CREATE", "TABLE", "VIEW", "SEQUENCE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
270                 "UPDATE", "SET", "WHERE"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
271
272         SyntaxHighlighter textUpdater = new SyntaxHighlighter();
273         
274         private class UpdateRequest {
275                 public UpdateRequest(String text, int start, int length) {
276                         this.text = text;
277                         this.start = start;
278                         this.length = length;
279                 }
280                 public String text;
281                 public int start;
282                 public int length;
283         }
284         
285         private class SyntaxHighlighter extends Thread {
286                 private boolean running = true;
287                 private LinkedList requests = new LinkedList();
288                 public SyntaxHighlighter() {
289                         super();
290                         setPriority(Thread.MIN_PRIORITY);
291                         start();
292                 }
293                 public synchronized void updateText(String text, int start, int length) {
294                         requests.add(new UpdateRequest(text, start, length));
295                         notify();
296                 }
297                 public synchronized void shutdown() {
298                         running = false;
299                         interrupt();
300                 }
301                 public void run() {
302                         while (running) {
303                                 try {
304                                         synchronized (this) {
305                                                 if (requests.size() <= 0) {
306                                                         wait();
307                                                 } else {
308                                                         Thread.sleep(10);
309                                                 }
310                                         }
311                                         UpdateRequest request = (UpdateRequest) requests.removeFirst();
312                                         String text = request.text.toUpperCase();
313                                         int dirtyStart = request.start;
314                                         int dirtyEnd = request.start + request.length;
315                                         StyleRange styleRange;
316                                         long startTime = System.currentTimeMillis();
317                                         Vector tokens = SQLLexx.parse(text);
318                                         long subTime = System.currentTimeMillis();
319                                         Vector styles = new Vector();
320                                         int min = Integer.MAX_VALUE;
321                                         int max = 0;
322                                         for (int i = 0; i < tokens.size(); i++) {
323                                                 Token t = (Token) tokens.elementAt(i);
324                                                 String value = t.getValue();
325                                                 int start = t.getStart();
326                                                 int length = t.getEnd() - t.getStart();
327                                                 styleRange = new StyleRange();
328                                                 styleRange.start = start;
329                                                 styleRange.length = value.length();
330                                                 styleRange.fontStyle = SWT.NULL;
331                                                 styleRange.foreground = DEFAULT;
332                                                 boolean upper = start <= dirtyEnd && start >= dirtyStart;
333                                                 boolean lower = ((start + length) >= dirtyStart && (start + length) <= dirtyEnd);
334                                                 boolean both = (start <= dirtyStart && (start + length) >= dirtyEnd);
335                                                 if (upper || lower || both) {
336                                                         min = Math.min(start, min);
337                                                         max = Math.max(max, start + length);
338                                                         if (t.getType() == Token.IDENTIFIER) {
339                                                                 boolean keyword = false;
340                                                                 for (int index = 0; index < keywords.length; index++) {
341                                                                         if (value.equals(keywords[index])) {
342                                                                                 keyword = true;
343                                                                         }
344                                                                 }
345                                                                 if (keyword) {
346                                                                         styleRange.fontStyle = SWT.BOLD;
347                                                                         styleRange.foreground = KEYWORD;
348                                                                 } else {
349                                                                         styleRange.foreground = DEFAULT;
350                                                                 }
351                                                                 styles.addElement(styleRange);
352                                                         } else if (t.getType() == Token.COMMENT) {
353                                                                 styleRange.foreground = COMMENT;
354                                                                 styles.addElement(styleRange);
355                                                         } else if (t.getType() == Token.LITERAL) {
356                                                                 styleRange.foreground = STRING_LITERAL;
357                                                                 styles.addElement(styleRange);
358                                                         } else if (t.getType() == Token.NUMERIC) {
359                                                                 styleRange.foreground = NUMERIC;
360                                                                 styles.addElement(styleRange);
361                                                         } else {
362                                                                 styles.addElement(styleRange);
363                                                         }
364                                                 }
365                                         }
366                                         StyleRange[] ranges = new StyleRange[styles.size()];
367                                         for (int k = 0; k < ranges.length; k++) {
368                                                 ranges[k] = (StyleRange) styles.elementAt(k);
369                                         }
370                                         if (max >= 0 && ranges.length > 0) {
371                                                 setStyles(ranges, min, max - min);
372                                         }
373                                         long endTime = System.currentTimeMillis();
374                                         parseTime = subTime - startTime;
375                                         fullTime = endTime - startTime;
376                                 } catch (NoSuchElementException e) {
377                                         // ignore a missing request
378                                 } catch (InterruptedException e) {
379                                         // ignore any interruptions
380                                 }
381                         }
382                 }
383         }
384         public void setStyles(final StyleRange[] styles, final int start, final int length) {
385                 getViewSite().getShell().getDisplay().asyncExec(new Runnable() {
386                         public void run() {
387                                 try {
388                                         for (int i = 0; i < styles.length; i++) {
389                                                 widget.setStyleRange(styles[i]);
390                                         }
391                                 } catch (Throwable t) {
392                                         System.out.println("Error with styles: " + t.getClass().toString()); //$NON-NLS-1$
393                                         // ignore any errors
394                                 }
395                         }
396                 });
397         }
398         
399         ExtendedModifyListener modifyListener = new ExtendedModifyListener() {
400                 public void modifyText(ExtendedModifyEvent event) {
401                         textUpdater.updateText(getQuery(), event.start, event.length);
402                 }
403         };
404                 
405         private Action cutAction = new Action() {
406                 public void run() {
407                         widget.cut();
408                 }
409         };
410         private Action copyAction = new Action() {
411                 public void run() {
412                         widget.copy();
413                 }
414         };
415         private Action pasteAction = new Action() {
416                 public void run() {
417                         widget.paste();
418                 }
419         };
420         private Action selectAllAction = new Action() {
421                 public void run() {
422                         widget.selectAll();
423                 }
424         };
425 }