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