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