improved syntax highlighting (php tag/return keyword/brackets and operators)
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.quantum.sql / src / com / quantum / view / SQLQueryView.java
1 package com.quantum.view;
2
3 import java.sql.SQLException;
4 import java.util.LinkedList;
5 import java.util.NoSuchElementException;
6 import java.util.Vector;
7
8 import com.quantum.ImageStore;
9 import com.quantum.Messages;
10 import com.quantum.QuantumPlugin;
11 import com.quantum.actions.ExecuteAction;
12 import com.quantum.actions.ExportQueryAction;
13 import com.quantum.actions.ImportQueryAction;
14 import com.quantum.model.Bookmark;
15 import com.quantum.model.BookmarkCollection;
16 import com.quantum.model.NotConnectedException;
17 import com.quantum.sql.MultiSQLServer;
18 import com.quantum.sql.SQLGrammar;
19 import com.quantum.sql.parser.SQLLexx;
20 import com.quantum.sql.parser.Token;
21 import com.quantum.ui.dialog.ExceptionDisplayDialog;
22 import com.quantum.util.versioning.VersioningHelper;
23
24 import org.eclipse.jface.action.Action;
25 import org.eclipse.jface.action.IToolBarManager;
26 import org.eclipse.jface.action.Separator;
27 import org.eclipse.jface.preference.PreferenceConverter;
28 import org.eclipse.jface.util.IPropertyChangeListener;
29 import org.eclipse.jface.util.PropertyChangeEvent;
30 import org.eclipse.jface.viewers.ILabelProvider;
31 import org.eclipse.jface.viewers.ILabelProviderListener;
32 import org.eclipse.jface.viewers.IStructuredContentProvider;
33 import org.eclipse.jface.viewers.Viewer;
34 import org.eclipse.swt.SWT;
35 import org.eclipse.swt.custom.ExtendedModifyEvent;
36 import org.eclipse.swt.custom.ExtendedModifyListener;
37 import org.eclipse.swt.custom.StyleRange;
38 import org.eclipse.swt.custom.StyledText;
39 import org.eclipse.swt.graphics.Color;
40 import org.eclipse.swt.graphics.Font;
41 import org.eclipse.swt.graphics.FontData;
42 import org.eclipse.swt.graphics.Image;
43 import org.eclipse.swt.layout.GridData;
44 import org.eclipse.swt.layout.GridLayout;
45 import org.eclipse.swt.widgets.Display;
46 import org.eclipse.ui.IActionBars;
47 import org.eclipse.ui.IWorkbenchActionConstants;
48 import org.eclipse.ui.part.ViewPart;
49
50 public class SQLQueryView extends ViewPart {
51         private class ClearAction extends Action {
52                 
53                 public ClearAction() {
54                         setImageDescriptor(ImageStore.getImageDescriptor(ImageStore.CLEAR));
55                         setToolTipText(Messages.getString("sqlqueryview.clear"));
56                 }
57
58                 public void run() {
59                         setQuery("");
60                 }
61         }
62
63         private class AutoCommitPreferenceAction extends Action {
64                 
65                 public AutoCommitPreferenceAction() {
66                         super(Messages.getString("SQLQueryView.AutoCommit"));
67                         setToolTipText(Messages.getString("SQLQueryView.AutoCommit"));
68                         setImageDescriptor(ImageStore.getImageDescriptor(ImageStore.AUTOCOMMIT));
69                 }
70                 
71                 public void run() {
72                         setAutoCommitPreference(isChecked());
73                 }
74         }
75         
76         private class RollbackAction extends Action {
77                 public RollbackAction() {
78                         setText(Messages.getString("SQLQueryView.RollBack"));
79                         setToolTipText(Messages.getString("SQLQueryView.RollBack"));
80                 }
81                 
82                 public void run() {
83                 Bookmark[] bookmarks = BookmarkCollection.getInstance().getBookmarks();
84                 for (int i = 0, length = bookmarks == null ? 0 : bookmarks.length; i < length; i++) {
85                         try {
86                                         if (bookmarks[i].isConnected() && !bookmarks[i].getConnection().getAutoCommit()) {
87                                                 MultiSQLServer.getInstance().rollback(bookmarks[i].getConnection());
88                                         }
89                     } catch (SQLException e) {
90                         ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e);
91                     } catch (NotConnectedException e) {
92                         ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e);
93                     }
94                         }
95                 }
96         }
97         
98         
99         private class CommitAction extends Action {
100                 public CommitAction() {
101                         setText(Messages.getString("SQLQueryView.Commit"));
102                         setToolTipText(Messages.getString("SQLQueryView.Commit"));
103                 }
104                 
105                 public void run() {
106                 Bookmark[] bookmarks = BookmarkCollection.getInstance().getBookmarks();
107                 for (int i = 0, length = bookmarks == null ? 0 : bookmarks.length; i < length; i++) {
108                         try {
109                                         if (bookmarks[i].isConnected() && !bookmarks[i].getConnection().getAutoCommit()) {
110                                                 MultiSQLServer.getInstance().commit(bookmarks[i].getConnection());
111                                         }
112                     } catch (SQLException e) {
113                         ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e);
114                     } catch (NotConnectedException e) {
115                         ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e);
116                     }
117                         }
118                 }
119         }
120         
121         
122         public class LabelProviderImpl implements ILabelProvider {
123                 public Image getImage(Object element) {
124                         return ImageStore.getImage(ImageStore.BOOKMARK);
125                 }
126                 public String getText(Object element) {
127                         if (element instanceof Bookmark) {
128                                 return ((Bookmark) element).getName();
129                         } else {
130                                 return null;
131                         }
132                 }
133                 public void addListener(ILabelProviderListener listener) {
134                 }
135                 public void dispose() {
136                 }
137                 public boolean isLabelProperty(Object element, String property) {
138                         return false;
139                 }
140                 public void removeListener(ILabelProviderListener listener) {
141                 }
142         }
143         public class ContentProviderImpl implements IStructuredContentProvider {
144                 public Object[] getElements(Object inputElement) {
145                         if (inputElement instanceof BookmarkCollection) {
146                                 return ((BookmarkCollection) inputElement).getBookmarks();
147                         } else {
148                                 return null;
149                         }
150                 }
151                 public void dispose() {
152                 }
153                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
154                 }
155         }
156         
157         private ExecuteAction executeAction;
158         private ImportQueryAction importQueryAction;
159         private ExportQueryAction exportQueryAction;
160         private StyledText widget;
161         private Color STRING_LITERAL;
162         private Color KEYWORD;
163         private Color COMMENT;
164         private Color NUMERIC;
165         private Color DEFAULT;
166         private AutoCommitPreferenceAction autoCommitPreferenceAction;
167         private RollbackAction rollbackAction;
168         private CommitAction commitAction;
169         private boolean autoCommitPreference = true;
170         
171         public SQLQueryView() {
172                 super();
173                 IPropertyChangeListener listener = new IPropertyChangeListener() {
174                         public void propertyChange(PropertyChangeEvent event) {
175                                 setFont();
176                         }
177                 };
178                 QuantumPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(listener);
179         }
180         public static SQLQueryView getInstance() {
181                 return (SQLQueryView) QuantumPlugin.getDefault().getView("com.quantum.view.sqlqueryview");
182
183         }
184
185         public void createPartControl(org.eclipse.swt.widgets.Composite parent) {
186                 initActions();
187                 
188                 initializeColours(parent);
189                 GridLayout layout = new GridLayout(1, false);
190                 layout.horizontalSpacing = 0;
191                 layout.verticalSpacing = 0;
192                 layout.marginHeight = 0;
193                 layout.marginWidth = 0;
194                 parent.setLayout(layout);
195                 parent.setLayoutData(new GridData(GridData.FILL_BOTH));
196                 
197                 widget = new StyledText(parent, SWT.H_SCROLL | SWT.V_SCROLL);
198                 
199                 setFont();
200
201                 IActionBars bars = this.getViewSite().getActionBars();
202                 bars.setGlobalActionHandler(IWorkbenchActionConstants.CUT, cutAction);
203                 bars.setGlobalActionHandler(IWorkbenchActionConstants.COPY, copyAction);
204                 bars.setGlobalActionHandler(IWorkbenchActionConstants.PASTE, pasteAction);
205                 bars.setGlobalActionHandler(IWorkbenchActionConstants.SELECT_ALL, selectAllAction);
206
207                 widget.setEditable(true);
208                 widget.addExtendedModifyListener(modifyListener);
209
210                 widget.setLayoutData(new GridData(GridData.FILL_BOTH));
211
212                 VersioningHelper.registerActionToKeyBindingService(getSite(), 
213                                 new String[] { "org.eclipse.ui.globalScope", "com.quantum.view.sql" }, 
214                         this.executeAction);
215         }
216
217         /**
218          * @param widget2
219          */
220         private void setFont() {
221                 FontData font = PreferenceConverter.getFontData(
222                                 QuantumPlugin.getDefault().getPreferenceStore(), 
223                                 "quantum.font"); //$NON-NLS-1$
224                 if (font != null && this.widget != null) {
225                         this.widget.setFont(new Font(Display.getCurrent(), font));
226                 }
227         }
228         /**
229          * @param parent
230          */
231         private void initializeColours(org.eclipse.swt.widgets.Composite parent) {
232                 KEYWORD = new Color(parent.getShell().getDisplay(), 126, 0, 75);
233                 STRING_LITERAL = new Color(parent.getShell().getDisplay(), 0, 0, 255);
234                 COMMENT = new Color(parent.getShell().getDisplay(), 88, 148, 64);
235                 NUMERIC = new Color(parent.getShell().getDisplay(), 255, 0, 0);
236             DEFAULT = new Color(parent.getShell().getDisplay(), 0, 0, 0);
237         }
238         
239         private void initActions() {
240
241                 IToolBarManager toolBar = getViewSite().getActionBars().getToolBarManager();
242
243                 executeAction = new ExecuteAction(this);
244                 toolBar.add(this.executeAction);
245                 toolBar.add(new ClearAction());
246                 
247         IActionBars actionBars = getViewSite().getActionBars();
248                 this.importQueryAction = new ImportQueryAction();
249                 this.importQueryAction.init(this);
250         actionBars.getMenuManager().add(this.importQueryAction);
251         this.exportQueryAction = new ExportQueryAction();
252         this.exportQueryAction.init(this);
253         actionBars.getMenuManager().add(this.exportQueryAction);
254         actionBars.getMenuManager().add(new Separator());
255         this.autoCommitPreferenceAction = new AutoCommitPreferenceAction();
256         this.autoCommitPreferenceAction.setChecked(this.autoCommitPreference);
257         actionBars.getMenuManager().add(this.autoCommitPreferenceAction);
258
259         this.rollbackAction = new RollbackAction();
260         actionBars.getMenuManager().add(this.rollbackAction);
261
262         this.commitAction = new CommitAction();
263         actionBars.getMenuManager().add(this.commitAction);
264 }
265
266         public String getQuery() {
267                 return widget.getText();
268         }
269         
270         public void setQuery(String text) {
271                 widget.setText(text);
272         }
273         
274         SyntaxHighlighter textUpdater = new SyntaxHighlighter();
275         
276         private class UpdateRequest {
277                 public UpdateRequest(String text, int start, int length) {
278                         this.text = text;
279                         this.start = start;
280                         this.length = length;
281                 }
282                 public String text;
283                 public int start;
284                 public int length;
285         }
286         
287         private class SyntaxHighlighter extends Thread {
288                 private boolean running = true;
289                 private LinkedList requests = new LinkedList();
290                 public SyntaxHighlighter() {
291                         super();
292                         setPriority(Thread.MIN_PRIORITY);
293                         start();
294                 }
295                 public synchronized void updateText(String text, int start, int length) {
296                         requests.add(new UpdateRequest(text, start, length));
297                         notify();
298                 }
299                 public synchronized void shutdown() {
300                         running = false;
301                         interrupt();
302                 }
303                 public void run() {
304                         while (running) {
305                                 try {
306                                         synchronized (this) {
307                                                 if (requests.size() <= 0) {
308                                                         wait();
309                                                 } else {
310                                                         Thread.sleep(10);
311                                                 }
312                                         }
313                                         UpdateRequest request = (UpdateRequest) requests.removeFirst();
314                                         String text = request.text.toUpperCase();
315                                         //int dirtyStart = request.start;
316                                         //int dirtyEnd = request.start + request.length;
317                                         StyleRange styleRange;
318                                         Vector tokens = SQLLexx.parse(text);
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                                                 if (true) { // Let's update the whole text, as some comment changes can alter everything
337                                                         min = Math.min(start, min);
338                                                         max = Math.max(max, start + length);
339                                                         if (t.getType() == Token.IDENTIFIER) {
340                                                                 boolean keyword = false;
341                                                                 for (int index = 0; index < SQLGrammar.KEYWORDS.length; index++) {
342                                                                         if (value.equals(SQLGrammar.KEYWORDS[index])) {
343                                                                                 keyword = true;
344                                                                         }
345                                                                 }
346                                                                 if (keyword) {
347                                                                         styleRange.fontStyle = SWT.BOLD;
348                                                                         styleRange.foreground = KEYWORD;
349                                                                 } else {
350                                                                         styleRange.foreground = DEFAULT;
351                                                                 }
352                                                                 styles.addElement(styleRange);
353                                                         } else if (t.getType() == Token.COMMENT) {
354                                                                 styleRange.foreground = COMMENT;
355                                                                 styles.addElement(styleRange);
356                                                         } else if (t.getType() == Token.LITERAL) {
357                                                                 styleRange.foreground = STRING_LITERAL;
358                                                                 styles.addElement(styleRange);
359                                                         } else if (t.getType() == Token.NUMERIC) {
360                                                                 styleRange.foreground = NUMERIC;
361                                                                 styles.addElement(styleRange);
362                                                         } else {
363                                                                 styles.addElement(styleRange);
364                                                         }
365                                                 }
366                                         }
367                                         StyleRange[] ranges = new StyleRange[styles.size()];
368                                         for (int k = 0; k < ranges.length; k++) {
369                                                 ranges[k] = (StyleRange) styles.elementAt(k);
370                                         }
371                                         if (max >= 0 && ranges.length > 0) {
372                                                 setStyles(ranges, min, max - min);
373                                         }
374                                 } catch (NoSuchElementException e) {
375                                         // ignore a missing request
376                                 } catch (InterruptedException e) {
377                                         // ignore any interruptions
378                                 }
379                         }
380                 }
381         }
382         public void setStyles(final StyleRange[] styles, final int start, final int length) {
383                 getViewSite().getShell().getDisplay().asyncExec(new Runnable() {
384                         public void run() {
385                                 try {
386                                         for (int i = 0; i < styles.length; i++) {
387                                                 widget.setStyleRange(styles[i]);
388                                         }
389                                 } catch (Throwable t) {
390                                         System.out.println("Error with styles: " + t.getClass().toString()); //$NON-NLS-1$
391                                         // ignore any errors
392                                 }
393                         }
394                 });
395         }
396         
397         ExtendedModifyListener modifyListener = new ExtendedModifyListener() {
398                 public void modifyText(ExtendedModifyEvent event) {
399                         textUpdater.updateText(getQuery(), event.start, event.length);
400                 }
401         };
402                 
403         private Action cutAction = new Action() {
404                 public void run() {
405                         widget.cut();
406                 }
407         };
408         private Action copyAction = new Action() {
409                 public void run() {
410                         widget.copy();
411                 }
412         };
413         private Action pasteAction = new Action() {
414                 public void run() {
415                         widget.paste();
416                 }
417         };
418         private Action selectAllAction = new Action() {
419                 public void run() {
420                         widget.selectAll();
421                 }
422         };
423
424         public void setFocus() {
425         }
426         public boolean isAutoCommitPreference() {
427                 return this.autoCommitPreference;
428         }
429         public void setAutoCommitPreference(boolean autoCommitPreference) {
430                 this.autoCommitPreference = autoCommitPreference;
431         }
432 }