1 package com.quantum.view;
3 import java.sql.SQLException;
4 import java.util.ArrayList;
5 import java.util.LinkedList;
7 import java.util.NoSuchElementException;
8 import java.util.Vector;
10 import com.quantum.ImageStore;
11 import com.quantum.Messages;
12 import com.quantum.PluginPreferences;
13 import com.quantum.QuantumPlugin;
14 import com.quantum.actions.ExecuteAction;
15 import com.quantum.actions.ExportQueryAction;
16 import com.quantum.actions.ImportQueryAction;
17 import com.quantum.editors.ColorManager;
18 import com.quantum.model.Bookmark;
19 import com.quantum.model.BookmarkCollection;
20 import com.quantum.model.NotConnectedException;
21 import com.quantum.sql.MultiSQLServer;
22 import com.quantum.sql.SQLGrammar;
23 import com.quantum.sql.parser.SQLLexx;
24 import com.quantum.sql.parser.Token;
25 import com.quantum.ui.dialog.ExceptionDisplayDialog;
26 import com.quantum.ui.dialog.SQLExceptionDialog;
27 import com.quantum.util.versioning.VersioningHelper;
29 import org.eclipse.jface.action.Action;
30 import org.eclipse.jface.action.IToolBarManager;
31 import org.eclipse.jface.action.Separator;
32 import org.eclipse.jface.preference.IPreferenceStore;
33 import org.eclipse.jface.preference.PreferenceConverter;
34 import org.eclipse.jface.util.IPropertyChangeListener;
35 import org.eclipse.jface.util.PropertyChangeEvent;
36 import org.eclipse.jface.viewers.ILabelProvider;
37 import org.eclipse.jface.viewers.ILabelProviderListener;
38 import org.eclipse.jface.viewers.IStructuredContentProvider;
39 import org.eclipse.jface.viewers.Viewer;
40 import org.eclipse.swt.SWT;
41 import org.eclipse.swt.custom.ExtendedModifyEvent;
42 import org.eclipse.swt.custom.ExtendedModifyListener;
43 import org.eclipse.swt.custom.StyleRange;
44 import org.eclipse.swt.custom.StyledText;
45 import org.eclipse.swt.dnd.Clipboard;
46 import org.eclipse.swt.dnd.TransferData;
47 import org.eclipse.swt.graphics.Color;
48 import org.eclipse.swt.graphics.Font;
49 import org.eclipse.swt.graphics.FontData;
50 import org.eclipse.swt.graphics.Image;
51 import org.eclipse.swt.layout.GridData;
52 import org.eclipse.swt.layout.GridLayout;
53 import org.eclipse.swt.widgets.Composite;
54 import org.eclipse.swt.widgets.Display;
55 import org.eclipse.ui.IActionBars;
56 import org.eclipse.ui.IWorkbenchActionConstants;
57 import org.eclipse.ui.part.ViewPart;
59 public class SQLQueryView extends ViewPart {
60 private class ClearAction extends Action {
62 public ClearAction() {
63 setImageDescriptor(ImageStore.getImageDescriptor(ImageStore.CLEAR));
64 setToolTipText(Messages.getString("sqlqueryview.clear"));
72 private class AutoCommitPreferenceAction extends Action {
74 public AutoCommitPreferenceAction() {
75 super(Messages.getString("SQLQueryView.AutoCommit"));
76 setToolTipText(Messages.getString("SQLQueryView.AutoCommit"));
77 setImageDescriptor(ImageStore.getImageDescriptor(ImageStore.AUTOCOMMIT));
81 setAutoCommitPreference(isChecked());
85 private class RollbackAction extends Action {
86 public RollbackAction() {
87 setText(Messages.getString("SQLQueryView.RollBack"));
88 setToolTipText(Messages.getString("SQLQueryView.RollBack"));
92 Bookmark[] bookmarks = BookmarkCollection.getInstance().getBookmarks();
93 for (int i = 0, length = bookmarks == null ? 0 : bookmarks.length; i < length; i++) {
95 if (bookmarks[i].isConnected() && !bookmarks[i].getConnection().getAutoCommit()) {
96 MultiSQLServer.getInstance().rollback(bookmarks[i].getConnection());
98 } catch (SQLException e) {
99 SQLExceptionDialog.openException(getSite().getShell(), bookmarks[i], e);
100 } catch (NotConnectedException e) {
101 ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e);
108 private class CommitAction extends Action {
109 public CommitAction() {
110 setText(Messages.getString("SQLQueryView.Commit"));
111 setToolTipText(Messages.getString("SQLQueryView.Commit"));
115 Bookmark[] bookmarks = BookmarkCollection.getInstance().getBookmarks();
116 for (int i = 0, length = bookmarks == null ? 0 : bookmarks.length; i < length; i++) {
118 if (bookmarks[i].isConnected() && !bookmarks[i].getConnection().getAutoCommit()) {
119 MultiSQLServer.getInstance().commit(bookmarks[i].getConnection());
121 } catch (SQLException e) {
122 SQLExceptionDialog.openException(getSite().getShell(), bookmarks[i], e);
123 } catch (NotConnectedException e) {
124 ExceptionDisplayDialog.openError(getSite().getShell(), null, null, e);
131 public class LabelProviderImpl implements ILabelProvider {
132 public Image getImage(Object element) {
133 return ImageStore.getImage(ImageStore.BOOKMARK);
135 public String getText(Object element) {
136 if (element instanceof Bookmark) {
137 return ((Bookmark) element).getName();
142 public void addListener(ILabelProviderListener listener) {
144 public void dispose() {
146 public boolean isLabelProperty(Object element, String property) {
149 public void removeListener(ILabelProviderListener listener) {
152 public class ContentProviderImpl implements IStructuredContentProvider {
153 public Object[] getElements(Object inputElement) {
154 if (inputElement instanceof BookmarkCollection) {
155 return ((BookmarkCollection) inputElement).getBookmarks();
160 public void dispose() {
162 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
166 private ExecuteAction executeAction;
167 private ImportQueryAction importQueryAction;
168 private ExportQueryAction exportQueryAction;
169 private StyledText widget;
170 private AutoCommitPreferenceAction autoCommitPreferenceAction;
171 private RollbackAction rollbackAction;
172 private CommitAction commitAction;
173 private boolean autoCommitPreference = true;
174 private IPropertyChangeListener listener;
175 private ColorManager colorManager = new ColorManager();
177 private SyntaxHighlighter textUpdater = new SyntaxHighlighter(this.colorManager);
180 public SQLQueryView() {
182 this.listener = new IPropertyChangeListener() {
183 public void propertyChange(PropertyChangeEvent event) {
187 QuantumPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(listener);
190 public void dispose() {
191 QuantumPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this.listener);
192 this.colorManager.dispose();
196 public static SQLQueryView getInstance() {
197 return (SQLQueryView) QuantumPlugin.getDefault().getView("com.quantum.view.sqlqueryview");
201 public void createPartControl(org.eclipse.swt.widgets.Composite parent) {
204 initializeColours(parent);
205 GridLayout layout = new GridLayout(1, false);
206 layout.horizontalSpacing = 0;
207 layout.verticalSpacing = 0;
208 layout.marginHeight = 0;
209 layout.marginWidth = 0;
210 parent.setLayout(layout);
211 parent.setLayoutData(new GridData(GridData.FILL_BOTH));
213 widget = new StyledText(parent, SWT.H_SCROLL | SWT.V_SCROLL);
217 IActionBars bars = this.getViewSite().getActionBars();
218 bars.setGlobalActionHandler(IWorkbenchActionConstants.CUT, cutAction);
219 bars.setGlobalActionHandler(IWorkbenchActionConstants.COPY, copyAction);
220 bars.setGlobalActionHandler(IWorkbenchActionConstants.PASTE, pasteAction);
221 bars.setGlobalActionHandler(IWorkbenchActionConstants.SELECT_ALL, selectAllAction);
223 widget.setEditable(true);
224 widget.addExtendedModifyListener(modifyListener);
226 widget.setLayoutData(new GridData(GridData.FILL_BOTH));
228 VersioningHelper.registerActionToKeyBindingService(getSite(),
229 new String[] { "org.eclipse.ui.globalScope", "com.quantum.view.sql" },
236 private void setFont() {
237 FontData font = PreferenceConverter.getFontData(
238 QuantumPlugin.getDefault().getPreferenceStore(),
239 "quantum.font"); //$NON-NLS-1$
240 if (font != null && this.widget != null) {
241 this.widget.setFont(new Font(Display.getCurrent(), font));
247 private void initializeColours(Composite parent) {
248 IPreferenceStore store = QuantumPlugin.getDefault().getPreferenceStore();
250 parent.setBackground(this.colorManager.getColor(
251 PreferenceConverter.getColor(store, PluginPreferences.BACKGROUND_COLOR)));
252 this.textUpdater.initializeColours();
255 private void initActions() {
257 IToolBarManager toolBar = getViewSite().getActionBars().getToolBarManager();
259 executeAction = new ExecuteAction(this);
260 toolBar.add(this.executeAction);
261 toolBar.add(new ClearAction());
263 IActionBars actionBars = getViewSite().getActionBars();
264 this.importQueryAction = new ImportQueryAction();
265 this.importQueryAction.init(this);
266 actionBars.getMenuManager().add(this.importQueryAction);
267 this.exportQueryAction = new ExportQueryAction();
268 this.exportQueryAction.init(this);
269 actionBars.getMenuManager().add(this.exportQueryAction);
270 actionBars.getMenuManager().add(new Separator());
271 this.autoCommitPreferenceAction = new AutoCommitPreferenceAction();
272 this.autoCommitPreferenceAction.setChecked(this.autoCommitPreference);
273 actionBars.getMenuManager().add(this.autoCommitPreferenceAction);
275 this.rollbackAction = new RollbackAction();
276 actionBars.getMenuManager().add(this.rollbackAction);
278 this.commitAction = new CommitAction();
279 actionBars.getMenuManager().add(this.commitAction);
282 public String getQuery() {
283 return widget.getText();
286 public void setQuery(String text) {
287 widget.setText(text);
290 private class UpdateRequest {
291 public UpdateRequest(String text, int start, int length) {
294 this.length = length;
301 private class SyntaxHighlighter extends Thread {
303 private Color STRING_LITERAL;
304 private Color KEYWORD;
305 private Color COMMENT;
306 private Color NUMERIC;
307 private Color DEFAULT;
309 private boolean running = true;
310 private LinkedList requests = new LinkedList();
311 private final ColorManager colorManager;
312 public SyntaxHighlighter(ColorManager colorManager) {
314 this.colorManager = colorManager;
316 setPriority(Thread.MIN_PRIORITY);
319 public void initializeColours() {
320 IPreferenceStore store = QuantumPlugin.getDefault().getPreferenceStore();
322 this.DEFAULT = this.colorManager.getColor(
323 PreferenceConverter.getColor(store, PluginPreferences.TEXT_COLOR));
324 this.KEYWORD = this.colorManager.getColor(
325 PreferenceConverter.getColor(store, PluginPreferences.KEYWORD_COLOR));
326 this.STRING_LITERAL = this.colorManager.getColor(
327 PreferenceConverter.getColor(store, PluginPreferences.STRING_COLOR));
328 this.COMMENT = this.colorManager.getColor(
329 PreferenceConverter.getColor(store, PluginPreferences.COMMENT_COLOR));
330 this.NUMERIC = this.colorManager.getColor(
331 PreferenceConverter.getColor(store, PluginPreferences.NUMERIC_COLOR));
334 public synchronized void updateText(String text, int start, int length) {
335 requests.add(new UpdateRequest(text, start, length));
341 synchronized (this) {
342 if (requests.size() <= 0) {
348 UpdateRequest request = (UpdateRequest) requests.removeFirst();
349 String text = request.text.toUpperCase();
350 //int dirtyStart = request.start;
351 //int dirtyEnd = request.start + request.length;
352 StyleRange styleRange;
353 List tokens = SQLLexx.parse(text);
354 List styles = new ArrayList();
355 int min = Integer.MAX_VALUE;
357 for (int i = 0; i < tokens.size(); i++) {
358 Token t = (Token) tokens.get(i);
359 String value = t.getValue();
360 int start = t.getStart();
361 int length = t.getEnd() - t.getStart();
362 styleRange = new StyleRange();
363 styleRange.start = start;
364 styleRange.length = value.length();
365 styleRange.fontStyle = SWT.NULL;
366 styleRange.foreground = DEFAULT;
367 //boolean upper = start <= dirtyEnd && start >= dirtyStart;
368 //boolean lower = ((start + length) >= dirtyStart && (start + length) <= dirtyEnd);
369 //boolean both = (start <= dirtyStart && (start + length) >= dirtyEnd);
370 //if (upper || lower || both) {
371 if (true) { // Let's update the whole text, as some comment changes can alter everything
372 min = Math.min(start, min);
373 max = Math.max(max, start + length);
374 if (t.getType() == Token.IDENTIFIER) {
375 boolean keyword = false;
376 for (int index = 0; index < SQLGrammar.KEYWORDS.length; index++) {
377 if (value.equals(SQLGrammar.KEYWORDS[index])) {
382 styleRange.fontStyle = SWT.BOLD;
383 styleRange.foreground = KEYWORD;
385 styleRange.foreground = DEFAULT;
387 styles.add(styleRange);
388 } else if (t.getType() == Token.COMMENT) {
389 styleRange.foreground = COMMENT;
390 styles.add(styleRange);
391 } else if (t.getType() == Token.LITERAL) {
392 styleRange.foreground = STRING_LITERAL;
393 styles.add(styleRange);
394 } else if (t.getType() == Token.NUMERIC) {
395 styleRange.foreground = NUMERIC;
396 styles.add(styleRange);
398 styles.add(styleRange);
402 StyleRange[] ranges =
403 (StyleRange[]) styles.toArray(new StyleRange[styles.size()]);
404 if (max >= 0 && ranges.length > 0) {
405 setStyles(ranges, min, max - min);
407 } catch (NoSuchElementException e) {
408 // ignore a missing request
409 } catch (InterruptedException e) {
410 // ignore any interruptions
415 public void setStyles(final StyleRange[] styles, final int start, final int length) {
416 getViewSite().getShell().getDisplay().asyncExec(new Runnable() {
419 for (int i = 0; i < styles.length; i++) {
420 widget.setStyleRange(styles[i]);
422 } catch (Throwable t) {
423 System.out.println("Error with styles: " + t.getClass().toString()); //$NON-NLS-1$
430 ExtendedModifyListener modifyListener = new ExtendedModifyListener() {
431 public void modifyText(ExtendedModifyEvent event) {
432 textUpdater.updateText(getQuery(), event.start, event.length);
436 private Action cutAction = new Action() {
441 private Action copyAction = new Action() {
446 private Action pasteAction = new Action() {
451 private Action selectAllAction = new Action() {
457 public void setFocus() {
459 public boolean isAutoCommitPreference() {
460 return this.autoCommitPreference;
462 public void setAutoCommitPreference(boolean autoCommitPreference) {
463 this.autoCommitPreference = autoCommitPreference;