Bug 13063 fixed: Color selection in SciNotes preferences threw exceptions
[scilab.git] / scilab / modules / scinotes / src / java / org / scilab / modules / scinotes / ScilabEditorPane.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - 2011 - Calixte DENIZET
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 package org.scilab.modules.scinotes;
14
15 import java.awt.Color;
16 import java.awt.Cursor;
17 import java.awt.Font;
18 import java.awt.Graphics;
19 import java.awt.Point;
20 import java.awt.Rectangle;
21 import java.awt.Shape;
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.awt.event.FocusEvent;
25 import java.awt.event.FocusListener;
26 import java.awt.event.KeyEvent;
27 import java.awt.event.KeyListener;
28 import java.awt.event.MouseEvent;
29 import java.awt.event.MouseListener;
30 import java.awt.event.MouseMotionListener;
31 import java.awt.event.MouseWheelEvent;
32 import java.awt.event.MouseWheelListener;
33 import java.io.File;
34 import java.util.ArrayList;
35 import java.util.EventObject;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.UUID;
40 import java.util.Vector;
41 import java.util.regex.Matcher;
42 import java.util.regex.Pattern;
43
44 import javax.swing.JEditorPane;
45 import javax.swing.JScrollBar;
46 import javax.swing.JScrollPane;
47 import javax.swing.JSplitPane;
48 import javax.swing.SwingUtilities;
49 import javax.swing.Timer;
50 import javax.swing.UIManager;
51 import javax.swing.event.CaretEvent;
52 import javax.swing.event.CaretListener;
53 import javax.swing.event.EventListenerList;
54 import javax.swing.text.BadLocationException;
55 import javax.swing.text.Caret;
56 import javax.swing.text.DefaultHighlighter;
57 import javax.swing.text.Document;
58 import javax.swing.text.Element;
59 import javax.swing.text.Highlighter;
60 import javax.swing.text.JTextComponent;
61 import javax.swing.text.View;
62
63 import org.scilab.modules.commons.OS;
64 import org.scilab.modules.commons.gui.ScilabCaret;
65 import org.scilab.modules.console.utils.ScilabLaTeXViewer;
66 import org.scilab.modules.gui.messagebox.MessageBox;
67 import org.scilab.modules.gui.messagebox.ScilabMessageBox;
68 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
69 import org.scilab.modules.gui.messagebox.ScilabModalDialog.AnswerOption;
70 import org.scilab.modules.gui.messagebox.ScilabModalDialog.ButtonType;
71 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
72 import org.scilab.modules.gui.utils.WebBrowser;
73 import org.scilab.modules.scinotes.actions.CopyAsHTMLAction;
74 import org.scilab.modules.scinotes.actions.OpenSourceFileOnKeywordAction;
75 import org.scilab.modules.scinotes.utils.NavigatorWindow;
76 import org.scilab.modules.scinotes.utils.ScilabScrollPane;
77 import org.scilab.modules.scinotes.utils.SciNotesMessages;
78
79 /**
80  * Class ScilabEditorPane
81  * @author Calixte DENIZET
82  *
83  */
84 public class ScilabEditorPane extends JEditorPane implements Highlighter.HighlightPainter,
85     CaretListener, MouseListener,
86     MouseMotionListener, Cloneable,
87     KeyListener {
88
89     private static final long serialVersionUID = 4322071415211939097L;
90
91     private static final String TIRET = " - ";
92     private static final Cursor HANDCURSOR = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
93     private static final Cursor TEXTCURSOR = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR);
94     private static final DefaultHighlighter.DefaultHighlightPainter HIGHLIGHTER = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW);
95
96     private static ScilabEditorPane focused;
97
98     private Color highlightColor;
99     private Color highlightContourColor;
100     private boolean highlightEnable;
101     private Object highlightCL;
102     private boolean matchingKeywordsEnable;
103     private boolean matchingOpenersEnable;
104     private boolean overwriteMode;
105     private ScilabLexer lexer;
106     private SciNotes editor;
107     private IndentManager indent;
108     private TabManager tab;
109     private CommentManager com;
110     private HelpOnTypingManager helpOnTyping;
111     private TrailingWhiteManager trailingWhite;
112     private boolean readonly;
113     private boolean binary;
114     private String infoBar = "";
115     private String shortName = "";
116     private String title = "";
117     private Timer selectionTimer;
118     private Timer matcherTimer;
119
120     private Point mousePoint;
121
122     private long lastModified;
123     private long lastExternalModification;
124
125     /* matchLR matches Left to Right ... */
126     private MatchingBlockManager matchLR;
127     private MatchingBlockManager matchRL;
128
129     private boolean suppressCom = true;
130
131     private SciNotesLineNumberPanel xln;
132     private ScilabEditorPane rightTextPane;
133     private UUID uuid;
134
135     private EditorComponent edComponent;
136
137     private boolean hand;
138     private boolean infoBarChanged;
139     private boolean ctrlHit;
140
141     private Color saveHighlightContourColor;
142     private Color saveHighlightColor;
143     private boolean hasBeenSaved;
144     private boolean saveHighlightEnable;
145
146     private EventListenerList kwListeners = new EventListenerList();
147     private Map<Integer, Object> highlightedWords = new HashMap<Integer, Object>();
148
149     //private List<Object> highlightedWords = new ArrayList<Object>();
150     //private List<Integer> highlightedWordsBegin = new ArrayList<Integer>();
151
152     /**
153      * Constructor
154      * @param editor which uses this pane
155      */
156     public ScilabEditorPane(SciNotes editor) {
157         super();
158         if (focused == null) {
159             focused = this;
160         }
161         this.editor = editor;
162         this.uuid = UUID.randomUUID();
163         edComponent = new EditorComponent(this);
164
165         /*
166           When SciNotes is docked and has two tabs, switching the tabs causes a focus loss.
167           The focus is gave to the other docked component and that generates a toolbar change.
168           The solution is to set FocusCycleRoot to false (set to true by default in JEditorPane).
169         */
170         setFocusCycleRoot(false);
171
172         addCaretListener(this);
173         addMouseMotionListener(this);
174         addMouseListener(this);
175         enableMatchingKeywords(SciNotesOptions.getSciNotesDisplay().highlightKeywords);
176         enableMatchingOpeners(SciNotesOptions.getSciNotesDisplay().highlightBrackets);
177         setFocusable(true);
178         addFocusListener(new FocusListener() {
179             public void focusGained(FocusEvent e) {
180                 updateInfosWhenFocused();
181                 if (ScilabEditorPane.this.editor != null) {
182                     NavigatorWindow nav = ScilabEditorPane.this.editor.getNavigator();
183                     if (nav != null) {
184                         nav.update((ScilabDocument) getDocument());
185                     }
186                 }
187                 setMustAdjustVisibility(true);
188             }
189
190             public void focusLost(FocusEvent e) {
191                 ((ScilabDocument) getDocument()).setFocused(false);
192                 if (e.getOppositeComponent() == getOtherPaneInSplit()) {
193                     setMustAdjustVisibility(false);
194                 }
195             }
196         });
197
198         addKeywordListener(new KeywordAdapter.MouseOverAdapter() {
199             public void caughtKeyword(KeywordEvent e) {
200                 if (ScilabLexerConstants.isClickable(e.getType())) {
201                     if (ctrlHit) {
202                         setCursor(HANDCURSOR);
203                         hand = true;
204                         try {
205                             String url = ((ScilabDocument) getDocument()).getText(e.getStart(), e.getLength());
206                             if (ScilabLexerConstants.isClickable(e.getType())) {
207                                 String text;
208                                 switch (e.getType()) {
209                                     case ScilabLexerConstants.URL :
210                                         text = SciNotesMessages.OPENURL;
211                                         break;
212                                     case ScilabLexerConstants.MAIL :
213                                         text = SciNotesMessages.MAILTO;
214                                         break;
215                                     case ScilabLexerConstants.MACROS :
216                                         text = SciNotesMessages.OPENSOURCE;
217                                         break;
218                                     case ScilabLexerConstants.MACROINFILE :
219                                         text = SciNotesMessages.SHOWSOURCE;
220                                         break;
221                                     default :
222                                         text = null;
223                                 }
224
225                                 if (text != null && ScilabEditorPane.this.editor != null) {
226                                     ScilabEditorPane.this.editor.getInfoBar().setText(text + url);
227                                     infoBarChanged = true;
228                                 }
229                             }
230                         } catch (BadLocationException ex) { }
231                     } else if (ScilabEditorPane.this.editor != null) {
232                         ScilabEditorPane.this.editor.getInfoBar().setText(SciNotesMessages.CLICKABLE_URL);
233                         infoBarChanged = true;
234                         if (hand) {
235                             setCursor(TEXTCURSOR);
236                             hand = false;
237                         }
238                     }
239                 } else {
240                     if (hand) {
241                         setCursor(TEXTCURSOR);
242                         hand = false;
243                     }
244                     if (infoBarChanged && ScilabEditorPane.this.editor != null) {
245                         ScilabEditorPane.this.editor.getInfoBar().setText(infoBar);
246                         infoBarChanged = false;
247                     }
248                     if (ScilabLexerConstants.isLaTeX(e.getType())) {
249                         try {
250                             int start = e.getStart();
251                             int end = start + e.getLength();
252                             String exp = ((ScilabDocument) getDocument()).getText(start, e.getLength());
253                             ScilabScrollPane ssp = getScrollPane();
254                             int height;
255                             if (ssp != null) {
256                                 height = ssp.getHeight() + ssp.getVerticalScrollBar().getValue();
257                             } else {
258                                 height = edComponent.getHeight();
259                             }
260                             ScilabLaTeXViewer.displayExpression(ScilabEditorPane.this, height, exp, start, end);
261                         } catch (BadLocationException ex) { }
262                     } else {
263                         ScilabLaTeXViewer.removeLaTeXViewer(ScilabEditorPane.this);
264                     }
265                 }
266             }
267         });
268
269         addKeywordListener(new KeywordAdapter.MouseClickedAdapter() {
270             public void caughtKeyword(KeywordEvent e) {
271                 if (ctrlHit && ScilabLexerConstants.isClickable(e.getType())) {
272                     try {
273                         hand = false;
274                         ctrlHit = false;
275                         infoBarChanged = false;
276                         setCursor(TEXTCURSOR);
277                         if (ScilabEditorPane.this.editor != null) {
278                             ScilabEditorPane.this.editor.getInfoBar().setText(infoBar);
279                         }
280                         String url = ((ScilabDocument) getDocument()).getText(e.getStart(), e.getLength());
281                         if (ScilabLexerConstants.URL == e.getType() || ScilabLexerConstants.MAIL == e.getType()) {
282                             WebBrowser.openUrl(url);
283                         } else if (ScilabLexerConstants.isOpenable(e.getType())) {
284                             OpenSourceFileOnKeywordAction.openSource(ScilabEditorPane.this, url);
285                         }
286                     } catch (BadLocationException ex) { }
287                 }
288             }
289         });
290
291         getScrollPane().addMouseWheelListener(new MouseWheelListener() {
292             public void mouseWheelMoved(MouseWheelEvent e) {
293                 if ((OS.get() == OS.MAC && e.isMetaDown()) || e.isControlDown()) {
294                     int n = e.getWheelRotation();
295                     SciNotes.updateFontSize(n);
296                     e.consume();
297                 }
298             }
299         });
300
301         addKeyListener(this);
302         setTransferHandler(new CopyAsHTMLAction.HTMLTransferHandler());
303
304         ((ScilabCaret) getCaret()).setMustAdjustVisibility(false);
305     }
306
307     public void enableColorization(boolean b) {
308         View view = ((ScilabDocument) getDocument()).getView();
309         if (view != null) {
310             if (view instanceof ScilabView) {
311                 ((ScilabView) view).enable(b);
312             } else {
313                 ((ScilabPlainView) view).enable(b);
314             }
315         }
316     }
317
318     public void configurationChanged(SciNotesConfiguration.Conf conf) {
319         ((ScilabEditorKit) getEditorKit()).getStylePreferences().configurationChanged(conf);
320
321         if (conf.font) {
322             resetFont();
323         }
324
325         if (conf.display) {
326             enableHighlightedLine(SciNotesOptions.getSciNotesDisplay().highlightCurrentLine);
327             setHighlightedLineColor(SciNotesOptions.getSciNotesDisplay().currentLineColor);
328             enableColorization(SciNotesOptions.getSciNotesDisplay().keywordsColorization);
329             setBackground(SciNotesOptions.getSciNotesDisplay().backgroundColor);
330             setCaretColor(SciNotesOptions.getSciNotesDisplay().caretColor);
331
332             boolean kw = SciNotesOptions.getSciNotesDisplay().highlightKeywords;
333             boolean op = SciNotesOptions.getSciNotesDisplay().highlightBrackets;
334
335             if ((kw || op) && (!matchingKeywordsEnable && !matchingOpenersEnable)) {
336                 matchLR = new MatchingBlockManager((ScilabDocument) getDocument(), this, true, getHighlighter());
337                 matchLR.setDefaults();
338                 matchRL = new MatchingBlockManager((ScilabDocument) getDocument(), this, false, getHighlighter());
339                 matchRL.setDefaults();
340                 enableMatchingKeywords(kw);
341                 enableMatchingOpeners(op);
342                 return;
343             }
344
345             if ((kw || op) && (matchingKeywordsEnable || matchingOpenersEnable)) {
346                 matchLR.configurationChanged(conf);
347                 matchRL.configurationChanged(conf);
348                 return;
349             }
350
351             if ((!kw && !op) && (matchingKeywordsEnable || matchingOpenersEnable)) {
352                 matchLR.desactivateMouseOver();
353                 matchLR = null;
354                 matchRL.desactivateMouseOver();
355                 matchRL = null;
356                 return;
357             }
358         }
359     }
360
361     /**
362      * @return the lexer
363      */
364     public ScilabLexer getLexer() {
365         return lexer;
366     }
367
368     /**
369      * {@inheritDoc}
370      * When no split and in wrapped view , this method return true and the consequence is
371      * that there is no horizontal scrollbar.
372      */
373     public boolean getScrollableTracksViewportWidth() {
374         return ((ScilabDocument) getDocument()).getView() instanceof ScilabView && !edComponent.isSplited();
375     }
376
377     /**
378      * @return true if the pane is in OverWrite mode (insert)
379      */
380     public boolean getOverwriteMode() {
381         return this.overwriteMode;
382     }
383
384     /**
385      * @param overwriteMode true if the pane is in OverWrite mode (insert)
386      */
387     public void setOverwriteMode(boolean overwriteMode) {
388         this.overwriteMode = overwriteMode;
389         ((ScilabCaret) getCaret()).setOverwriteMode(overwriteMode);
390     }
391
392     /**
393      * {@inheritDoc}
394      */
395     public void replaceSelection(String content) {
396         if (overwriteMode && getSelectionStart() == getSelectionEnd()) {
397             int pos = getCaretPosition();
398             select(pos, pos + content.length());
399         }
400
401         if (((SciNotesCaret) getCaret()).isEmptySelection()) {
402             super.replaceSelection(content);
403         } else {
404             SciNotesCaret caret = (SciNotesCaret) getCaret();
405             int[][] pos = caret.getSelectedPositions();
406             List<Object> sels = caret.getSelections();
407             int len = content.length();
408             int res = 0;
409             int sres;
410             ScilabDocument doc = (ScilabDocument) getDocument();
411             doc.getUndoManager().enableOneShot(true);
412             doc.mergeEditsBegin();
413             caret.protectHighlights(true);
414             for (int i = 0; i < pos.length; i++) {
415                 if (sels.get(i) != null) {
416                     sres = pos[i][0] + res;
417                     try {
418                         doc.replace(sres, pos[i][1] - pos[i][0], content, null);
419                     } catch (BadLocationException e) { }
420                     res = sres + len - pos[i][1];
421                     pos[i][0] = sres + len;
422                     pos[i][1] = sres + len;
423                 }
424             }
425             doc.mergeEditsEnd();
426             doc.getUndoManager().enableOneShot(false);
427             caret.protectHighlights(false);
428             caret.updateHighlights();
429         }
430     }
431
432     /**
433      * Nothing !
434      * @param e the event
435      */
436     public void keyPressed(KeyEvent e) {
437         // Workaround for bug 7238
438         if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD
439                 && e.getKeyCode() == KeyEvent.VK_DELETE
440                 && e.getKeyChar() != KeyEvent.VK_DELETE) {
441             e.setKeyCode(KeyEvent.VK_DECIMAL);
442             ctrlHit = false;
443         } else if (mousePoint != null && e.getKeyCode() == KeyEvent.VK_CONTROL) {
444             ctrlHit = true;
445             preventConcernedKeywordListener(viewToModel(mousePoint), e, KeywordListener.ONMOUSEOVER);
446         } else {
447             ctrlHit = false;
448         }
449     }
450
451     /**
452      * Nothing !
453      * @param e the event
454      */
455     public void keyReleased(KeyEvent e) {
456         if (mousePoint != null && e.getKeyCode() == KeyEvent.VK_CONTROL) {
457             ctrlHit = false;
458             preventConcernedKeywordListener(viewToModel(mousePoint), e, KeywordListener.ONMOUSEOVER);
459         }
460     }
461
462     /**
463      * Nothing !
464      * @param e the event
465      */
466     public void keyTyped(KeyEvent e) { }
467
468     /**
469      * @overload #setDocument
470      * @param doc to set
471      */
472     public void setDocument(Document doc) {
473         super.setDocument(doc);
474         if (doc instanceof ScilabDocument) {
475             ((ScilabDocument) doc).getUndoManager().discardAllEdits();
476             initialize((ScilabDocument) doc);
477         }
478     }
479
480     /**
481      * {@inheritDoc}
482      */
483     public void setName(String name) {
484         setNameInSuper(name);
485         setShortNameAndTitle(name);
486         ScilabEditorPane pane = getOtherPaneInSplit();
487         if (pane != null) {
488             // I don't call pane.setName since we will enter in an infinite loop
489             pane.setNameInSuper(name);
490             pane.setShortNameAndTitle(name);
491         }
492     }
493
494     /**
495      * @param name the name
496      */
497     private void setNameInSuper(String name) {
498         super.setName(name);
499     }
500
501     /**
502      * @param name the name
503      */
504     private void setShortNameAndTitle(String name) {
505         if (name != null) {
506             File f = new File(name);
507             setShortName(f.getName());
508             title =  shortName + " (" + f.getAbsolutePath() + ")" + TIRET + SciNotesMessages.SCILAB_EDITOR;
509         }
510     }
511
512     /**
513      * @param title the title
514      */
515     public void setTitle(String title) {
516         this.title = title + TIRET + SciNotesMessages.SCILAB_EDITOR;
517     }
518
519     /**
520      * @return the title
521      */
522     public String getTitle() {
523         return title;
524     }
525
526     /**
527      * @param name the short name
528      */
529     public void setShortName(String name) {
530         this.shortName = name;
531     }
532
533     /**
534      * @return the short name of the file (without the full path)
535      */
536     public String getShortName() {
537         return shortName;
538     }
539
540     /**
541      * Init the pane
542      */
543     public void init(final int pos) {
544         SwingUtilities.invokeLater(new Runnable() {
545             public void run() {
546                 requestFocus();
547                 setCaretPosition(pos);
548             }
549         });
550     }
551
552     /**
553      * Close this pane
554      */
555     public void close() {
556         FocusListener[] l = getFocusListeners();
557         for (int i = 0; i < l.length; i++) {
558             removeFocusListener(l[i]);
559         }
560     }
561
562     /**
563      * Update infos
564      */
565     public void updateInfosWhenFocused() {
566         ScilabDocument doc = (ScilabDocument) getDocument();
567         doc.setFocused(true);
568         SciNotes.setEditor(editor);
569         focused = this;
570         doc.getUndoManager().enableUndoRedoButtons();
571
572         if (editor != null) {
573             if (checkExternalModif() && lastExternalModification < getLastModification()) {
574                 editor.getInfoBar().setText(SciNotesMessages.EXTERNAL_MODIFICATION_INFO);
575                 if (ScilabModalDialog.show(editor, String.format(SciNotesMessages.ASK_TO_RELOAD, getShortName()), SciNotesMessages.RELOAD, IconType.QUESTION_ICON, ButtonType.YES_NO) == AnswerOption.YES_OPTION) {
576                     editor.reload(getEditor().getTabPane().indexOfComponent(getEditorComponent()));
577                     editor.getTextPane().updateInfosWhenFocused();
578                 }
579                 lastExternalModification = getLastModification();
580             } else {
581                 editor.getInfoBar().setText(getInfoBarText());
582             }
583         }
584     }
585
586     /**
587      * @return true if an external modif occurred
588      */
589     public boolean checkExternalModif() {
590         String path = getName();
591         if (path != null) {
592             File f = new File(path);
593             if (f != null && f.exists()) {
594                 return lastModified < f.lastModified();
595             } else {
596                 return true;
597             }
598         }
599         return false;
600     }
601
602     /**
603      * Get last modification on file
604      * @return the lastModified value
605      */
606     public long getLastModification() {
607         String path = getName();
608         if (path != null) {
609             File f = new File(path);
610             if (f != null && f.exists()) {
611                 return f.lastModified();
612             }
613         }
614
615         return -1;
616     }
617
618     /**
619      * @return the String which must be displayed in the infobar
620      */
621     public String getInfoBarText() {
622         return infoBar;
623     }
624
625     /**
626      * @param text String which must be displayed in the infobar
627      */
628     public void setInfoBarText(String text) {
629         this.infoBar = text;
630         if (editor != null) {
631             editor.getInfoBar().setText(getInfoBarText());
632         }
633     }
634
635     /**
636      * @param readonly true to set Read-Only mode
637      */
638     public void setReadOnly(boolean readonly) {
639         this.readonly = readonly;
640         setEditable(!readonly);
641         setDragEnabled(!readonly);
642         if (readonly) {
643             infoBar = SciNotesMessages.READ_ONLY_MODE;
644         } else {
645             infoBar = "";
646         }
647     }
648
649     /**
650      * @param binary true to set binary mode
651      */
652     public void setBinary(boolean binary) {
653         this.binary = binary;
654         setEditable(!binary);
655         setDragEnabled(!binary);
656         if (binary) {
657             infoBar = SciNotesMessages.BINARY_FILE_MODE;
658             disableAll();
659         } else {
660             infoBar = "";
661         }
662     }
663
664     /**
665      * Copy the props of this textPane to pane
666      * @param pane the pane which receives the same props as this
667      */
668     public void copyProps(ScilabEditorPane pane) {
669         pane.lastModified = lastModified;
670         pane.highlightEnable = highlightEnable;
671         pane.matchingKeywordsEnable = matchingKeywordsEnable;
672         pane.matchingOpenersEnable = matchingOpenersEnable;
673         pane.suppressCom = suppressCom;
674         pane.setName(getName());
675         pane.setShortName(getShortName());
676         pane.setTitle(getTitle().substring(0, getTitle().lastIndexOf(TIRET)));
677         pane.setEditable(isEditable());
678     }
679
680     /**
681      * Get the UUID associated with the editor pane instance.
682      * @return unique identifier
683      */
684     public UUID getUUID() {
685         return uuid;
686     }
687
688     /**
689      * Get the time where the file associated with this pane
690      * has been modified.
691      * @return the last modified time or 0
692      */
693     public long getLastModified() {
694         return lastModified;
695     }
696
697     /**
698      * Set the last time where the file associated with this pane
699      * has been modified.
700      * @param time the time
701      */
702     public void setLastModified(long time) {
703         this.lastModified = time;
704         ScilabEditorPane pane = getOtherPaneInSplit();
705         if (pane != null) {
706             pane.lastModified = time;
707         }
708     }
709
710     /**
711      * @return the SciNotesLineNumberPanel used with this pane
712      */
713     public SciNotesLineNumberPanel getXln() {
714         return xln;
715     }
716
717     /**
718      * @return the editor
719      */
720     public SciNotes getEditor() {
721         return editor;
722     }
723
724     /**
725      * @param editor to set
726      */
727     public void setEditor(SciNotes editor) {
728         this.editor = editor;
729     }
730
731     /**
732      * Disable all
733      */
734     public void disableAll() {
735         indent = null;
736         tab = null;
737         com = null;
738         trailingWhite = null;
739         enableMatchingKeywords(false);
740         enableMatchingOpeners(false);
741         if (matchLR != null) {
742             matchLR.desactivateMouseOver();
743             matchLR = null;
744         }
745         if (matchRL != null) {
746             matchRL.desactivateMouseOver();
747             matchRL = null;
748         }
749     }
750
751     /**
752      * Destroy this component
753      */
754     public void destroy() {
755         FocusListener[] fls = getFocusListeners();
756         for (FocusListener fl : fls) {
757             removeFocusListener(fl);
758         }
759         disableAll();
760     }
761
762     /**
763      * @return the scrollPane or the splitpane associated with this textPane
764      */
765     public EditorComponent getEditorComponent() {
766         return edComponent;
767     }
768
769     /**
770      * @return the scrollPane or the splitpane associated with this textPane
771      */
772     public void setEditorComponent(EditorComponent ed) {
773         this.edComponent = ed;
774     }
775
776     /**
777      * @param split the split used
778      */
779     public void setSplitPane(JSplitPane split) {
780         edComponent.setSplitPane(split);
781     }
782
783     /**
784      * @param split the split used
785      */
786     public JSplitPane getSplitPane() {
787         return edComponent.getSplitPane();
788     }
789
790     /**
791      * Update the title of current tab
792      */
793     public void updateTitle() {
794         if (editor != null) {
795             editor.updateTabTitle();
796         }
797     }
798
799     public void setMustAdjustVisibility(boolean mustAdjustVisibility) {
800         ((ScilabCaret) getCaret()).setMustAdjustVisibility(mustAdjustVisibility);
801     }
802
803     public boolean getMustAdjustVisibility() {
804         return ((ScilabCaret) getCaret()).getMustAdjustVisibility();
805     }
806
807     /**
808      * Scroll the pane to have the line containing pos on the top of the pane
809      * @param pos the position in the document
810      */
811     public void scrollTextToPos(int pos) {
812         scrollTextToPos(pos, true, false);
813     }
814
815     /**
816      * Scroll the pane to have the line containing pos on the top or centered on the pane
817      * @param pos the position in the document
818      * @param setCaret, if true the caret is set at the given position
819      * @param centered, if true the line is centered
820      */
821     public void scrollTextToPos(final int pos, final boolean setCaret, final boolean centered) {
822         SwingUtilities.invokeLater(new Runnable() {
823             public void run() {
824                 try {
825                     if (setCaret) {
826                         setCaretPosition(pos);
827                     }
828                     JScrollBar scrollbar = getScrollPane().getVerticalScrollBar();
829                     Rectangle rect = modelToView(pos);
830                     if (centered) {
831                         int value = scrollbar.getValue();
832                         int h = scrollbar.getHeight();
833                         if (rect.y < value || rect.y > value + h) {
834                             scrollbar.setValue(Math.max(0, rect.y - h / 2));
835                         }
836                     } else {
837                         if (rect.y > scrollbar.getMaximum()) {
838                             scrollbar.setMaximum(rect.y);
839                         }
840                         scrollbar.setValue(rect.y);
841                     }
842                 } catch (BadLocationException e) { }
843             }
844         });
845     }
846
847     /**
848      * Scroll the pane to have the line lineNumber on the top of the pane
849      * @param lineNumber the number of the line
850      * @param highlight true to highlight the line
851      */
852     public void scrollTextToLineNumber(int lineNumber, boolean highlight) {
853         scrollTextToLineNumber(lineNumber, highlight, true, false);
854     }
855
856     /**
857      * Scroll the pane to have the line lineNumber on the top or centered on the pane
858      * @param lineNumber the number of the line
859      * @param highlight true to highlight the line
860      * @param setCaret, if true the caret is set at the given line
861      * @param centered, if true the line is centered
862      */
863     public void scrollTextToLineNumber(int lineNumber, final boolean highlight, final boolean setCaret, final boolean centered) {
864         Element root = getDocument().getDefaultRootElement();
865         if (lineNumber >= 1 && lineNumber <= root.getElementCount()) {
866             final int pos = root.getElement(lineNumber - 1).getStartOffset();
867             SwingUtilities.invokeLater(new Runnable() {
868                 public void run() {
869                     scrollTextToPos(pos, setCaret, centered);
870                     if (highlight) {
871                         saveHighlightContourColor = highlightContourColor;
872                         highlightContourColor = null;
873                         saveHighlightColor = highlightColor;
874                         highlightColor = Color.YELLOW;
875                         saveHighlightEnable = highlightEnable;
876                         hasBeenSaved = true;
877                         enableHighlightedLine(false);
878                         enableHighlightedLine(true);
879                     }
880                 }
881             });
882         }
883     }
884
885     /**
886      * Scroll the pane to have the line lineNumber on the top of the pane in whereami mode
887      * The line number is computed regarding the function named funname.
888      * @param lineNumber the number of the line
889      * @param funname the function name
890      * @param highlight true to highlight the line
891      */
892     public void scrollTextToLineNumberInWhereami(int lineNumber, String funname, boolean highlight) {
893         scrollTextToLineNumberInWhereami(lineNumber, funname, highlight, true, false);
894     }
895
896     /**
897      * Scroll the pane to have the line lineNumber on the top of the pane in whereami mode
898      * The line number is computed regarding the function named funname.
899      * @param lineNumber the number of the line
900      * @param funname the function name
901      * @param highlight true to highlight the line
902      * @param setCaret, if true the caret is set at the given line
903      * @param centered, if true the line is centered
904      */
905     public void scrollTextToLineNumberInWhereami(int lineNumber, String funname, boolean highlight, boolean setCaret, boolean centered) {
906         if (funname != null) {
907             Element root = getDocument().getDefaultRootElement();
908             int nlines = root.getElementCount();
909             ScilabDocument.ScilabLeafElement elem;
910             for (int i = 0; i < nlines; i++) {
911                 elem = (ScilabDocument.ScilabLeafElement) root.getElement(i);
912                 if (elem.getFunctionName().equals(funname)) {
913                     lineNumber += i;
914                     break;
915                 }
916             }
917         }
918         scrollTextToLineNumber(lineNumber, highlight, setCaret, centered);
919     }
920
921     /**
922      * @return the width of a white
923      */
924     public int getWhiteWidth() {
925         View view = ((ScilabDocument) getDocument()).getView();
926         if (view != null) {
927             if (view instanceof ScilabView) {
928                 return ((ScilabView) view).getWhiteWidth();
929             } else {
930                 return ((ScilabPlainView) view).getWhiteWidth();
931             }
932         }
933
934         return 0;
935     }
936
937     public void resetFont() {
938         Font font = ((ScilabEditorKit) getEditorKit()).getStylePreferences().getBaseFont();
939         setFont(font);
940         xln.updateFont(font);
941     }
942
943     /**
944      * Set a new font
945      * @param keyword the type of keyword
946      * @param type an int : -2 to reset italic, -1 to reset bold, 1 to set bold and 2 to set italic
947      */
948     public void resetFont(String keyword, int type) {
949         ((ScilabEditorKit) getEditorKit()).getStylePreferences().genFont(keyword, type);
950     }
951
952     /**
953      * Set a new attribute
954      * @param keyword the type of keyword
955      * @param type an int : 0 nothing, 1 underline, 2 stroke, 3 underline and stroke
956      */
957     public void resetAttribute(String keyword, int type) {
958         ((ScilabEditorKit) getEditorKit()).getStylePreferences().genAttribute(keyword, type);
959     }
960
961     /**
962      * Set a new color
963      * @param keyword the kind of the keyword
964      * @param color the color
965      */
966     public void resetColor(String keyword, Color color) {
967         ((ScilabEditorKit) getEditorKit()).getStylePreferences().genColors(keyword, color);
968     }
969
970     /**
971      * Set to true if the comments must be suppressed when the code is executing in the console
972      * @param b boolean
973      */
974     public void suppressCommentsInExecutingCode(boolean b) {
975         suppressCom = b;
976     }
977
978     /**
979      * Execute the code in the console, the code is the selected text if exists
980      * or the text from beginning to actual position of the caret
981      * Comments are removed if suppressCom is set to true
982      * @return the code to be executed in the console.
983      */
984     public String getCodeToExecute() {
985         String selection;
986         int start, end;
987         start = getSelectionStart();
988         end = getSelectionEnd();
989
990         if (((SciNotesCaret) getCaret()).isEmptySelection()) {
991             try {
992                 if (start == end) {
993                     selection = getDocument().getText(0, start);
994                     start = 0;
995                 } else {
996                     selection = getSelectedText();
997                 }
998             } catch (BadLocationException e) {
999                 selection = "";
1000             }
1001         } else {
1002             selection = getSelectedText();
1003         }
1004
1005         if (suppressCom) {
1006             StringBuffer buf = new StringBuffer(selection.length());
1007             ScilabLexer.ScilabTokens tokens = ScilabLexer.getScilabTokens(selection);
1008             List<Integer> tokType = tokens.getTokenType();
1009             List<Integer> tokPos = tokens.getTokenPos();
1010             List<String> commands = new ArrayList<String>();
1011             int prevPos = 0;
1012             for (int i = 0; i < tokType.size(); i++) {
1013                 String str = selection.substring(prevPos, tokPos.get(i));
1014                 if ("\n".equals(str)) {
1015                     commands.add(buf.toString());
1016                     buf.setLength(0);
1017                 } else if (!ScilabLexerConstants.isComment(tokType.get(i))) {
1018                     buf.append(str);
1019                 }
1020                 prevPos = tokPos.get(i);
1021             }
1022
1023             if (buf.length() != 0) {
1024                 commands.add(buf.toString());
1025             }
1026
1027             buf.setLength(0);
1028             Pattern pat = Pattern.compile("[ \t]*");
1029             for (String command : commands) {
1030                 if (!pat.matcher(command).matches()) {
1031                     buf.append(command).append("\n");
1032                 }
1033             }
1034
1035             return buf.toString();
1036         }
1037
1038         return selection;
1039     }
1040
1041     /**
1042      * Add a new KeywordListener
1043      * @param kw a KeywordListener
1044      */
1045     public void addKeywordListener(KeywordListener kw) {
1046         kwListeners.add(KeywordListener.class, kw);
1047     }
1048
1049     /**
1050      * Remove a new KeywordListener
1051      * @param kw a KeywordListener
1052      */
1053     public void removeKeywordListener(KeywordListener kw) {
1054         kwListeners.remove(KeywordListener.class, kw);
1055     }
1056
1057     /**
1058      * @return an array of KeywordListener
1059      */
1060     public KeywordListener[] getKeywordListeners() {
1061         return kwListeners.getListeners(KeywordListener.class);
1062     }
1063
1064     /**
1065      * Set a new color for the highlighting
1066      * @param c the color, can be null (useful if setHighlightedContourColor is used with a
1067      * non-null value)
1068      */
1069     public void setHighlightedLineColor(Color c) {
1070         highlightColor = c;
1071     }
1072
1073     /**
1074      * Set a new color for the contour of the highlighting
1075      * @param c the color, if null no contour is drawn
1076      */
1077     public void setHighlightedContourColor(Color c) {
1078         highlightContourColor = c;
1079     }
1080
1081     /**
1082      * Activate or desactivate the help on typing
1083      */
1084     public void activateHelpOnTyping() {
1085         boolean isActive = HelpOnTypingManager.isActive();
1086         if (isActive && helpOnTyping == null) {
1087             helpOnTyping = HelpOnTypingManager.getInstance();
1088             addKeyListener(helpOnTyping);
1089         } else if (!isActive && helpOnTyping != null) {
1090             removeKeyListener(helpOnTyping);
1091             helpOnTyping = null;
1092         }
1093     }
1094
1095     /**
1096      * Enable (active true) or disable (active false) the line-highlighting.
1097      * @param active true or false
1098      */
1099     public void enableHighlightedLine(boolean active) {
1100         if (active && !highlightEnable) {
1101             try {
1102                 highlightCL = getHighlighter().addHighlight(0, 0, this);
1103             } catch (BadLocationException e) { }
1104             highlightEnable = true;
1105         }
1106
1107         if (!active && highlightEnable) {
1108             getHighlighter().removeHighlight(highlightCL);
1109             highlightEnable = false;
1110         }
1111
1112         repaint();
1113     }
1114
1115     /**
1116      * Enable (active true) or disable (active false) the matching keywords.
1117      * @param active true or false
1118      */
1119     public void enableMatchingKeywords(boolean active) {
1120         matchingKeywordsEnable = active;
1121     }
1122
1123     /**
1124      * Enable (active true) or disable (active false) the matching keywords.
1125      * @param active true or false
1126      */
1127     public void enableMatchingOpeners(boolean active) {
1128         matchingOpenersEnable = active;
1129     }
1130
1131     /**
1132      * Get a matching manager
1133      * @param lr true if the LR matcher must be returned
1134      * @return the MatchingBlockManager
1135      */
1136     public MatchingBlockManager getMatchingBlockManager(boolean lr) {
1137         if (lr) {
1138             return matchLR;
1139         } else {
1140             return matchRL;
1141         }
1142     }
1143
1144     /**
1145      * This class listens to the caret event
1146      * @param e event
1147      */
1148     public void caretUpdate(CaretEvent e) {
1149         if (hasBeenSaved) {
1150             removeHighlightForLine();
1151         }
1152
1153         if (hasFocus()) {
1154             final String str = getSelectedText();
1155             if (str != null && str.length() != 0) {
1156                 if (selectionTimer == null) {
1157                     selectionTimer = new Timer(1000, new ActionListener() {
1158                         public void actionPerformed(ActionEvent e) {
1159                             final String str = getSelectedText();
1160                             if (str != null && str.length() != 0) {
1161                                 int tok = lexer.getKeyword(getSelectionStart(), false);
1162                                 int s = lexer.start + lexer.yychar();
1163                                 if (ScilabLexerConstants.isSearchable(tok) && getSelectionStart() == s && getSelectionEnd() == s + lexer.yylength()) {
1164                                     highlightWords(tok, SearchManager.generatePattern(str, false, true, false), false);
1165                                 } else {
1166                                     highlightWords(str, false);
1167                                 }
1168
1169                                 if (highlightedWords.size() > 1 && editor != null && editor.getInfoBar() != null) {
1170                                     editor.getInfoBar().setText(String.format(SciNotesMessages.OCCURENCES_FOUND, Integer.toString(highlightedWords.size())));
1171                                 }
1172                                 removeHighlightOnPosition(getSelectionStart());
1173                             }
1174                             selectionTimer = null;
1175                         }
1176                     });
1177                     selectionTimer.setRepeats(false);
1178                     selectionTimer.start();
1179                 } else {
1180                     selectionTimer.restart();
1181                 }
1182             } else {
1183                 removeHighlightedWords();
1184             }
1185         }
1186
1187         if (highlightEnable) {
1188             repaint();
1189         }
1190
1191         int pos = getCaretPosition();
1192
1193         if (matchingKeywordsEnable || matchingOpenersEnable) {
1194             if (matcherTimer == null) {
1195                 matcherTimer = new Timer(100, new ActionListener() {
1196                     public void actionPerformed(ActionEvent e) {
1197                         int pos = getCaretPosition();
1198                         int tok = lexer.getKeyword(pos, false);
1199                         matchLR.searchMatchingBlock(false, tok, lexer.start + lexer.yychar());
1200                         tok = lexer.getKeyword(pos, true);
1201                         matchRL.searchMatchingBlock(false, tok, lexer.start + lexer.yychar() + lexer.yylength());
1202                         matcherTimer = null;
1203                     }
1204                 });
1205                 matcherTimer.setRepeats(false);
1206                 matcherTimer.start();
1207             } else {
1208                 matcherTimer.restart();
1209                 matchLR.update();
1210                 matchRL.update();
1211             }
1212         }
1213
1214         if (!readonly && !binary && editor != null) {
1215             editor.getInfoBar().setText(((ScilabDocument) getDocument()).getCurrentFunction(pos));
1216         }
1217     }
1218
1219     /**
1220      * Used to paint the highlighted line
1221      * @param g graphics to use
1222      * @param p0 start
1223      * @param p1 end
1224      * @param bounds the shape representing the area
1225      * @param c this pane
1226      */
1227     public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c) {
1228         if (highlightEnable) {
1229             try {
1230                 Rectangle r = modelToView(getCaretPosition());
1231                 if (highlightColor != null) {
1232                     g.setColor(highlightColor);
1233                     g.fillRect(0, r.y, getWidth(), r.height);
1234                 }
1235                 if (highlightContourColor != null) {
1236                     g.setColor(highlightContourColor);
1237                     g.drawLine(0, r.y - 1, getWidth(), r.y - 1);
1238                     g.drawLine(0, r.y + r.height, getWidth(), r.y + r.height);
1239                 }
1240
1241             } catch (BadLocationException e) { }
1242         }
1243     }
1244
1245     /**
1246      * @return the current TrailingWhiteManager
1247      */
1248     public TrailingWhiteManager getTrailingWhiteManager() {
1249         return trailingWhite;
1250     }
1251
1252     /**
1253      * @return the current IndentManager
1254      */
1255     public IndentManager getIndentManager() {
1256         return indent;
1257     }
1258
1259     /**
1260      * @return the current TabManager
1261      */
1262     public TabManager getTabManager() {
1263         return tab;
1264     }
1265
1266     /**
1267      * @return the current CommentManager
1268      */
1269     public CommentManager getCommentManager() {
1270         return com;
1271     }
1272
1273     /**
1274      * Get a keyword at a position in the document.
1275      * @param position in the document
1276      * @return the KeywordEvent containing infos about keyword.
1277      */
1278     public KeywordEvent getKeywordEvent(int position) {
1279         int tok = lexer.getKeyword(position, true);
1280         return new KeywordEvent(this, null, tok, lexer.start + lexer.yychar(), lexer.yylength());
1281     }
1282
1283     /**
1284      * Get a keyword at the current position in the document.
1285      * @return the KeywordEvent containing infos about keyword.
1286      */
1287     public KeywordEvent getKeywordEvent() {
1288         return getKeywordEvent(getCaretPosition());
1289     }
1290
1291     /**
1292      * Get a keyword at the current position in the document.
1293      * @param caret if true the position is the current caret position in the doc else
1294      * the position is the mouse pointer position projected in the document.
1295      * @param strict if true the char just after the caret is ignored
1296      * @return the KeywordEvent containing infos about keyword.
1297      */
1298     public KeywordEvent getKeywordEvent(boolean caret, boolean strict) {
1299         int tok;
1300         if (caret) {
1301             tok = lexer.getKeyword(getCaretPosition(), strict);
1302         } else {
1303             tok = lexer.getKeyword(viewToModel(mousePoint), strict);
1304         }
1305         return new KeywordEvent(this, null, tok, lexer.start + lexer.yychar(), lexer.yylength());
1306     }
1307
1308     /**
1309      * Get an helpable keyword at the current position in the document.
1310      * @param caret if true the position is the current caret position in the doc else
1311      * the position is the mouse pointer position projected in the document.
1312      * @return the helpable keyword.
1313      */
1314     public String getHelpableKeyword(boolean caret) {
1315         int tok;
1316         int pos;
1317         if (caret) {
1318             pos = getCaretPosition();
1319         } else {
1320             pos = viewToModel(mousePoint);
1321         }
1322
1323         tok = lexer.getKeyword(pos, true);
1324         if (!ScilabLexerConstants.isHelpable(tok)) {
1325             tok = lexer.getKeyword(pos + 1, true);
1326         }
1327
1328         if (ScilabLexerConstants.isHelpable(tok)) {
1329             try {
1330                 return getDocument().getText(lexer.start + lexer.yychar(), lexer.yylength());
1331             } catch (BadLocationException e) { }
1332         }
1333
1334         return null;
1335     }
1336
1337     /**
1338      * Prevents the different KeywordListener that a MouseEvent occurred
1339      * @param position of the mouse
1340      * @param ev the event which occurred
1341      * @param type of the event : KeywordListener.ONMOUSECLICKED or KeywordListener.ONMOUSEOVER
1342      */
1343     protected void preventConcernedKeywordListener(int position, EventObject ev, int type) {
1344         KeywordEvent kev = null;
1345         Object[] listeners = kwListeners.getListenerList();
1346         for (int i = listeners.length - 2; i >= 0; i -= 2) {
1347             if (listeners[i] == KeywordListener.class && type == ((KeywordListener) listeners[i + 1]).getType()) {
1348                 if (kev == null) {
1349                     int tok = lexer.getKeyword(position, true);
1350                     kev = new KeywordEvent(this, ev, tok, lexer.start + lexer.yychar(), lexer.yylength());
1351                 }
1352
1353                 ((KeywordListener) listeners[i + 1]).caughtKeyword(kev);
1354             }
1355         }
1356     }
1357
1358     /**
1359      * Implements mouseClicked in MouseListener
1360      * @param e event
1361      */
1362     public void mouseClicked(MouseEvent e) {
1363         preventConcernedKeywordListener(getCaretPosition(), e, KeywordListener.ONMOUSECLICKED);
1364     }
1365
1366     /**
1367      * Implements mouseEntered in MouseListener
1368      * @param e event
1369      */
1370     public void mouseEntered(MouseEvent e) {
1371         this.mousePoint = e.getPoint();
1372     }
1373
1374     /**
1375      * Implements mouseExited in MouseListener
1376      * @param e event
1377      */
1378     public void mouseExited(MouseEvent e) { }
1379
1380     /**
1381      * Implements mousePressed in MouseListener
1382      * @param e event
1383      */
1384     public void mousePressed(MouseEvent e) {
1385         if (hasBeenSaved) {
1386             removeHighlightForLine();
1387         }
1388
1389         removeHighlightedWords();
1390
1391         if (highlightEnable) {
1392             repaint();
1393         }
1394     }
1395
1396     /**
1397      * Implements mouseReleseaed in MouseListener
1398      * @param e event
1399      */
1400     public void mouseReleased(MouseEvent e) { }
1401
1402     /**
1403      * Implements mouseMoved in MouseMotionListener
1404      * @param e event
1405      */
1406     public void mouseMoved(MouseEvent e) {
1407         this.mousePoint = e.getPoint();
1408         preventConcernedKeywordListener(viewToModel(mousePoint), e, KeywordListener.ONMOUSEOVER);
1409     }
1410
1411     /**
1412      * Implements mouseDragged in MouseMotionListener
1413      * @param e event
1414      */
1415     public void mouseDragged(MouseEvent e) {
1416         if (hasBeenSaved) {
1417             removeHighlightForLine();
1418         }
1419
1420         removeHighlightedWords();
1421
1422         if (highlightEnable) {
1423             repaint();
1424         }
1425     }
1426
1427     /**
1428      * @return the current mouse poisition in this pane
1429      */
1430     public Point getMousePoint() {
1431         return mousePoint;
1432     }
1433
1434     /**
1435      * @param pane the EditorPane associated with this EditorPane in a splitted view
1436      */
1437     public void setOtherPaneInSplit(ScilabEditorPane pane) {
1438         if (pane == null) {
1439             rightTextPane.rightTextPane = null;
1440         }
1441         rightTextPane = pane;
1442     }
1443
1444     /**
1445      * @return the EditorPane associated with this EditorPane in a splitted view
1446      */
1447     public ScilabEditorPane getOtherPaneInSplit() {
1448         return rightTextPane;
1449     }
1450
1451     public ScilabEditorPane getCurrent() {
1452         if (focused == rightTextPane) {
1453             return rightTextPane;
1454         }
1455
1456         return this;
1457     }
1458
1459
1460     /**
1461      * @return the scrollPane associated with this EditorPane
1462      */
1463     public ScilabScrollPane getScrollPane() {
1464         return (ScilabScrollPane) SwingUtilities.getAncestorOfClass(ScilabScrollPane.class, this);
1465     }
1466
1467     /**
1468      * @return the current focused editorPane
1469      */
1470     public static ScilabEditorPane getFocusedPane() {
1471         return focused;
1472     }
1473
1474     /**
1475      * {@inheritDoc}
1476      */
1477     public String toString() {
1478         return shortName;
1479     }
1480
1481     /**
1482      * @return true if something has been copied
1483      */
1484     public boolean copyColumnSelectionInClipBoard() {
1485         return ((SciNotesCaret) getCaret()).copyPositionsInClipboard();
1486     }
1487
1488     /**
1489      * @return true if something has been removed
1490      */
1491     public boolean removeColumnSelection() {
1492         return ((SciNotesCaret) getCaret()).removePositions();
1493     }
1494
1495     /**
1496      * {@inheritDoc}
1497      */
1498     public String getSelectedText() {
1499         String str = ((SciNotesCaret) getCaret()).getSelectedText();
1500         if (str == null) {
1501             return super.getSelectedText();
1502         } else {
1503             return str;
1504         }
1505     }
1506
1507     /**
1508      * @param pos the position int the text
1509      * @return null if no column selection on the same line and an array of
1510      * integer (of size 2) containing the position of the selection
1511      */
1512     public int[] isNearColumnSelection(int pos) {
1513         if (!(getCaret() instanceof SciNotesCaret) || ((SciNotesCaret) getCaret()).isEmptySelection()) {
1514             return null;
1515         }
1516
1517         Element root = getDocument().getDefaultRootElement();
1518         int[][] positions = ((SciNotesCaret) getCaret()).getSelectedPositions();
1519         int line = root.getElementIndex(pos);
1520         int min = root.getElementIndex(positions[0][0]);
1521         int max = root.getElementIndex(positions[positions.length - 1][0]);
1522
1523         if (line >= min && line <= max) {
1524             return positions[line - min];
1525         }
1526
1527         return null;
1528     }
1529
1530     /**
1531      * {@inheritDoc}
1532      */
1533     public void setCaret(Caret c) {
1534         if (!(c instanceof ScilabCaret)) {
1535             final Caret caret = new SciNotesCaret(this);
1536             setCaretColor(getCaretColor());
1537             SwingUtilities.invokeLater(new Runnable() {
1538                 public void run() {
1539                     int blinkRate = 500;
1540                     Object o = UIManager.get("TextComponent.caretBlinkRate");
1541                     if ((o != null) && (o instanceof Integer)) {
1542                         Integer rate = (Integer) o;
1543                         blinkRate = rate.intValue();
1544                     }
1545                     caret.setBlinkRate(blinkRate);
1546                     caret.setVisible(true);
1547                 }
1548             });
1549             super.setCaret(caret);
1550         } else {
1551             super.setCaret(c);
1552         }
1553     }
1554
1555     /**
1556      * {@inheritDoc}
1557      */
1558     public void select(int start, int end) {
1559         removeHighlightOnPosition(start);
1560         int docLength = getDocument().getLength();
1561         if (start > docLength) {
1562             start = docLength;
1563         }
1564         if (end > docLength) {
1565             end = docLength;
1566         }
1567         super.setCaretPosition(start);
1568         super.moveCaretPosition(end);
1569     }
1570
1571     /**
1572      * Remove the highlight putted to show the line (for editor('foo',123))
1573      */
1574     private void removeHighlightForLine() {
1575         highlightContourColor = saveHighlightContourColor;
1576         highlightColor = saveHighlightColor;
1577         enableHighlightedLine(false);
1578         if (saveHighlightEnable) {
1579             enableHighlightedLine(true);
1580         }
1581         hasBeenSaved = false;
1582     }
1583
1584     /**
1585      * Remove the highlight at position start
1586      * @param start the beginning of the highlight
1587      */
1588     public void removeHighlightOnPosition(int start) {
1589         Object h = highlightedWords.get(start);
1590         if (h != null) {
1591             getHighlighter().removeHighlight(h);
1592             highlightedWords.remove(h);
1593         }
1594     }
1595
1596     /**
1597      * Highlight a word in this textpane.
1598      * @param word the word to highlight
1599      * @param exact if true the search is case sensitive
1600      */
1601     public void highlightWords(String word, boolean exact) {
1602         if (word != null && word.length() != 0) {
1603             highlightWords(SearchManager.generatePattern(word, exact, false, false), false);
1604         }
1605     }
1606
1607     /**
1608      * Highlight a word according to a pattern in this textpane.
1609      * @param pattern the pattern to highlight
1610      * @param centered, if true the pane is centered on the first occurence
1611      */
1612     public void highlightWords(Pattern pattern, boolean centered) {
1613         highlightWords(-1, pattern, centered);
1614     }
1615
1616     /**
1617      * Highlight a word according to a pattern in this textpane.
1618      * @param pattern the pattern to highlight
1619      * @param centered, if true the pane is centered on the first occurence
1620      */
1621     public void highlightWords(int tok, Pattern pattern, boolean centered) {
1622         if (pattern != null) {
1623             removeHighlightedWords();
1624             int first = -1;
1625             String text = ((ScilabDocument) getDocument()).getText();
1626             Matcher matcher = pattern.matcher(text);
1627
1628             Highlighter highlighter = getHighlighter();
1629             List<Integer[]> positions = SearchManager.findToken((ScilabDocument) getDocument(), tok, lexer, pattern);
1630
1631             if (positions != null) {
1632                 List<Rectangle> marks = new ArrayList<Rectangle>();
1633
1634                 for (Integer[] position : positions) {
1635                     try {
1636                         highlightedWords.put(position[0], highlighter.addHighlight(position[0], position[1], HIGHLIGHTER));
1637                         Rectangle r = modelToView(position[0]);
1638                         if (r != null && (marks.size() == 0 || marks.get(marks.size() - 1).y != r.y)) {
1639                             marks.add(r);
1640                         }
1641                     } catch (BadLocationException e) { }
1642                 }
1643
1644                 ScilabScrollPane ssp = getScrollPane();
1645                 if (ssp != null) {
1646                     ssp.putMarks(marks);
1647                 }
1648
1649                 if (centered && positions.size() != 0) {
1650                     scrollTextToPos(positions.get(0)[0], false, true);
1651                 }
1652             }
1653         }
1654     }
1655
1656     /**
1657      * Remove all the highlighted words
1658      */
1659     public void removeHighlightedWords() {
1660         Highlighter highlighter = getHighlighter();
1661         for (Object obj : highlightedWords.values()) {
1662             highlighter.removeHighlight(obj);
1663         }
1664         highlightedWords.clear();
1665         ScilabScrollPane ssp = getScrollPane();
1666         if (ssp != null) {
1667             ssp.removeMarks();
1668         }
1669     }
1670
1671     /**
1672      * Initialize the pane when the document is loaded
1673      * @param doc used with this pane
1674      */
1675     private void initialize(ScilabDocument doc) {
1676         indent = new IndentManager(doc);
1677         tab = new TabManager(doc, indent);
1678         tab.setDefaultTabulation();
1679         com = new CommentManager(doc);
1680         trailingWhite = new TrailingWhiteManager(doc);
1681
1682         if (matchingKeywordsEnable || matchingOpenersEnable) {
1683             matchLR = new MatchingBlockManager(doc, this, true, getHighlighter());
1684             matchLR.setDefaults();
1685             matchRL = new MatchingBlockManager(doc, this, false, getHighlighter());
1686             matchRL.setDefaults();
1687         }
1688
1689         lexer = doc.createLexer();
1690         xln = new SciNotesLineNumberPanel(this);
1691
1692         /* The order of the next two lines is important: the doc
1693            as listener will be called before xln so the resetTypeWhenBroken
1694            will be called before ! */
1695         doc.addDocumentListener(xln);
1696         doc.addDocumentListener(doc);
1697
1698         getScrollPane().setRowHeaderView(xln);
1699         doc.setEditorPane(this);
1700
1701         if (editor != null) {
1702             NavigatorWindow nav = editor.getNavigator();
1703             if (nav != null) {
1704                 nav.addEditorPane(this);
1705             }
1706         }
1707
1708         resetFont();
1709     }
1710 }