001: /*
002: * The contents of this file are subject to the Mozilla Public License
003: * Version 1.1 (the "License"); you may not use this file except in
004: * compliance with the License. You may obtain a copy of the License at
005: * http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
009: * License for the specific language governing rights and limitations
010: * under the License.
011: *
012: * The Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
013: *
014: * The Initial Developer of the Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
015: * Portions created by Mark A. Kobold are Copyright (C) 2000-2007. All Rights Reserved.
016: *
017: * Contributor(s):
018: * Mark A. Kobold [mkobold <at> isqlviewer <dot> com].
019: *
020: * If you didn't download this code from the following link, you should check
021: * if you aren't using an obsolete version: http://www.isqlviewer.com
022: */
023: package org.isqlviewer.ui;
024:
025: import java.awt.BorderLayout;
026: import java.awt.GridBagConstraints;
027: import java.awt.GridBagLayout;
028: import java.awt.dnd.DnDConstants;
029: import java.awt.dnd.DropTarget;
030: import java.awt.event.ActionEvent;
031: import java.awt.event.FocusEvent;
032: import java.awt.event.FocusListener;
033: import java.awt.event.KeyEvent;
034: import java.sql.Connection;
035: import java.sql.DatabaseMetaData;
036: import java.sql.SQLException;
037: import java.util.prefs.Preferences;
038:
039: import javax.swing.AbstractAction;
040: import javax.swing.Action;
041: import javax.swing.BorderFactory;
042: import javax.swing.Box;
043: import javax.swing.JComponent;
044: import javax.swing.JLabel;
045: import javax.swing.JMenuBar;
046: import javax.swing.JPanel;
047: import javax.swing.JScrollPane;
048: import javax.swing.KeyStroke;
049: import javax.swing.SwingConstants;
050: import javax.swing.border.Border;
051: import javax.swing.event.CaretEvent;
052: import javax.swing.event.CaretListener;
053: import javax.swing.event.DocumentListener;
054: import javax.swing.event.HyperlinkEvent;
055: import javax.swing.event.HyperlinkListener;
056: import javax.swing.event.UndoableEditEvent;
057: import javax.swing.event.UndoableEditListener;
058: import javax.swing.text.BadLocationException;
059: import javax.swing.text.JTextComponent;
060: import javax.swing.text.Keymap;
061: import javax.swing.undo.UndoManager;
062: import javax.swing.undo.UndoableEdit;
063:
064: import org.isqlviewer.sql.JdbcService;
065: import org.isqlviewer.sql.processor.SqlProcessor;
066: import org.isqlviewer.swing.SwingUtilities;
067: import org.isqlviewer.swing.action.CustomAction;
068: import org.isqlviewer.swing.action.OverwriteToggleAction;
069: import org.isqlviewer.swing.action.SharedActions;
070: import org.isqlviewer.swing.action.SwingEventManager;
071: import org.isqlviewer.swing.text.SyntaxHighlighter;
072: import org.isqlviewer.ui.dnd.TextComponentDropTarget;
073:
074: /**
075: * @author Mark A. Kobold <mkobold at isqlviewer dot com>
076: * @version 1.0
077: */
078: public class SqlCommandEditor extends AbstractApplicationView implements
079: CaretListener, FocusListener, UndoableEditListener,
080: HyperlinkListener {
081:
082: private SqlProcessor sqlProcessor = new SqlProcessor();
083: private SyntaxHighlighter commandEditor = new SyntaxHighlighter(
084: 320, 240, sqlProcessor);
085: private JLabel labelCaretPosition = new JLabel();
086: private JLabel labelEditMode = new JLabel();
087: private UndoManager undoManager = new UndoManager();
088: private boolean executable = false;
089:
090: public SqlCommandEditor() {
091:
092: this (false);
093: }
094:
095: public SqlCommandEditor(boolean executable) {
096:
097: this .executable = executable;
098: }
099:
100: public void doLayout(JComponent parentComponent,
101: Preferences preferences, SwingEventManager eventManager) {
102:
103: parentComponent.setLayout(new BorderLayout());
104: parentComponent.add(new JScrollPane(commandEditor),
105: BorderLayout.CENTER);
106: parentComponent.add(createStatusBar(), BorderLayout.SOUTH);
107: Keymap map = commandEditor.getKeymap();
108: KeyStroke ks = null;
109: int eventMask = 0;
110:
111: Action a = new OverwriteToggleAction(eventManager);
112: if (SwingUtilities.isMacOS()) {
113: ks = KeyStroke.getKeyStroke(KeyEvent.VK_I,
114: SwingUtilities.MENU_SHORTCUT_MASK, true);
115: map.addActionForKeyStroke(ks, a);
116: } else {
117: ks = KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0, false);
118: map.addActionForKeyStroke(ks, a);
119: }
120:
121: if (executable) {
122: a = new CustomAction("execute-sql-command",
123: SharedActions.EXECUTE_SQL_COMMAND, eventManager);
124: eventMask = SwingUtilities.MENU_SHORTCUT_MASK;
125: ks = SwingUtilities.createKeyStroke(KeyEvent.VK_ENTER,
126: eventMask);
127: a = new TextCommandAction(eventManager, commandEditor);
128: map.addActionForKeyStroke(ks, a);
129:
130: eventMask = 0;
131: ks = SwingUtilities.createKeyStroke(KeyEvent.VK_F9,
132: eventMask);
133: map.addActionForKeyStroke(ks, a);
134:
135: eventMask = KeyEvent.SHIFT_DOWN_MASK;
136: ks = SwingUtilities.createKeyStroke(KeyEvent.VK_F9,
137: eventMask);
138: a = new ContextExecutionAction(eventManager, commandEditor);
139: map.addActionForKeyStroke(ks, a);
140:
141: SqlCommandMouseAdapter adapter = new SqlCommandMouseAdapter();
142:
143: commandEditor.addMouseMotionListener(adapter);
144: commandEditor.addMouseListener(adapter);
145: commandEditor.addHyperlinkListener(this );
146: }
147: }
148:
149: public void configureMenubar(JMenuBar menuBar) {
150:
151: }
152:
153: public void initializeView() {
154:
155: commandEditor.addFocusListener(this );
156: commandEditor.addCaretListener(this );
157:
158: DropTarget dropTarget = new TextComponentDropTarget(
159: commandEditor);
160: dropTarget.setActive(true);
161: dropTarget.setDefaultActions(DnDConstants.ACTION_COPY_OR_MOVE);
162: commandEditor.setDropTarget(dropTarget);
163:
164: commandEditor.setDragEnabled(true);
165: commandEditor.getDocument().addUndoableEditListener(this );
166: localizeTextComponent(commandEditor, undoManager);
167: }
168:
169: public void disposeView(Preferences preferences) {
170:
171: }
172:
173: public void focusGained(FocusEvent e) {
174:
175: caretUpdate(null);
176: }
177:
178: public void focusLost(FocusEvent e) {
179:
180: }
181:
182: public void caretUpdate(CaretEvent e) {
183:
184: Object src = (e == null ? commandEditor : e.getSource());
185: int dot = (e == null ? commandEditor.getCaretPosition() : e
186: .getDot());
187:
188: int row = 0;
189: int column = 0;
190: if (src == commandEditor) {
191: try {
192: row = SwingUtilities.getCaretRow(dot, commandEditor) + 1;
193: } catch (BadLocationException e1) {
194: row = -1;
195: }
196: try {
197: column = SwingUtilities.getCaretCol(dot, commandEditor) + 1;
198: } catch (BadLocationException e1) {
199: column = -1;
200: }
201: String str = " " + row + " : " + column + "[" + dot + "]";
202: labelCaretPosition.setText(str);
203: }
204: }
205:
206: public void undoableEditHappened(UndoableEditEvent e) {
207:
208: if (e == null || e.getEdit() == null) {
209: return;
210: }
211: UndoableEdit edit = e.getEdit();
212: String editName = edit.getPresentationName();
213: if (editName.startsWith("style")) {
214: return;
215: }
216: undoManager.addEdit(e.getEdit());
217: }
218:
219: public void hyperlinkUpdate(HyperlinkEvent e) {
220:
221: }
222:
223: public void updateServiceKeywords(JdbcService service,
224: String catalog, String schema) throws SQLException {
225:
226: Connection connection = service.getConnection();
227: DatabaseMetaData metaData = connection.getMetaData();
228: sqlProcessor.installServiceKeywords(metaData, catalog, schema);
229: commandEditor.setText(commandEditor.getText());
230: }
231:
232: public String getText() {
233:
234: return commandEditor.getText();
235: }
236:
237: public void setText(String commandText) {
238:
239: commandEditor.setText(commandText);
240: }
241:
242: public void addDocumentListener(DocumentListener listener) {
243:
244: commandEditor.getDocument().addDocumentListener(listener);
245: }
246:
247: private JComponent createStatusBar() {
248:
249: JPanel bar = new JPanel(new GridBagLayout());
250: Border bdr = BorderFactory.createEtchedBorder();
251: labelCaretPosition.setBorder(bdr);
252: labelEditMode.setBorder(bdr);
253:
254: labelCaretPosition.setVerticalAlignment(SwingConstants.CENTER);
255: labelEditMode.setVerticalAlignment(SwingConstants.CENTER);
256: labelCaretPosition
257: .setHorizontalAlignment(SwingConstants.CENTER);
258: labelEditMode.setHorizontalAlignment(SwingConstants.CENTER);
259:
260: Object constraint = null;
261:
262: constraint = constrain(0, 0, 1, 1, 1, 0,
263: GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL);
264: bar.add(Box.createHorizontalGlue(), constraint);
265:
266: constraint = constrain(1, 0, 1, 1, 0, 0,
267: GridBagConstraints.WEST, GridBagConstraints.NONE);
268: bar.add(labelEditMode, constraint);
269:
270: constraint = constrain(2, 0, 1, 1, 0, 0,
271: GridBagConstraints.WEST, GridBagConstraints.NONE);
272: bar.add(Box.createHorizontalStrut(2), constraint);
273:
274: constraint = constrain(3, 0, 1, 1, 0, 0,
275: GridBagConstraints.WEST, GridBagConstraints.NONE);
276: bar.add(labelCaretPosition, constraint);
277: return bar;
278: }
279:
280: private static class ContextExecutionAction extends AbstractAction {
281:
282: private static final long serialVersionUID = 6166961766823737471L;
283: private SwingEventManager eventManager = null;
284: private JTextComponent textComponent = null;
285:
286: public ContextExecutionAction(SwingEventManager eventManager,
287: JTextComponent textComponent) {
288:
289: this .eventManager = eventManager;
290: this .textComponent = textComponent;
291: }
292:
293: public void actionPerformed(ActionEvent event) {
294:
295: String text = textComponent.getText();
296: int currentLocation = Math.min(text.length() - 1,
297: textComponent.getCaretPosition());
298: currentLocation = Math.max(0, currentLocation);
299:
300: int fromIndex = 0;
301: int toIndex = text.length() - 1;
302: char previousCharacter = 0;
303: for (int i = currentLocation; i >= 0; i--) {
304: char c = text.charAt(i);
305: if (c == '\n' && previousCharacter == '\n') {
306: fromIndex = i;
307: break;
308: }
309: previousCharacter = c;
310: }
311: previousCharacter = 0;
312: boolean found = false;
313: for (int i = currentLocation; i < toIndex; i++) {
314: char c = text.charAt(i);
315: if (c == '\n' && previousCharacter == '\n') {
316: toIndex = i;
317: found = true;
318: break;
319: }
320: previousCharacter = c;
321: }
322: if (!found) {
323: toIndex = text.length();
324: }
325: Object source = event.getSource();
326: String contextQuery = text.substring(fromIndex, toIndex)
327: .trim();
328: if (contextQuery.length() == 0) {
329: SwingUtilities.beep();
330: return;
331: }
332: ActionEvent proxiedEvent = new ActionEvent(source,
333: SharedActions.EXECUTE_SQL_COMMAND, contextQuery);
334: eventManager.actionPerformed(proxiedEvent);
335: }
336: }
337:
338: private static class TextCommandAction extends AbstractAction {
339:
340: private static final long serialVersionUID = 3595177463415569695L;
341: private SwingEventManager eventManager = null;
342: private JTextComponent textComponent = null;
343:
344: public TextCommandAction(SwingEventManager eventManager,
345: JTextComponent textComponent) {
346:
347: this .eventManager = eventManager;
348: this .textComponent = textComponent;
349: }
350:
351: public void actionPerformed(ActionEvent event) {
352:
353: Object source = event.getSource();
354: String commandText = textComponent.getText();
355: String currentSelection = textComponent.getSelectedText();
356:
357: if (currentSelection != null
358: && currentSelection.trim().length() > 0) {
359: ActionEvent proxiedEvent = new ActionEvent(source,
360: SharedActions.EXECUTE_SQL_COMMAND,
361: currentSelection);
362: eventManager.actionPerformed(proxiedEvent);
363: } else {
364: ActionEvent proxiedEvent = new ActionEvent(source,
365: SharedActions.EXECUTE_SQL_COMMAND, commandText);
366: eventManager.actionPerformed(proxiedEvent);
367: }
368: }
369: }
370:
371: }
|