1 package com.quantum.view;
3 import java.sql.SQLException;
4 import java.util.LinkedList;
5 import java.util.NoSuchElementException;
6 import java.util.Vector;
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;
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;
50 public class SQLQueryView extends ViewPart {
51 private class ClearAction extends Action {
53 public ClearAction() {
54 setImageDescriptor(ImageStore.getImageDescriptor(ImageStore.CLEAR));
55 setToolTipText(Messages.getString("sqlqueryview.clear"));
63 private class AutoCommitPreferenceAction extends Action {
65 public AutoCommitPreferenceAction() {
66 super(Messages.getString("SQLQueryView.AutoCommit"));
67 setToolTipText(Messages.getString("SQLQueryView.AutoCommit"));
68 setImageDescriptor(ImageStore.getImageDescriptor(ImageStore.AUTOCOMMIT));
72 setAutoCommitPreference(isChecked());
76 private class RollbackAction extends Action {
77 public RollbackAction() {
78 setText(Messages.getString("SQLQueryView.RollBack"));
79 setToolTipText(Messages.getString("SQLQueryView.RollBack"));
83 Bookmark[] bookmarks = BookmarkCollection.getInstance().getBookmarks();
84 for (int i = 0, length = bookmarks == null ? 0 : bookmarks.length; i < length; i++) {
86 if (bookmarks[i].isConnected() && !bookmarks[i].getConnection().getAutoCommit()) {
87 MultiSQLServer.getInstance().rollback(bookmarks[i].getConnection());
89 } catch (SQLException e) {
90 ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e);
91 } catch (NotConnectedException e) {
92 ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e);
99 private class CommitAction extends Action {
100 public CommitAction() {
101 setText(Messages.getString("SQLQueryView.Commit"));
102 setToolTipText(Messages.getString("SQLQueryView.Commit"));
106 Bookmark[] bookmarks = BookmarkCollection.getInstance().getBookmarks();
107 for (int i = 0, length = bookmarks == null ? 0 : bookmarks.length; i < length; i++) {
109 if (bookmarks[i].isConnected() && !bookmarks[i].getConnection().getAutoCommit()) {
110 MultiSQLServer.getInstance().commit(bookmarks[i].getConnection());
112 } catch (SQLException e) {
113 ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e);
114 } catch (NotConnectedException e) {
115 ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e);
122 public class LabelProviderImpl implements ILabelProvider {
123 public Image getImage(Object element) {
124 return ImageStore.getImage(ImageStore.BOOKMARK);
126 public String getText(Object element) {
127 if (element instanceof Bookmark) {
128 return ((Bookmark) element).getName();
133 public void addListener(ILabelProviderListener listener) {
135 public void dispose() {
137 public boolean isLabelProperty(Object element, String property) {
140 public void removeListener(ILabelProviderListener listener) {
143 public class ContentProviderImpl implements IStructuredContentProvider {
144 public Object[] getElements(Object inputElement) {
145 if (inputElement instanceof BookmarkCollection) {
146 return ((BookmarkCollection) inputElement).getBookmarks();
151 public void dispose() {
153 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
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;
171 public SQLQueryView() {
173 IPropertyChangeListener listener = new IPropertyChangeListener() {
174 public void propertyChange(PropertyChangeEvent event) {
178 QuantumPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(listener);
180 public static SQLQueryView getInstance() {
181 return (SQLQueryView) QuantumPlugin.getDefault().getView("com.quantum.view.sqlqueryview");
185 public void createPartControl(org.eclipse.swt.widgets.Composite parent) {
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));
197 widget = new StyledText(parent, SWT.H_SCROLL | SWT.V_SCROLL);
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);
207 widget.setEditable(true);
208 widget.addExtendedModifyListener(modifyListener);
210 widget.setLayoutData(new GridData(GridData.FILL_BOTH));
212 VersioningHelper.registerActionToKeyBindingService(getSite(),
213 new String[] { "org.eclipse.ui.globalScope", "com.quantum.view.sql" },
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));
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);
239 private void initActions() {
241 IToolBarManager toolBar = getViewSite().getActionBars().getToolBarManager();
243 executeAction = new ExecuteAction(this);
244 toolBar.add(this.executeAction);
245 toolBar.add(new ClearAction());
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);
259 this.rollbackAction = new RollbackAction();
260 actionBars.getMenuManager().add(this.rollbackAction);
262 this.commitAction = new CommitAction();
263 actionBars.getMenuManager().add(this.commitAction);
266 public String getQuery() {
267 return widget.getText();
270 public void setQuery(String text) {
271 widget.setText(text);
274 SyntaxHighlighter textUpdater = new SyntaxHighlighter();
276 private class UpdateRequest {
277 public UpdateRequest(String text, int start, int length) {
280 this.length = length;
287 private class SyntaxHighlighter extends Thread {
288 private boolean running = true;
289 private LinkedList requests = new LinkedList();
290 public SyntaxHighlighter() {
292 setPriority(Thread.MIN_PRIORITY);
295 public synchronized void updateText(String text, int start, int length) {
296 requests.add(new UpdateRequest(text, start, length));
299 public synchronized void shutdown() {
306 synchronized (this) {
307 if (requests.size() <= 0) {
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;
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])) {
347 styleRange.fontStyle = SWT.BOLD;
348 styleRange.foreground = KEYWORD;
350 styleRange.foreground = DEFAULT;
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);
363 styles.addElement(styleRange);
367 StyleRange[] ranges = new StyleRange[styles.size()];
368 for (int k = 0; k < ranges.length; k++) {
369 ranges[k] = (StyleRange) styles.elementAt(k);
371 if (max >= 0 && ranges.length > 0) {
372 setStyles(ranges, min, max - min);
374 } catch (NoSuchElementException e) {
375 // ignore a missing request
376 } catch (InterruptedException e) {
377 // ignore any interruptions
382 public void setStyles(final StyleRange[] styles, final int start, final int length) {
383 getViewSite().getShell().getDisplay().asyncExec(new Runnable() {
386 for (int i = 0; i < styles.length; i++) {
387 widget.setStyleRange(styles[i]);
389 } catch (Throwable t) {
390 System.out.println("Error with styles: " + t.getClass().toString()); //$NON-NLS-1$
397 ExtendedModifyListener modifyListener = new ExtendedModifyListener() {
398 public void modifyText(ExtendedModifyEvent event) {
399 textUpdater.updateText(getQuery(), event.start, event.length);
403 private Action cutAction = new Action() {
408 private Action copyAction = new Action() {
413 private Action pasteAction = new Action() {
418 private Action selectAllAction = new Action() {
424 public void setFocus() {
426 public boolean isAutoCommitPreference() {
427 return this.autoCommitPreference;
429 public void setAutoCommitPreference(boolean autoCommitPreference) {
430 this.autoCommitPreference = autoCommitPreference;