001: /*
002: * EditorPanel.java
003: *
004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
005: *
006: * Copyright 2002-2008, Thomas Kellerer
007: * No part of this code maybe reused without the permission of the author
008: *
009: * To contact the author please send an email to: support@sql-workbench.net
010: *
011: */
012: package workbench.gui.sql;
013:
014: import java.awt.Component;
015: import java.awt.EventQueue;
016: import java.awt.Font;
017: import java.awt.Window;
018: import java.awt.datatransfer.DataFlavor;
019: import java.awt.datatransfer.Transferable;
020: import java.awt.datatransfer.UnsupportedFlavorException;
021: import java.awt.dnd.DnDConstants;
022: import java.awt.dnd.DropTarget;
023: import java.awt.dnd.DropTargetListener;
024: import java.beans.PropertyChangeEvent;
025: import java.beans.PropertyChangeListener;
026: import java.io.BufferedReader;
027: import java.io.File;
028: import java.io.FileInputStream;
029: import java.io.IOException;
030: import java.io.InputStreamReader;
031: import java.io.UnsupportedEncodingException;
032: import java.io.Writer;
033: import java.util.Collection;
034: import java.util.Iterator;
035: import java.util.LinkedList;
036: import java.util.List;
037: import java.util.Set;
038: import javax.swing.BorderFactory;
039: import javax.swing.JComponent;
040: import javax.swing.JFileChooser;
041: import javax.swing.JOptionPane;
042: import javax.swing.SwingUtilities;
043: import javax.swing.border.Border;
044: import javax.swing.border.EmptyBorder;
045: import javax.swing.border.EtchedBorder;
046: import javax.swing.filechooser.FileFilter;
047: import javax.swing.text.BadLocationException;
048: import javax.swing.text.GapContent;
049: import workbench.WbManager;
050: import workbench.db.WbConnection;
051: import workbench.gui.actions.FileSaveAction;
052: import workbench.gui.editor.SearchAndReplace;
053: import workbench.gui.editor.SyntaxUtilities;
054: import workbench.gui.editor.TextFormatter;
055: import workbench.interfaces.EncodingSelector;
056: import workbench.sql.DelimiterDefinition;
057: import workbench.util.EncodingUtil;
058: import workbench.util.ExceptionUtil;
059: import workbench.gui.WbSwingUtilities;
060: import workbench.gui.actions.ColumnSelectionAction;
061: import workbench.gui.actions.CommentAction;
062: import workbench.gui.actions.FileOpenAction;
063: import workbench.gui.actions.FileReloadAction;
064: import workbench.gui.actions.FileSaveAsAction;
065: import workbench.gui.actions.FindAction;
066: import workbench.gui.actions.FindAgainAction;
067: import workbench.gui.actions.FormatSqlAction;
068: import workbench.gui.actions.MatchBracketAction;
069: import workbench.gui.actions.ReplaceAction;
070: import workbench.gui.actions.UnCommentAction;
071: import workbench.gui.actions.WbAction;
072: import workbench.gui.components.ExtensionFileFilter;
073: import workbench.gui.components.WbMenuItem;
074: import workbench.gui.editor.AnsiSQLTokenMarker;
075: import workbench.gui.editor.JEditTextArea;
076: import workbench.gui.editor.SyntaxDocument;
077: import workbench.gui.editor.TokenMarker;
078: import workbench.interfaces.ClipboardSupport;
079: import workbench.interfaces.FilenameChangeListener;
080: import workbench.interfaces.FontChangedListener;
081: import workbench.interfaces.FormattableSql;
082: import workbench.interfaces.TextContainer;
083: import workbench.interfaces.TextFileContainer;
084: import workbench.log.LogMgr;
085: import workbench.resource.ResourceMgr;
086: import workbench.resource.Settings;
087: import workbench.util.FileUtil;
088: import workbench.util.StringUtil;
089:
090: /**
091: * An extension to {@link workbench.gui.editor.JEditTextArea}. This class
092: * implements Workbench (SQL) specific extensions to the original jEdit class.
093: *
094: * @see workbench.gui.editor.JEditTextArea
095: *
096: * @author support@sql-workbench.net
097: */
098: public class EditorPanel extends JEditTextArea implements
099: ClipboardSupport, FontChangedListener, PropertyChangeListener,
100: DropTargetListener, TextContainer, TextFileContainer,
101: FormattableSql {
102: private static final Border DEFAULT_BORDER = BorderFactory
103: .createEtchedBorder(EtchedBorder.LOWERED);
104: private AnsiSQLTokenMarker sqlTokenMarker;
105: private static final int SQL_EDITOR = 0;
106: private static final int TEXT_EDITOR = 1;
107: private int editorType;
108: private String lastSearchCriteria;
109:
110: private FormatSqlAction formatSql;
111: private SearchAndReplace replacer;
112:
113: protected FileOpenAction fileOpen;
114: protected FileSaveAsAction fileSaveAs;
115:
116: protected FileSaveAction fileSave;
117: protected FileReloadAction fileReloadAction;
118:
119: private ColumnSelectionAction columnSelection;
120: private MatchBracketAction matchBracket;
121: private CommentAction commentAction;
122: private UnCommentAction unCommentAction;
123:
124: private List<FilenameChangeListener> filenameChangeListeners;
125: private File currentFile;
126: private String fileEncoding;
127: private Set<String> dbFunctions = null;
128: private Set<String> dbDatatypes = null;
129: private boolean isMySQL = false;
130: private DelimiterDefinition alternateDelimiter;
131:
132: public static EditorPanel createSqlEditor() {
133: AnsiSQLTokenMarker sql = new AnsiSQLTokenMarker();
134: EditorPanel p = new EditorPanel(sql);
135: p.editorType = SQL_EDITOR;
136: p.sqlTokenMarker = sql;
137: return p;
138: }
139:
140: public static EditorPanel createTextEditor() {
141: EditorPanel p = new EditorPanel(null);
142: p.editorType = TEXT_EDITOR;
143: return p;
144: }
145:
146: public EditorPanel(TokenMarker aMarker) {
147: super ();
148: this .setDoubleBuffered(true);
149: this .setFont(Settings.getInstance().getEditorFont());
150: this .setBorder(DEFAULT_BORDER);
151:
152: this .getPainter().setStyles(
153: SyntaxUtilities.getDefaultSyntaxStyles());
154:
155: this .setTabSize(Settings.getInstance().getEditorTabWidth());
156: this .setCaretBlinkEnabled(true);
157: this .fileSave = new FileSaveAction(this );
158: this .fileSaveAs = new FileSaveAsAction(this );
159: this .addPopupMenuItem(fileSaveAs, true);
160: this .fileOpen = new FileOpenAction(this );
161: this .addPopupMenuItem(this .fileOpen, false);
162:
163: this .fileReloadAction = new FileReloadAction(this );
164: this .fileReloadAction.setEnabled(false);
165:
166: this .replacer = new SearchAndReplace(this , this );
167: this .addKeyBinding(this .getFindAction());
168: this .addKeyBinding(this .getFindAgainAction());
169: this .addKeyBinding(this .getReplaceAction());
170:
171: if (aMarker != null)
172: this .setTokenMarker(aMarker);
173:
174: this .setMaximumSize(null);
175: this .setPreferredSize(null);
176: this .setShowLineNumbers(Settings.getInstance()
177: .getShowLineNumbers());
178:
179: this .columnSelection = new ColumnSelectionAction(this );
180: this .matchBracket = new MatchBracketAction(this );
181: this .addKeyBinding(this .matchBracket);
182:
183: this .commentAction = new CommentAction(this );
184: this .unCommentAction = new UnCommentAction(this );
185: this .addKeyBinding(this .commentAction);
186: this .addKeyBinding(this .unCommentAction);
187:
188: Settings.getInstance().addFontChangedListener(this );
189: Settings.getInstance().addPropertyChangeListener(this ,
190: Settings.PROPERTY_SHOW_LINE_NUMBERS,
191: Settings.PROPERTY_EDITOR_TAB_WIDTH,
192: Settings.PROPERTY_EDITOR_ELECTRIC_SCROLL);
193: this .setRightClickMovesCursor(Settings.getInstance()
194: .getRightClickMovesCursor());
195: new DropTarget(this , DnDConstants.ACTION_COPY, this );
196: }
197:
198: public void disableSqlHighlight() {
199: // this.sqlTokenMarker = null;
200: this .setTokenMarker(null);
201: }
202:
203: public void enableSqlHighlight() {
204: if (this .sqlTokenMarker == null) {
205: this .sqlTokenMarker = new AnsiSQLTokenMarker();
206: }
207: this .setTokenMarker(this .sqlTokenMarker);
208: }
209:
210: public void setDatabaseConnection(WbConnection aConnection) {
211: if (aConnection == null) {
212: this .alternateDelimiter = Settings.getInstance()
213: .getAlternateDelimiter();
214: return;
215: }
216: AnsiSQLTokenMarker token = this .getSqlTokenMarker();
217: this .dbFunctions = aConnection.getMetadata().getDbFunctions();
218: this .dbDatatypes = aConnection.getMetadata().getDbDataTypes();
219:
220: if (token != null) {
221: token.initKeywordMap(); // reset keywords, to get rid of old DBMS specific ones
222:
223: Collection<String> keywords = aConnection.getMetadata()
224: .getSqlKeywords();
225: token.setSqlKeyWords(keywords);
226: token.setSqlFunctions(this .dbFunctions);
227:
228: String key = "workbench.db."
229: + aConnection.getMetadata().getDbId() + ".syntax.";
230:
231: List<String> addKeys = StringUtil.stringToList(Settings
232: .getInstance().getProperty(key + "functions", ""),
233: ",", true, true);
234: token.setSqlFunctions(addKeys);
235: this .isMySQL = aConnection.getMetadata().isMySql();
236: token.setIsMySQL(isMySQL);
237: }
238:
239: this .commentChar = "--";
240:
241: if (aConnection.getMetadata().isMySql()
242: && Settings.getInstance().getBoolProperty(
243: "workbench.editor.mysql.usehashcomment", false)) {
244: this .commentChar = "#";
245: }
246:
247: this .alternateDelimiter = Settings.getInstance()
248: .getAlternateDelimiter(aConnection);
249: }
250:
251: public void fontChanged(String aKey, Font aFont) {
252: if (aKey.equals(Settings.PROPERTY_EDITOR_FONT)) {
253: this .setFont(aFont);
254: }
255: }
256:
257: public AnsiSQLTokenMarker getSqlTokenMarker() {
258: TokenMarker marker = this .getTokenMarker();
259: if (marker instanceof AnsiSQLTokenMarker) {
260: return (AnsiSQLTokenMarker) marker;
261: }
262: return null;
263: }
264:
265: public void showFindOnPopupMenu() {
266: this .addPopupMenuItem(this .getFindAction(), true);
267: this .addPopupMenuItem(this .getFindAgainAction(), false);
268: this .addPopupMenuItem(this .getReplaceAction(), false);
269: }
270:
271: public MatchBracketAction getMatchBracketAction() {
272: return this .matchBracket;
273: }
274:
275: public ColumnSelectionAction getColumnSelection() {
276: return this .columnSelection;
277: }
278:
279: protected FindAction getFindAction() {
280: return this .replacer.getFindAction();
281: }
282:
283: protected FindAgainAction getFindAgainAction() {
284: return this .replacer.getFindAgainAction();
285: }
286:
287: protected ReplaceAction getReplaceAction() {
288: return this .replacer.getReplaceAction();
289: }
290:
291: public SearchAndReplace getReplacer() {
292: return this .replacer;
293: }
294:
295: public FileSaveAction getFileSaveAction() {
296: return this .fileSave;
297: }
298:
299: public FileSaveAsAction getFileSaveAsAction() {
300: return this .fileSaveAs;
301: }
302:
303: public FormatSqlAction getFormatSqlAction() {
304: return this .formatSql;
305: }
306:
307: public FileReloadAction getReloadAction() {
308: return this .fileReloadAction;
309: }
310:
311: public FileOpenAction getFileOpenAction() {
312: return this .fileOpen;
313: }
314:
315: public void showFormatSql() {
316: if (this .formatSql != null)
317: return;
318: this .formatSql = new FormatSqlAction(this );
319: this .addKeyBinding(this .formatSql);
320: this .addPopupMenuItem(this .formatSql, true);
321: }
322:
323: public void setEditable(boolean editable) {
324: super .setEditable(editable);
325: this .getReplaceAction().setEnabled(editable);
326: this .fileOpen.setEnabled(editable);
327: if (!editable) {
328: Component[] c = this .popup.getComponents();
329: for (int i = 0; i < c.length; i++) {
330: if (c[i] instanceof WbMenuItem) {
331: WbMenuItem menu = (WbMenuItem) c[i];
332: if (menu.getAction() == fileOpen) {
333: popup.remove(c[i]);
334: return;
335: }
336: }
337: }
338: }
339: }
340:
341: public void reformatSql() {
342: TextFormatter f = new TextFormatter();
343: f.formatSql(this , alternateDelimiter, dbFunctions, dbDatatypes,
344: isMySQL ? "#" : "--");
345: }
346:
347: /**
348: * Enable column selection for the next selection.
349: */
350: public void enableColumnSelection() {
351: this .setSelectionRectangular(true);
352: }
353:
354: public void addPopupMenuItem(WbAction anAction,
355: boolean withSeparator) {
356: if (withSeparator) {
357: this .popup.addSeparator();
358: }
359: this .popup.add(anAction.getMenuItem());
360: this .addKeyBinding(anAction);
361: }
362:
363: public void dispose() {
364: Settings.getInstance().removeFontChangedListener(this );
365: Settings.getInstance().removePropertyChangeListener(this );
366: this .clearUndoBuffer();
367: this .popup.removeAll();
368: this .popup = null;
369: this .stopBlinkTimer();
370: this .painter.dispose();
371: this .setDocument(new SyntaxDocument());
372: }
373:
374: /**
375: * Return the selected statement of the editor. If no
376: * text is selected, the whole text will be returned
377: */
378: public String getSelectedStatement() {
379: String text = this .getSelectedText();
380: if (text == null || text.length() == 0)
381: return this .getText();
382: else
383: return text;
384: }
385:
386: public boolean closeFile(boolean clearText) {
387: if (this .currentFile == null)
388: return false;
389: this .currentFile = null;
390: if (clearText) {
391: this .setCaretPosition(0);
392: this .setDocument(new SyntaxDocument());
393: this .clearUndoBuffer();
394: }
395: fireFilenameChanged(null);
396: this .resetModified();
397: return true;
398: }
399:
400: protected void checkFileActions() {
401: boolean hasFile = this .hasFileLoaded();
402: this .fileSave.setEnabled(hasFile);
403: this .fileReloadAction.setEnabled(hasFile);
404: }
405:
406: public void fireFilenameChanged(String aNewName) {
407: this .checkFileActions();
408: if (this .filenameChangeListeners == null)
409: return;
410: Iterator<FilenameChangeListener> itr = filenameChangeListeners
411: .iterator();
412: while (itr.hasNext()) {
413: FilenameChangeListener l = itr.next();
414: l.fileNameChanged(this , aNewName);
415: }
416: }
417:
418: public void addFilenameChangeListener(
419: FilenameChangeListener aListener) {
420: if (aListener == null)
421: return;
422: if (this .filenameChangeListeners == null)
423: this .filenameChangeListeners = new LinkedList<FilenameChangeListener>();
424: this .filenameChangeListeners.add(aListener);
425: }
426:
427: public void removeFilenameChangeListener(
428: FilenameChangeListener aListener) {
429: if (aListener == null)
430: return;
431: if (this .filenameChangeListeners == null)
432: return;
433: this .filenameChangeListeners.remove(aListener);
434: }
435:
436: public boolean openFile() {
437: boolean result = false;
438: YesNoCancelResult choice = this .canCloseFile();
439: if (choice == YesNoCancelResult.cancel) {
440: this .requestFocusInWindow();
441: return false;
442: }
443:
444: try {
445: String lastDir = Settings.getInstance().getLastSqlDir();
446: JFileChooser fc = new JFileChooser(lastDir);
447: JComponent p = EncodingUtil.createEncodingPanel();
448: p.setBorder(new EmptyBorder(0, 5, 0, 0));
449: EncodingSelector selector = (EncodingSelector) p;
450: selector.setEncoding(Settings.getInstance()
451: .getDefaultFileEncoding());
452: fc.setAccessory(p);
453:
454: fc.addChoosableFileFilter(ExtensionFileFilter
455: .getSqlFileFilter());
456: int answer = fc.showOpenDialog(SwingUtilities
457: .getWindowAncestor(this ));
458: if (answer == JFileChooser.APPROVE_OPTION) {
459: String encoding = selector.getEncoding();
460:
461: result = readFile(fc.getSelectedFile(), encoding);
462:
463: WbSwingUtilities.repaintLater(this .getParent());
464:
465: lastDir = fc.getCurrentDirectory().getAbsolutePath();
466: Settings.getInstance().setLastSqlDir(lastDir);
467: Settings.getInstance().setDefaultFileEncoding(encoding);
468: }
469: return result;
470: } catch (Throwable e) {
471: LogMgr.logError("EditorPanel.openFile()",
472: "Error selecting file", e);
473: WbSwingUtilities.showErrorMessage(ExceptionUtil
474: .getDisplay(e));
475: return false;
476: }
477: }
478:
479: public boolean reloadFile() {
480: if (!this .hasFileLoaded())
481: return false;
482: if (this .currentFile == null)
483: return false;
484:
485: if (this .isModified()) {
486: String msg = ResourceMgr
487: .getString("MsgConfirmUnsavedReload");
488: msg = StringUtil.replace(msg, "%filename%", this
489: .getCurrentFileName());
490: boolean reload = WbSwingUtilities.getYesNo(this , msg);
491: if (!reload)
492: return false;
493: }
494: boolean result = false;
495: int caret = this .getCaretPosition();
496: result = this .readFile(currentFile, fileEncoding);
497: if (result) {
498: this .setCaretPosition(caret);
499: }
500: return result;
501: }
502:
503: public boolean hasFileLoaded() {
504: String file = this .getCurrentFileName();
505: return (file != null) && (file.length() > 0);
506: }
507:
508: public int checkAndSaveFile() {
509: if (!this .hasFileLoaded())
510: return JOptionPane.YES_OPTION;
511: int result = JOptionPane.YES_OPTION;
512:
513: if (this .isModified()) {
514: String msg = ResourceMgr
515: .getString("MsgConfirmUnsavedEditorFile");
516: msg = StringUtil.replace(msg, "%filename%", this
517: .getCurrentFileName());
518: result = WbSwingUtilities.getYesNoCancel(this , msg);
519: if (result == JOptionPane.YES_OPTION) {
520: this .saveCurrentFile();
521: }
522: }
523: return result;
524: }
525:
526: public YesNoCancelResult canCloseFile() {
527: if (!this .hasFileLoaded())
528: return YesNoCancelResult.yes;
529: if (!this .isModified())
530: return YesNoCancelResult.yes;
531: int choice = this .checkAndSaveFile();
532: if (choice == JOptionPane.YES_OPTION) {
533: return YesNoCancelResult.yes;
534: } else if (choice == JOptionPane.NO_OPTION) {
535: return YesNoCancelResult.no;
536: } else {
537: return YesNoCancelResult.cancel;
538: }
539: }
540:
541: public boolean readFile(File aFile) {
542: return this .readFile(aFile, null);
543: }
544:
545: public boolean readFile(File aFile, String encoding) {
546: if (aFile == null)
547: return false;
548: if (!aFile.exists())
549: return false;
550: if (aFile.length() >= Integer.MAX_VALUE / 2) {
551: WbSwingUtilities.showErrorMessageKey(this , "MsgFileTooBig");
552: return false;
553: }
554:
555: boolean result = false;
556:
557: BufferedReader reader = null;
558: SyntaxDocument doc = null;
559:
560: try {
561: // try to free memory by releasing the current document
562: if (this .document != null) {
563: this .document.removeDocumentListener(documentHandler);
564: this .document.dispose();
565: }
566: System.gc();
567: System.runFinalization();
568:
569: String filename = aFile.getAbsolutePath();
570: File f = new File(filename);
571: try {
572: if (StringUtil.isEmptyString(encoding))
573: encoding = EncodingUtil.getDefaultEncoding();
574: reader = EncodingUtil.createBufferedReader(f, encoding);
575: } catch (UnsupportedEncodingException e) {
576: LogMgr.logError("EditorPanel.readFile()",
577: "Unsupported encoding: " + encoding
578: + " requested. Using UTF-8", e);
579: try {
580: encoding = "UTF-8";
581: FileInputStream in = new FileInputStream(filename);
582: reader = new BufferedReader(new InputStreamReader(
583: in, "UTF-8"), 8192);
584: } catch (Throwable ignore) {
585: }
586: }
587:
588: // Creating a SyntaxDocument with a filled GapContent
589: // does not seem to work, inserting the text has to
590: // go through the SyntaxDocument
591: // but we initiallize the GapContent in advance to avoid
592: // too many re-allocations of the internal buffer
593: GapContent content = new GapContent(
594: (int) aFile.length() + 1500);
595: doc = new SyntaxDocument(content);
596: doc.suspendUndo();
597:
598: int pos = 0;
599:
600: final int numLines = 50;
601: StringBuilder lineBuffer = new StringBuilder(numLines * 100);
602:
603: // Inserting the text in chunks is much faster than
604: // inserting it line by line. Optimal speed would probably
605: // when reading everything into a buffer, and then call insertString()
606: // only once, but that will double the memory usage during loading
607: int lines = FileUtil.readLines(reader, lineBuffer,
608: numLines, "\n");
609: while (lines > 0) {
610: doc.insertString(pos, lineBuffer.toString(), null);
611: pos += lineBuffer.length();
612: lineBuffer.setLength(0);
613: lines = FileUtil.readLines(reader, lineBuffer,
614: numLines, "\n");
615: }
616:
617: doc.resumeUndo();
618: this .setDocument(doc);
619:
620: this .currentFile = aFile;
621: this .fileEncoding = encoding;
622: result = true;
623: this .fireFilenameChanged(filename);
624: } catch (BadLocationException bl) {
625: LogMgr
626: .logError("EditorPanel.readFile()",
627: "Error reading file "
628: + aFile.getAbsolutePath(), bl);
629: } catch (IOException e) {
630: LogMgr.logError("EditorPanel.readFile()",
631: "Error reading file " + aFile.getAbsolutePath(), e);
632: } catch (OutOfMemoryError mem) {
633: doc.dispose();
634: System.gc();
635: WbManager.getInstance().showOutOfMemoryError();
636: result = false;
637: } finally {
638: this .resetModified();
639: FileUtil.closeQuitely(reader);
640: }
641: return result;
642: }
643:
644: public boolean saveCurrentFile() {
645: boolean result = false;
646: try {
647: if (this .currentFile != null) {
648: this .saveFile(this .currentFile);
649: result = true;
650: } else {
651: result = this .saveFile();
652: }
653: } catch (IOException e) {
654: result = false;
655: }
656: return result;
657: }
658:
659: public boolean saveFile() {
660: boolean result = false;
661: String lastDir;
662: FileFilter ff = null;
663: if (this .editorType == SQL_EDITOR) {
664: lastDir = Settings.getInstance().getLastSqlDir();
665: ff = ExtensionFileFilter.getSqlFileFilter();
666: } else {
667: lastDir = Settings.getInstance().getLastEditorDir();
668: ff = ExtensionFileFilter.getTextFileFilter();
669: }
670: JFileChooser fc = new JFileChooser(lastDir);
671: fc.setSelectedFile(this .currentFile);
672: fc.addChoosableFileFilter(ff);
673: JComponent p = EncodingUtil.createEncodingPanel();
674: p.setBorder(new EmptyBorder(0, 5, 0, 0));
675: EncodingSelector selector = (EncodingSelector) p;
676: selector.setEncoding(this .fileEncoding);
677: fc.setAccessory(p);
678:
679: int answer = fc.showSaveDialog(SwingUtilities
680: .getWindowAncestor(this ));
681: if (answer == JFileChooser.APPROVE_OPTION) {
682: try {
683: String encoding = selector.getEncoding();
684: this .saveFile(fc.getSelectedFile(), encoding, Settings
685: .getInstance().getExternalEditorLineEnding());
686: this .fireFilenameChanged(this .getCurrentFileName());
687: lastDir = fc.getCurrentDirectory().getAbsolutePath();
688: if (this .editorType == SQL_EDITOR) {
689: Settings.getInstance().setLastSqlDir(lastDir);
690: } else {
691: Settings.getInstance().setLastEditorDir(lastDir);
692: }
693: result = true;
694: } catch (IOException e) {
695: WbSwingUtilities.showErrorMessage(this , ResourceMgr
696: .getString("ErrSavingFile")
697: + "\n" + ExceptionUtil.getDisplay(e));
698: result = false;
699: }
700: }
701: return result;
702: }
703:
704: public void saveFile(File aFile) throws IOException {
705: this .saveFile(aFile, this .fileEncoding, Settings.getInstance()
706: .getExternalEditorLineEnding());
707: }
708:
709: public void saveFile(File aFile, String encoding)
710: throws IOException {
711: this .saveFile(aFile, encoding, Settings.getInstance()
712: .getExternalEditorLineEnding());
713: }
714:
715: public void saveFile(File aFile, String encoding, String lineEnding)
716: throws IOException {
717: if (encoding == null) {
718: encoding = Settings.getInstance().getDefaultFileEncoding();
719: }
720:
721: try {
722: String filename = aFile.getAbsolutePath();
723: int pos = filename.indexOf('.');
724: if (pos < 0) {
725: filename = filename + ".sql";
726: aFile = new File(filename);
727: }
728:
729: Writer writer = EncodingUtil.createWriter(aFile, encoding,
730: false);
731:
732: int count = this .getLineCount();
733:
734: for (int i = 0; i < count; i++) {
735: String line = this .getLineText(i);
736: int len = StringUtil.getRealLineLength(line);
737: if (len > 0)
738: writer.write(line, 0, len);
739: writer.write(lineEnding);
740: }
741: writer.close();
742: this .currentFile = aFile;
743: this .fileEncoding = encoding;
744: this .resetModified();
745: } catch (IOException e) {
746: LogMgr.logError("EditorPanel.saveFile()",
747: "Error saving file", e);
748: throw e;
749: }
750: }
751:
752: public File getCurrentFile() {
753: return this .currentFile;
754: }
755:
756: public String getCurrentFileEncoding() {
757: if (this .currentFile == null)
758: return null;
759: return this .fileEncoding;
760: }
761:
762: public String getCurrentFileName() {
763: if (this .currentFile == null)
764: return null;
765: return this .currentFile.getAbsolutePath();
766: }
767:
768: public CommentAction getCommentAction() {
769: return this .commentAction;
770: }
771:
772: public UnCommentAction getUnCommentAction() {
773: return this .unCommentAction;
774: }
775:
776: /**
777: * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
778: */
779: public void propertyChange(PropertyChangeEvent evt) {
780: if (Settings.PROPERTY_SHOW_LINE_NUMBERS.equals(evt
781: .getPropertyName())) {
782: this .setShowLineNumbers(Settings.getInstance()
783: .getShowLineNumbers());
784: } else if (Settings.PROPERTY_EDITOR_TAB_WIDTH.equals(evt
785: .getPropertyName())) {
786: this .setTabSize(Settings.getInstance().getEditorTabWidth());
787: } else if (Settings.PROPERTY_EDITOR_ELECTRIC_SCROLL.equals(evt
788: .getPropertyName())) {
789: this .setElectricScroll(Settings.getInstance()
790: .getElectricScroll());
791: }
792: WbSwingUtilities.repaintNow(this );
793: }
794:
795: public void dragEnter(
796: java.awt.dnd.DropTargetDragEvent dropTargetDragEvent) {
797: if (this .isEditable()) {
798: dropTargetDragEvent.acceptDrag(DnDConstants.ACTION_COPY);
799: } else {
800: dropTargetDragEvent.rejectDrag();
801: }
802: }
803:
804: public void dragExit(java.awt.dnd.DropTargetEvent dropTargetEvent) {
805: }
806:
807: public void dragOver(
808: java.awt.dnd.DropTargetDragEvent dropTargetDragEvent) {
809: }
810:
811: public void drop(
812: java.awt.dnd.DropTargetDropEvent dropTargetDropEvent) {
813: try {
814: Transferable tr = dropTargetDropEvent.getTransferable();
815: if (tr.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
816: dropTargetDropEvent
817: .acceptDrop(DnDConstants.ACTION_COPY);
818: java.util.List fileList = (java.util.List) tr
819: .getTransferData(DataFlavor.javaFileListFlavor);
820: if (fileList != null && fileList.size() == 1) {
821: File file = (File) fileList.get(0);
822: if (this .canCloseFile() != YesNoCancelResult.cancel) {
823: this .readFile(file);
824: dropTargetDropEvent.getDropTargetContext()
825: .dropComplete(true);
826: } else {
827: dropTargetDropEvent.getDropTargetContext()
828: .dropComplete(false);
829: }
830: } else {
831: dropTargetDropEvent.getDropTargetContext()
832: .dropComplete(false);
833: final Window w = SwingUtilities
834: .getWindowAncestor(this );
835: EventQueue.invokeLater(new Runnable() {
836: public void run() {
837: w.toFront();
838: w.requestFocus();
839: WbSwingUtilities.showErrorMessageKey(w,
840: "ErrNoMultipleDrop");
841: }
842: });
843: }
844: } else {
845: dropTargetDropEvent.rejectDrop();
846: }
847: } catch (IOException io) {
848: io.printStackTrace();
849: dropTargetDropEvent.rejectDrop();
850: } catch (UnsupportedFlavorException ufe) {
851: ufe.printStackTrace();
852: dropTargetDropEvent.rejectDrop();
853: }
854: }
855:
856: public void dropActionChanged(
857: java.awt.dnd.DropTargetDragEvent dropTargetDragEvent) {
858: }
859:
860: }
|