merge 6.0 into master
[scilab.git] / scilab / modules / scinotes / src / java / org / scilab / modules / scinotes / SciNotes.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
4  * Copyright (C) 2010 - 2011 - Calixte DENIZET
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 package org.scilab.modules.scinotes;
18
19 import java.awt.Color;
20 import java.awt.Component;
21 import java.awt.Font;
22 import java.awt.event.FocusEvent;
23 import java.awt.event.FocusListener;
24 import java.io.BufferedReader;
25 import java.io.BufferedWriter;
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.FileNotFoundException;
29 import java.io.FileOutputStream;
30 import java.io.InputStreamReader;
31 import java.io.IOException;
32 import java.io.OutputStreamWriter;
33 import java.io.StringReader;
34 import java.lang.reflect.Constructor;
35 import java.lang.reflect.InvocationTargetException;
36 import java.nio.charset.CharacterCodingException;
37 import java.nio.charset.Charset;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.HashMap;
41 import java.util.Iterator;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.StringTokenizer;
45 import java.util.UUID;
46 import java.util.logging.Logger;
47
48 import javax.swing.BorderFactory;
49 import javax.swing.JButton;
50 import javax.swing.JComponent;
51 import javax.swing.JFileChooser;
52 import javax.swing.JFrame;
53 import javax.swing.JOptionPane;
54 import javax.swing.JPanel;
55 import javax.swing.JSplitPane;
56 import javax.swing.KeyStroke;
57 import javax.swing.SwingUtilities;
58 import javax.swing.event.ChangeEvent;
59 import javax.swing.event.ChangeListener;
60 import javax.swing.filechooser.FileFilter;
61 import javax.swing.text.BadLocationException;
62 import javax.swing.text.EditorKit;
63 import javax.swing.text.View;
64 import javax.swing.undo.UndoManager;
65
66 import org.w3c.dom.Document;
67
68 import org.flexdock.docking.event.DockingEvent;
69 import org.scilab.modules.commons.CommonFileUtils;
70 import org.scilab.modules.commons.gui.ScilabKeyStroke;
71 import org.scilab.modules.commons.xml.ScilabXMLUtilities;
72 import org.scilab.modules.commons.xml.XConfiguration;
73 import static org.scilab.modules.commons.xml.XConfiguration.XConfAttribute;
74 import org.scilab.modules.core.Scilab;
75 import org.scilab.modules.gui.bridge.filechooser.SwingScilabFileChooser;
76 import org.scilab.modules.gui.bridge.tab.SwingScilabDockablePanel;
77 import org.scilab.modules.gui.bridge.window.SwingScilabWindow;
78 import org.scilab.modules.gui.filechooser.Juigetfile;
79 import org.scilab.modules.gui.filechooser.ScilabFileChooser;
80 import org.scilab.modules.gui.menubar.MenuBar;
81 import org.scilab.modules.gui.messagebox.MessageBox;
82 import org.scilab.modules.gui.messagebox.ScilabMessageBox;
83 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
84 import org.scilab.modules.gui.messagebox.ScilabModalDialog.AnswerOption;
85 import org.scilab.modules.gui.messagebox.ScilabModalDialog.ButtonType;
86 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
87 import org.scilab.modules.gui.tab.SimpleTab;
88 import org.scilab.modules.gui.tabfactory.ScilabTabFactory;
89 import org.scilab.modules.gui.textbox.TextBox;
90 import org.scilab.modules.gui.toolbar.ToolBar;
91 import org.scilab.modules.gui.utils.ClosingOperationsManager;
92 import org.scilab.modules.gui.utils.ConfigManager;
93 import org.scilab.modules.gui.utils.Position;
94 import org.scilab.modules.gui.utils.SciFileFilter;
95 import org.scilab.modules.gui.utils.Size;
96 import org.scilab.modules.gui.utils.WindowsConfigurationManager;
97
98 import org.scilab.modules.scinotes.actions.DoubleQuoteStringAction;
99 import org.scilab.modules.scinotes.actions.EncodingAction;
100 import org.scilab.modules.scinotes.actions.EndOfLineAction;
101 import org.scilab.modules.scinotes.actions.ExitAction;
102 import org.scilab.modules.scinotes.actions.FindAction;
103 import org.scilab.modules.scinotes.actions.IncrementalSearchAction;
104 import org.scilab.modules.scinotes.actions.IndentAction;
105 import org.scilab.modules.scinotes.actions.InsertOverwriteAction;
106 import org.scilab.modules.scinotes.actions.LineBeautifierAction;
107 import org.scilab.modules.scinotes.actions.OpenSourceFileOnKeywordAction;
108 import org.scilab.modules.scinotes.actions.RecentFileAction;
109 import org.scilab.modules.scinotes.actions.RegisterFavoriteDirsAction;
110 import org.scilab.modules.scinotes.actions.RemoveTrailingWhiteAction;
111 import org.scilab.modules.scinotes.actions.RestoreOpenedFilesAction;
112 import org.scilab.modules.scinotes.actions.SciNotesCompletionAction;
113 import org.scilab.modules.scinotes.actions.SearchWordInFilesAction;
114 import org.scilab.modules.scinotes.tabfactory.CodeNavigatorTab;
115 import org.scilab.modules.scinotes.tabfactory.SciNotesTab;
116 import org.scilab.modules.scinotes.tabfactory.SciNotesTabFactory;
117 import org.scilab.modules.scinotes.tabfactory.SearchInFilesTab;
118 import org.scilab.modules.scinotes.utils.ConfigSciNotesManager;
119 import org.scilab.modules.scinotes.utils.DropFilesListener;
120 import org.scilab.modules.scinotes.utils.NavigatorWindow;
121 import org.scilab.modules.scinotes.utils.SaveFile;
122 import org.scilab.modules.scinotes.utils.SciNotesContents;
123 import org.scilab.modules.scinotes.utils.SciNotesMessages;
124 import org.scilab.modules.scinotes.utils.ScilabTabbedPane;
125 import org.scilab.modules.scinotes.utils.SearchFile;
126
127 /**
128  * Main SciNotes class.
129  *
130  * @author Bruno JOFRET
131  * @author Calixte DENIZET
132  */
133 public class SciNotes extends SwingScilabDockablePanel {
134
135     private static final long serialVersionUID = -6410183357490518676L;
136
137     private static final String XPATH_SCINOTES_KEY = "//general/shortcuts/body/actions/action-folder[@name='Scinotes']/action";
138     private static final String XPATH_SCINOTES_ACTION = "/map/scinotes/entry";
139
140     private static final String SCINOTES = "SciNotes";
141     private static final String SCI_EXTENSION = ".sci";
142     private static final String SCE_EXTENSION = ".sce";
143     private static final String TST_EXTENSION = ".tst";
144     private static final String QUIT_EXTENSION = ".quit";
145     private static final String DEM_EXTENSION = ".dem";
146     private static final String START_EXTENSION = ".start";
147     private static final String ALL_TST_FILES = "*.tst";
148     private static final String ALL_QUIT_FILES = "*.quit";
149     private static final String ALL_START_FILES = "*.start";
150     private static final String ALL_SCI_FILES = "*.sci";
151     private static final String ALL_SCE_FILES = "*.sce";
152     private static final String ALL_DEM_FILES = "*.dem";
153     private static final String ALL_SCX_FILES = "*.sc*";
154     private static final String ALL_SCILAB = "all";
155     private static final String ALL_FILES = "*.*";
156     private static final String DOT = ".";
157
158     private static final String DEFAULTACTIONPATH = "org.scilab.modules.scinotes.actions";
159
160     private static final Map<String, String> actionToName;
161     private static Map<String, KeyStroke> actionKeys;
162
163     private static List<SciNotes> scinotesList = new ArrayList<SciNotes>();
164     private static SciNotes editor;
165     private static boolean mustWrapLines;
166
167     private SwingScilabWindow parentWindow;
168     private UUID uuid;
169
170     private ScilabTabbedPane tabPane;
171     private final SciNotesContents contentPane;
172     private NavigatorWindow navigator;
173     private SearchFile searchInFiles;
174
175     private int numberOfUntitled;
176     private EditorKit editorKit;
177
178     private JButton undoButton;
179     private JButton redoButton;
180
181     private boolean protectOpenFileList;
182     private boolean restored;
183     private boolean firstOpen = true;
184
185     private final List<Integer> tabList = new ArrayList<Integer>();
186     private final List<Integer> closedTabList = new ArrayList<Integer>();
187
188     static {
189         ConfigSciNotesManager.createUserCopy();
190         ScilabTabFactory.getInstance().addTabFactory(SciNotesTabFactory.getInstance());
191         Scilab.registerInitialHook(new Runnable() {
192             @Override
193             public void run() {
194                 updateSciNotes();
195             }
196         });
197
198         Document doc = ScilabXMLUtilities.readDocument(System.getenv("SCI") + "/modules/console/etc/Actions-Configuration.xml");
199         actionToName = XConfiguration.get(doc, "name", String.class, "action", String.class, XPATH_SCINOTES_ACTION);
200         XConfiguration.addXConfigurationListener(new SciNotesConfiguration());
201     }
202
203     /**
204      * Create SciNotes instance
205      */
206     public SciNotes(String uuid) {
207         super(SCINOTES, uuid);
208         setWindowIcon("accessories-text-editor");
209         setAssociatedXMLIDForHelp("scinotes");
210         this.uuid = UUID.fromString(uuid);
211         SciNotesAutosave.autosave();
212         editor = this;
213         scinotesList.add(this);
214         numberOfUntitled = 0;
215         mustWrapLines = SciNotesOptions.getSciNotesDisplay().wrapLines;
216         editorKit = new ScilabEditorKit(!mustWrapLines);
217         protectOpenFileList = false;
218         contentPane = new SciNotesContents(this);
219         tabPane = contentPane.getScilabTabbedPane();
220         tabPane.addChangeListener(new ChangeListener() {
221             @Override
222             public void stateChanged(ChangeEvent e) {
223                 if (getTextPane() != null) {
224                     // updateUI();
225                     getTextPane().updateInfosWhenFocused();
226                     getTextPane().requestFocus();
227                     getTextPane().highlightWords(IncrementalSearchAction.getWord(SciNotes.this), IncrementalSearchAction.getExact(SciNotes.this));
228
229                     // Update encoding menu
230                     EncodingAction.updateEncodingMenu((ScilabDocument) getTextPane().getDocument());
231
232                     // Update End Of Line menu
233                     EndOfLineAction.updateEolMenu((ScilabDocument) getTextPane().getDocument());
234                     setTitle(getTextPane().getTitle());
235                 }
236             }
237         });
238         this.setContentPane(contentPane);
239     }
240
241     /**
242      * Default constructor
243      */
244     public SciNotes() {
245         this(UUID.randomUUID().toString());
246     }
247
248     public static void configurationChanged(SciNotesConfiguration.Conf conf) {
249         setWhereamiLineNumbering();
250         setAutoIndent();
251         setHorizontalWrap();
252         setDefaultTabulation();
253         if (conf.keymap) {
254             actionKeys = null;
255             setKeyStrokeActions();
256             setAllMenus();
257         }
258         if (conf.autosave) {
259             SciNotesAutosave.stopAutosave();
260             SciNotesAutosave.autosave();
261         }
262         if (conf.preferences) {
263             RecentFileAction.updateRecentOpenedFilesMenu();
264         }
265
266         updatePanes(conf);
267     }
268
269     public static Map<String, KeyStroke> getActionKeys() {
270         if (actionKeys == null) {
271             Document doc = XConfiguration.getXConfigurationDocument();
272             actionKeys = XConfiguration.get(doc, "name", String.class, "key", KeyStroke.class, XPATH_SCINOTES_KEY);
273         }
274
275         return actionKeys;
276     }
277
278     public static Map<String, String> getActionName() {
279         return actionToName;
280     }
281
282     /**
283      * Get an opened editor from its uuid
284      *
285      * @param uuid
286      *            the uuid
287      * @return the corresponding editor
288      */
289     public static SciNotes getEditorFromUUID(String uuid) {
290         for (SciNotes ed : scinotesList) {
291             if (ed.getPersistentId().equals(uuid)) {
292                 return ed;
293             }
294         }
295
296         return null;
297     }
298
299     public void setParentWindow() {
300         this.parentWindow = SwingScilabWindow.createWindow(true);
301         parentWindow.setLocation(150, 50);
302         parentWindow.setSize(650, 550);
303     }
304
305     /**
306      * {@inheritDoc}
307      */
308     @Override
309     public void setTitle(String title) {
310         super.setTitle(title);
311         SwingScilabWindow window = (SwingScilabWindow) SwingUtilities.getAncestorOfClass(SwingScilabWindow.class, tabPane);
312         if (window != null) {
313             window.setTitle(title);
314         }
315     }
316
317     public void insertBottomComponent(Component c) {
318         contentPane.insertBottomComponent(c);
319     }
320
321     /**
322      * @return the SwingScilabWindow containing this editor
323      */
324     public SwingScilabWindow getSwingParentWindow() {
325         return (SwingScilabWindow) SwingUtilities.getAncestorOfClass(SwingScilabWindow.class, this);
326     }
327
328     /**
329      * {@inheritDoc}
330      */
331     @Override
332     public void undockingComplete(DockingEvent evt) {
333         super.undockingComplete(evt);
334         if (navigator != null) {
335             navigator.addToolBar(null);
336         }
337         if (searchInFiles != null) {
338             searchInFiles.addToolBar(null);
339         }
340     }
341
342     /**
343      * {@inheritDoc}
344      */
345     @Override
346     public void dockingComplete(DockingEvent evt) {
347         super.dockingComplete(evt);
348         if (navigator != null) {
349             navigator.changeToolBar();
350         }
351         if (searchInFiles != null) {
352             searchInFiles.changeToolBar();
353         }
354     }
355
356     /**
357      * Add a code navigator
358      */
359     public void addNavigator() {
360         if (navigator == null) {
361             String navUUID = ConfigSciNotesManager.getCodeNavigatorStateForEditor(getPersistentId());
362             boolean success = WindowsConfigurationManager.restoreUUID(navUUID);
363             if (!success) {
364                 navigator = CodeNavigatorTab.getCodeNavigatorInstance(this, null);
365                 navigator.setParentWindow();
366             }
367             int count = getTabPane().getTabCount();
368             for (int i = 0; i < count; i++) {
369                 navigator.addEditorPane(getTextPane(i));
370             }
371         }
372     }
373
374     /**
375      * Add a code navigator
376      */
377     public void addNavigator(NavigatorWindow navigator) {
378         this.navigator = navigator;
379     }
380
381     /**
382      * Remove the navigator
383      */
384     public void removeNavigator() {
385         navigator = null;
386     }
387
388     /**
389      * @return the navigator associated with this editor
390      */
391     public NavigatorWindow getNavigator() {
392         return navigator;
393     }
394
395     /**
396      * Add a Search in files
397      */
398     public void addSearchInFiles() {
399         if (searchInFiles == null) {
400             String sfUUID = ConfigSciNotesManager.getSearchInFilesStateForEditor(getPersistentId());
401             boolean success = WindowsConfigurationManager.restoreUUID(sfUUID);
402             if (!success) {
403                 searchInFiles = SearchInFilesTab.getSearchInFilesTabInstance(this, null);
404                 searchInFiles.setParentWindow();
405             }
406         }
407     }
408
409     /**
410      * Add a Search In Files
411      */
412     public void addSearchInFiles(SearchFile sf) {
413         this.searchInFiles = sf;
414     }
415
416     /**
417      * Remove Search in Files
418      */
419     public void removeSearchInFiles() {
420         searchInFiles = null;
421     }
422
423     /**
424      * @return the Search In Files associated with this editor
425      */
426     public SearchFile getSearchInFiles() {
427         return searchInFiles;
428     }
429
430     /**
431      * Update the editor
432      */
433     public static void updateSciNotes() {
434         ScilabLexer.update();
435         for (SciNotes editor : scinotesList) {
436             if (editor.getTextPane() != null) {
437                 editor.getTextPane().repaint();
438             }
439         }
440     }
441
442     /**
443      * Launch SciNotes with an empty file
444      *
445      * This method *must not* be called on the EDT thread.
446      */
447     public static void scinotes() {
448         ScilabLexer.update();
449         try {
450             SwingUtilities.invokeAndWait(new Runnable() {
451
452                 @Override
453                 public void run() {
454                     launchSciNotes();
455                     // Open an empty file if no tabs were opened at launch.
456                     if (editor.getTabPane().getTabCount() == 0) {
457                         editor.openFile(null, 0, null);
458                     }
459                 }
460             });
461         } catch (InterruptedException e) {
462             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
463             throw new RuntimeException(e);
464         } catch (InvocationTargetException e) {
465             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
466             e.printStackTrace();
467             throw new RuntimeException(e);
468         }
469     }
470
471     /**
472      * Launch SciNotes with a file name to open.
473      *
474      * @param filePath
475      *            the name of the file to open
476      *
477      *            This method *must not* be called on the EDT thread.
478      */
479     public static void scinotes(final String filePath) {
480         ScilabLexer.update();
481         try {
482             SwingUtilities.invokeAndWait(new Runnable() {
483
484                 @Override
485                 public void run() {
486                     launchSciNotes();
487                     editor.openFile(filePath, 0, null);
488                 }
489             });
490         } catch (InterruptedException e) {
491             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
492             throw new RuntimeException(e);
493         } catch (InvocationTargetException e) {
494             e.printStackTrace();
495             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
496             throw new RuntimeException(e);
497         }
498     }
499
500     /**
501      * Launch SciNotes with a file name to open and a line to highlight.
502      *
503      * @param filePath
504      *            the name of the file to open
505      * @param lineNumber
506      *            the line to highlight
507      *
508      *            This method *must not* be called on the EDT thread.
509      */
510     public static void scinotes(final String filePath, final int lineNumber, final String functionName) {
511         ScilabLexer.update();
512         try {
513             SwingUtilities.invokeAndWait(new Runnable() {
514
515                 @Override
516                 public void run() {
517                     launchSciNotes();
518                     editor.openFile(filePath, lineNumber, functionName);
519                 }
520             });
521         } catch (InterruptedException e) {
522             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
523             throw new RuntimeException(e);
524         } catch (InvocationTargetException e) {
525             e.printStackTrace();
526             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
527             throw new RuntimeException(e);
528         }
529     }
530
531     /**
532      * Launch SciNotes with a file name to open and a line to highlight.
533      *
534      * @param filePath
535      *            the name of the file to open
536      * @param option
537      *            such as 'readonly'
538      *
539      *            This method *must not* be called on the EDT thread.
540      */
541     public static void scinotes(final String filePath, final String[] options) throws Exception {
542         boolean hasAction = false;
543         if (options != null && options.length != 0) {
544             try {
545                 hasAction = executeAction(filePath, options);
546             } catch (FileNotFoundException e) {
547                 throw new Exception(String.format(SciNotesMessages.INVALID_FILE, filePath));
548             } catch (IOException e) {
549                 throw new Exception(String.format(SciNotesMessages.IO_EXCEPTION, e.getLocalizedMessage()));
550             }
551         }
552
553         if (hasAction) {
554             return;
555         }
556
557         ScilabLexer.update();
558         try {
559             SwingUtilities.invokeAndWait(new Runnable() {
560
561                 @Override
562                 public void run() {
563                     launchSciNotes();
564                     if (options != null && options.length != 0) {
565                         editor.openFile(filePath, 0, options[0]);
566                     } else {
567                         editor.openFile(filePath, 0, "");
568                     }
569                 }
570             });
571         } catch (InterruptedException e) {
572             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
573             throw new RuntimeException(e);
574         } catch (InvocationTargetException e) {
575             e.printStackTrace();
576             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
577             throw new RuntimeException(e);
578         }
579     }
580
581     /**
582      * Launch SciNotes with a provided text (from the help for example).
583      *
584      * @param text
585      *            the text which should be modified
586      */
587     public static void scinotesWithText(String text) {
588         ScilabLexer.update();
589         launchSciNotes();
590         ScilabEditorPane theTextPane;
591         if (editor.getTabPane().getTabCount() != 0 && editor.getTextPane(0) != null) {
592             String name = editor.getTextPane(0).getName();
593             if (name == null) {
594                 theTextPane = editor.getTextPane(0);
595             } else {
596                 theTextPane = editor.addEmptyTab();
597             }
598         } else {
599             theTextPane = editor.addEmptyTab();
600         }
601
602         ScilabDocument styleDocument = (ScilabDocument) theTextPane.getDocument();
603         try {
604             editor.getEditorKit().read(new StringReader(text), styleDocument, theTextPane.getCaretPosition());
605         } catch (IOException e) {
606             System.err.println(SciNotesMessages.ERROR_WITH_STRING);
607         } catch (BadLocationException e) {
608             System.err.println(SciNotesMessages.ERROR_WITH_STRING);
609         }
610     }
611
612     /**
613      * Clone the current tab and if b is true close the tab
614      *
615      * @param ed
616      *            the editor where the tab is
617      * @param b
618      *            a boolean
619      */
620     public static void cloneAndCloseCurrentTab(SciNotes ed, boolean b) {
621         ScilabDocument cdoc = (ScilabDocument) ed.getTextPane().getDocument();
622         String title = ed.getTabPane().getScilabTitleAt(ed.getTabPane().getSelectedIndex());
623         ScilabEditorPane currentSep = ed.getTextPane();
624         String winTitle = ed.getTitle();
625
626         if (b) {
627             ed.closeTabAtWithoutConfirmation(ed.getTabPane().getSelectedIndex());
628             if (ed.getTabPane().getTabCount() == 0) {
629                 ClosingOperationsManager.startClosingOperationWithoutSave((SwingScilabDockablePanel) ed);
630                 ConfigSciNotesManager.removeEditorUUID(ed.uuid.toString());
631             }
632         }
633
634         editor = null;
635
636         scinotesWithText(cdoc.getText());
637         ScilabEditorPane sep = editor.getTextPane();
638
639         if (currentSep.getName() != null) {
640             sep.setTitle(title);
641             editor.setTitle(winTitle);
642         }
643
644         currentSep.copyProps(sep);
645         ScilabDocument sdoc = (ScilabDocument) sep.getDocument();
646         sdoc.setContentModified(cdoc.isContentModified());
647         sdoc.getUndoManager().discardAllEdits();
648         sep.setCaretPosition(0);
649         editor.enableUndoButton(false);
650         editor.enableRedoButton(false);
651         ConfigSciNotesManager.saveToOpenFiles(sep.getName(), editor, editor.getTextPane());
652
653         editor.activeRestoreTab();
654     }
655
656     /**
657      * Clone the current tab and if b is true close the tab
658      *
659      * @param ed
660      *            the editor where the tab is
661      * @param b
662      *            a boolean
663      */
664     public static void cloneAndCloseCurrentTab(SciNotes ed, boolean b, int x, int y) {
665         cloneAndCloseCurrentTab(ed, b);
666         editor.getSwingParentWindow().setLocation(x, y);
667     }
668
669     /**
670      * Execute after when the restoration is finished
671      */
672     @Override
673     public void endedRestoration() {
674         if (!SwingUtilities.isEventDispatchThread()) {
675             try {
676                 SwingUtilities.invokeAndWait(new Runnable() {
677
678                     @Override
679                     public void run() {
680                         restorePreviousSession();
681                     }
682                 });
683             } catch (InterruptedException e) {
684                 Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
685                 throw new RuntimeException(e);
686             } catch (InvocationTargetException e) {
687                 Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
688                 throw new RuntimeException(e);
689             }
690         } else {
691             restorePreviousSession();
692         }
693     }
694
695     /**
696      * Restore the previous session
697      */
698     public void restorePreviousSession() {
699         restored = true;
700         if (!SciNotesOptions.getSciNotesPreferences().restartOpen || !ConfigSciNotesManager.getRestoreOpenedFiles() || ConfigSciNotesManager.countExistingOpenFiles(getUUID()) == 0) {
701             if (getTabPane().getTabCount() == 0) {
702                 openFile(null, 0, null);
703             }
704
705             WindowsConfigurationManager.restorationFinished(this);
706
707             return;
708         }
709
710         addRestoreTab();
711         WindowsConfigurationManager.restorationFinished(SciNotes.this);
712         if  (System.getProperty("os.name").toLowerCase().contains("mac")) {
713           RestoreOpenedFilesAction.restoreEnabledComponents(this);
714         }
715     }
716
717     /**
718      * Create SciNotes instance
719      *
720      * @return the instance
721      */
722     public static void launchSciNotes() {
723         if (editor == null) {
724             List<String> uuids = ConfigSciNotesManager.getEditorsUUID();
725             boolean success = false;
726             if (!uuids.isEmpty()) {
727                 for (String uuid : uuids) {
728                     boolean exists = false;
729                     for (SciNotes ed : scinotesList) {
730                         if (ed.uuid.toString().equals(uuid)) {
731                             exists = true;
732                             break;
733                         }
734                     }
735                     if (!exists) {
736                         success = WindowsConfigurationManager.restoreUUID(uuid);
737                         if (success) {
738                             break;
739                         }
740                         ConfigSciNotesManager.removeEditorUUID(uuid);
741                     }
742                 }
743             }
744             if (!success) {
745                 editor = SciNotesTab.getEditorInstance(null);
746                 editor.setParentWindow();
747                 ConfigSciNotesManager.saveEditorUUID(editor.getPersistentId());
748                 SciNotesGUI.init(editor.getParentWindow(), editor, SCINOTES);
749                 WindowsConfigurationManager.unregisterEndedRestoration(editor);
750             }
751         } else {
752             /* restore if it is iconified */
753             if (editor.getParentWindow() != null) {
754                 int state = editor.getParentWindow().getExtendedState();
755                 if ((state & JFrame.ICONIFIED) == JFrame.ICONIFIED) {
756                     editor.getParentWindow().setExtendedState(state - JFrame.ICONIFIED);
757                 }
758             }
759         }
760
761         if (!editor.restored) {
762             editor.restorePreviousSession();
763         }
764
765         /* Bug #14489 */
766         SwingScilabWindow window = (SwingScilabWindow) SwingUtilities.getAncestorOfClass(SwingScilabWindow.class, editor.getTabPane());
767         if (window != null) {
768             window.toFront();
769         }
770
771     }
772
773     /**
774      * Open a file.
775      *
776      * This method *must* be called on the EDT thread.
777      *
778      * @param filePath
779      *            the file path (may be null)
780      * @param lineNumber
781      *            the line number (use 0 for unspecified)
782      * @param option
783      *            the options (may be null)
784      */
785     public void openFile(String filePath, int lineNumber, String option) {
786         if (!SwingUtilities.isEventDispatchThread()) {
787             throw new RuntimeException("called outside the EDT thread.");
788         }
789
790         if (filePath == null) {
791             addEmptyTab();
792             activeRestoreTab();
793             return;
794         }
795
796         File f = fileToCanonicalFile(new File(filePath));
797         if (!f.getParentFile().exists()) {
798             JOptionPane.showMessageDialog(SciNotes.this, SciNotesMessages.OPEN_ERROR);
799             addEmptyTab();
800             activeRestoreTab();
801             return;
802         }
803
804         if (f.isDirectory()) { /* Bug 5131 */
805             ConfigManager.saveLastOpenedDirectory(f.getPath());
806             addEmptyTab();
807             activeRestoreTab();
808             return;
809         }
810
811         readFileAndWait(f);
812         if (option == null || option.length() == 0 || "readonly".equals(option.toLowerCase())) {
813             getTextPane().scrollTextToLineNumber(lineNumber, true);
814         } else {
815             getTextPane().scrollTextToLineNumberInWhereami(lineNumber, option, true);
816         }
817         if ((option != null && "readonly".equals(option.toLowerCase()))) {
818             getTextPane().setReadOnly(true);
819             getInfoBar().setText(getTextPane().getInfoBarText());
820             ConfigSciNotesManager.removeFromOpenFiles(this, getTextPane());
821         } else {
822             ConfigSciNotesManager.saveToRecentOpenedFiles(filePath);
823             RecentFileAction.updateRecentOpenedFilesMenu(this);
824         }
825
826         activeRestoreTab();
827     }
828
829     public void activeRestoreTab() {
830         if (getTextPane(0) == null) {
831             tabPane.setSelectedIndex(0);
832             getInfoBar().setText("");
833         }
834     }
835
836     /**
837      * Close SciNotes instance including all tabs.
838      */
839     public void closeSciNotes() {
840         for (int i = 0; i < getTabPane().getTabCount(); i++) {
841             ScilabEditorPane textPaneAt = getTextPane(i);
842             if (textPaneAt != null) {
843                 textPaneAt.destroy();
844             }
845         }
846
847         FindAction.close();
848         IncrementalSearchAction.close(this);
849         RecentFileAction.close(this);
850         OpenSourceFileOnKeywordAction.closeOpenSourceWindow();
851         SearchWordInFilesAction.closeWindow();
852
853         /*
854          * setProtectOpenFileList(true); while (getTabPane().getTabCount() > 0)
855          * { closeTabAt(0, true); } setProtectOpenFileList(false);
856          */
857
858         scinotesList.remove(this);
859         if (scinotesList.size() == 0) {
860             SciNotesAutosave.stopAutosave();
861             ScilabEditorPane.clean();
862             RegisterFavoriteDirsAction.close();
863             OpenSourceFileOnKeywordAction.close();
864             EncodingAction.close();
865             EndOfLineAction.close();
866             HelpOnTypingManager.close();
867         }
868
869         editor = null;
870         SciNotesGUI.clean(this);
871         close();
872         ConfigSciNotesManager.resetDocument();
873     }
874
875     public boolean canClose() {
876         int numberOfTab = getTabPane().getTabCount();
877         setProtectOpenFileList(true);
878
879         for (int i = 0; i < numberOfTab; i++) {
880             boolean ans = checkToCloseTabAt(i);
881             if (!ans) {
882                 setProtectOpenFileList(false);
883                 return false;
884             }
885         }
886         setProtectOpenFileList(false);
887
888         return true;
889     }
890
891     public String askForClosing() {
892         int numberOfTab = getTabPane().getTabCount();
893         boolean isContentModified = false;
894         for (int i = 0; i < getTabPane().getTabCount(); i++) {
895             ScilabEditorPane textPaneAt = getTextPane(i);
896             if (textPaneAt != null && ((ScilabDocument) textPaneAt.getDocument()).isContentModified()) {
897                 isContentModified = true;
898                 break;
899             }
900         }
901
902         if (isContentModified) {
903             return "SciNotes";
904         }
905
906         return null;
907     }
908
909     public static void closeEditor(SciNotes ed) {
910         if (scinotesList.size() > 1) {
911             ClosingOperationsManager.startClosingOperationWithoutSave((SwingScilabDockablePanel) ed);
912         } else {
913             ClosingOperationsManager.startClosingOperation((SwingScilabDockablePanel) ed);
914         }
915     }
916
917     /**
918      * Close a tab using its index.
919      *
920      * @param indexTab
921      *            the index of the tab
922      * @return if the tab has been really closed
923      */
924     public boolean closeTabAtWithoutConfirmation(int indexTab) {
925         return closeTabAt(indexTab, false, false);
926     }
927
928     /**
929      * Close a tab using its index.
930      *
931      * @param indexTab
932      *            the index of the tab
933      * @return if the tab has been really closed
934      */
935     public boolean closeTabAt(int indexTab) {
936         return closeTabAt(indexTab, false, true);
937     }
938
939     /**
940      * Close a tab using its index.
941      *
942      * @param indexTab
943      *            the index of the tab
944      * @param scilabClose
945      *            if true, save dialog confirmation cannot be canceled
946      * @return if the tab has been really closed
947      */
948     public boolean closeTabAt(int indexTab, boolean scilabClose, boolean confirmation) {
949         ScilabEditorPane textPaneAt = getTextPane(indexTab);
950
951         /*
952          * Test for modification added after bug 5103 fix: do not ask the user
953          * for an Untitled not-modified file saving when closing SciNotes
954          */
955         if (confirmation && ((ScilabDocument) textPaneAt.getDocument()).isContentModified()) {
956             if (!save(indexTab, false, scilabClose)) {
957                 return false;
958             }
959         }
960
961         textPaneAt.close();
962
963         if (textPaneAt.getName() == null) {
964             String closedTabName = tabPane.getScilabTitleAt(indexTab);
965             String closedTabNameIndex = closedTabName.substring(closedTabName.length() - 1, closedTabName.length());
966             tabList.remove(Integer.valueOf(closedTabNameIndex));
967             closedTabList.add(Integer.valueOf(closedTabNameIndex));
968         }
969
970         // correction for bug 5404, closing the last tabPane generate an
971         // exception
972         // that's why we need to remove ChangeListeners before closing
973         if ((indexTab == 0) && (getTabPane().getTabCount() == 1)) {
974             for (int i = 0; i < tabPane.getChangeListeners().length; i++) {
975                 tabPane.removeChangeListener(tabPane.getChangeListeners()[i]);
976             }
977         }
978
979         // Remove the filename associated with the tab from the list of open
980         // files.
981         if (!protectOpenFileList) {
982             ConfigSciNotesManager.removeFromOpenFiles(this, textPaneAt);
983         }
984
985         if (navigator != null) {
986             navigator.removePane(textPaneAt);
987         }
988
989         tabPane.remove(indexTab);
990
991         textPaneAt = getTextPane();
992         if (textPaneAt != null) {
993             if (navigator != null) {
994                 navigator.update((ScilabDocument) textPaneAt.getDocument());
995             }
996         }
997         return true;
998     }
999
1000     public boolean checkToCloseTabAt(int index) {
1001         ScilabEditorPane textPaneAt = getTextPane(index);
1002
1003         /*
1004          * Test for modification added after bug 5103 fix: do not ask the user
1005          * for an Untitled not-modified file saving when closing SciNotes
1006          */
1007         if (textPaneAt != null && ((ScilabDocument) textPaneAt.getDocument()).isContentModified()) {
1008             if (!save(index, false, false)) {
1009                 return false;
1010             }
1011         }
1012
1013         return true;
1014     }
1015
1016     /**
1017      * Set or unset protection of the currently open file list. Call before
1018      * closing tabs if the tabs should be restored when scinotes restarts.
1019      *
1020      * @param protect
1021      *            Enables protection of the open file list if true.
1022      */
1023     public void setProtectOpenFileList(boolean protect) {
1024         protectOpenFileList = protect;
1025     }
1026
1027     /**
1028      * Determines if this editor is the only editor instance.
1029      *
1030      * @return true if this is the last editor instance.
1031      */
1032     public boolean isOnlyInstance() {
1033         if (scinotesList.size() > 1) {
1034             return false;
1035         }
1036
1037         return true;
1038     }
1039
1040     /**
1041      * @return the list of the different openened editors
1042      */
1043     public static List<SciNotes> getSciNotesList() {
1044         return scinotesList;
1045     }
1046
1047     /**
1048      * Save a file.
1049      *
1050      * @param indexTab
1051      *            the textPane index containing the file contents
1052      * @return execution status
1053      */
1054     public boolean save(int indexTab) {
1055         return save(indexTab, false, false);
1056     }
1057
1058     /**
1059      * Save a file.
1060      *
1061      * @param indexTab
1062      *            the textPane index containing the file contents
1063      * @param force
1064      *            : force save without confirmation dialog ( SaveAction )
1065      * @return execution status
1066      */
1067     public boolean save(int indexTab, boolean force) {
1068         return save(indexTab, force, false);
1069     }
1070
1071     /**
1072      * Save a file.
1073      *
1074      * @param indexTab
1075      *            the textPane index containing the file contents
1076      * @param force
1077      *            : force save without confirmation dialog ( SaveAction )
1078      * @param scilabClose
1079      *            : if true, save dialog confirmation cannot be canceled
1080      * @return execution status
1081      */
1082     public boolean save(int indexTab, boolean force, boolean scilabClose) {
1083         ScilabEditorPane textPaneAt = getTextPane(indexTab);
1084         getTabPane().setSelectedIndex(indexTab);
1085
1086         // if the file ( empty, new or loaded ) is not modified, exit save
1087         // process and return true
1088         if (!textPaneAt.checkExternalModif() && !((ScilabDocument) textPaneAt.getDocument()).isContentModified() && (textPaneAt.getName() != null)) {
1089             /*
1090              * Bug
1091              * 5103
1092              * fix
1093              */
1094             return true;
1095         }
1096
1097         if (!force) {
1098             AnswerOption answer;
1099             if (scilabClose) {
1100                 answer = ScilabModalDialog.show(this, String.format(SciNotesMessages.MODIFIED, textPaneAt.getShortName()), SciNotesMessages.SCILAB_EDITOR,
1101                                                 IconType.QUESTION_ICON, ButtonType.YES_NO);
1102             } else {
1103                 answer = ScilabModalDialog.show(this, String.format(SciNotesMessages.MODIFIED, textPaneAt.getShortName()), SciNotesMessages.SCILAB_EDITOR,
1104                                                 IconType.QUESTION_ICON, ButtonType.YES_NO_CANCEL);
1105             }
1106
1107             switch (answer) {
1108                 case YES_OPTION: // Yes, continue
1109                     break;
1110                 case NO_OPTION:// No, exit and returns true
1111                     return true;
1112                 case CANCEL_OPTION: // Cancel, exit and return false
1113                     return false;
1114                 default:
1115                     break;
1116             }
1117         }
1118
1119         String fileToSave = textPaneAt.getName();
1120         if (fileToSave == null) {
1121             // need a filename, call chooseFileToSave
1122             fileToSave = chooseFileToSave(SciNotesMessages.SAVE);
1123         } else {
1124             // check if the file has been modified by external software
1125             fileToSave = checkExternalModification(fileToSave);
1126         }
1127
1128         if (fileToSave == null || fileToSave.length() == 0) {
1129             return true; /*
1130                           * Bug 5189: The user cancels ==> do not want an error
1131                           * message
1132                           */
1133         }
1134
1135         File newSavedFile = new File(fileToSave);
1136
1137         if (!SaveFile.doSave(textPaneAt, indexTab, newSavedFile, editorKit)) {
1138             return false;
1139         }
1140
1141         ScilabDocument styledDocument = (ScilabDocument) textPaneAt.getDocument();
1142         styledDocument.setContentModified(false);
1143
1144         textPaneAt.setLastModified(newSavedFile.lastModified());
1145
1146         if (textPaneAt.getName() == null) {
1147             String name = getTabPane().getScilabTitleAt(indexTab);
1148             String index = name.substring(name.length() - 1, name.length());
1149             tabList.remove(Integer.valueOf(index));
1150             closedTabList.add(Integer.valueOf(index));
1151         }
1152
1153         textPaneAt.setName(fileToSave);
1154         getTabPane().setTitleAt(indexTab, newSavedFile.getName());
1155
1156         setTitle(textPaneAt.getTitle());
1157         ConfigSciNotesManager.saveToOpenFiles(fileToSave, this, textPaneAt);
1158
1159         return true;
1160     }
1161
1162     /**
1163      * Overwrite the file at a given index.
1164      *
1165      * @param indexTab
1166      *            the textPane index containing the file contents
1167      * @return execution status
1168      */
1169     public boolean overwrite(int indexTab) {
1170         ScilabEditorPane textPaneAt = getTextPane(indexTab);
1171         String fileToSave = textPaneAt.getName();
1172         if (fileToSave == null) {
1173             return true;
1174         }
1175
1176         File newSavedFile = new File(fileToSave);
1177         if (!newSavedFile.exists()) {
1178             return true;
1179         }
1180
1181         if (!SaveFile.doSave(textPaneAt, indexTab, newSavedFile, editorKit)) {
1182             return false;
1183         }
1184
1185         ScilabDocument styledDocument = (ScilabDocument) textPaneAt.getDocument();
1186         styledDocument.setContentModified(false);
1187
1188         getTabPane().setTitleAt(getTabPane().getSelectedIndex(), newSavedFile.getName());
1189
1190         // Get current file path for Execute file into Scilab
1191         getTextPane().setLastModified(newSavedFile.lastModified());
1192
1193         textPaneAt.setName(fileToSave);
1194         setTitle(textPaneAt.getTitle());
1195
1196         return true;
1197     }
1198
1199     /**
1200      * Check for external modification. If it is the case, propose to select a
1201      * new file name.
1202      *
1203      * @param filename
1204      *            The name of the file
1205      * @return the filename where to save
1206      */
1207     public String checkExternalModification(String filename) {
1208         File newSavedFile = new File(filename);
1209         if (newSavedFile.lastModified() > getTextPane().getLastModified()) {
1210             if (ScilabModalDialog.show(this, String.format(SciNotesMessages.EXTERNAL_MODIFICATION, newSavedFile.getPath()),
1211                                        SciNotesMessages.REPLACE_FILE_TITLE, IconType.QUESTION_ICON, ButtonType.YES_NO) == AnswerOption.NO_OPTION) {
1212                 return chooseFileToSave(SciNotesMessages.SAVE);
1213             }
1214         }
1215         return filename;
1216     }
1217
1218     /**
1219      * Return through a file selector the name of the selected file.
1220      *
1221      * @param title
1222      *            the title for JFileChooser
1223      * @return the file picked up by the user
1224      */
1225     public String chooseFileToSave(String title) {
1226         return chooseFileToSave(title, null);
1227     }
1228
1229     /**
1230      * Return through a file selector the name of the selected file.
1231      *
1232      * @param title
1233      *            the title for JFileChooser
1234      * @param path
1235      *            the path where to open the filechooser
1236      * @return the file picked up by the user
1237      */
1238     public String chooseFileToSave(String title, String path) {
1239         String extension = "";
1240
1241         String initialDirectoryPath = path;
1242         if (initialDirectoryPath == null) {
1243             initialDirectoryPath = getTextPane().getName();
1244         }
1245         if (initialDirectoryPath == null) {
1246             if (firstOpen) {
1247                 initialDirectoryPath = CommonFileUtils.getCWD();
1248                 firstOpen = false;
1249             } else {
1250                 initialDirectoryPath = ConfigManager.getLastOpenedDirectory();
1251             }
1252         }
1253
1254         SciFileFilter sceFilter = new SciFileFilter(ALL_SCE_FILES, null, 0);
1255         SciFileFilter sciFilter = new SciFileFilter(ALL_SCI_FILES, null, 1);
1256         SciFileFilter scxFilter = new SciFileFilter(ALL_SCX_FILES, null, 2);
1257         SciFileFilter tstFilter = new SciFileFilter(ALL_TST_FILES, null, 3);
1258         SciFileFilter startFilter = new SciFileFilter(ALL_START_FILES, null, 4);
1259         SciFileFilter quitFilter = new SciFileFilter(ALL_QUIT_FILES, null, 5);
1260         SciFileFilter demFilter = new SciFileFilter(ALL_DEM_FILES, null, 6);
1261         SciFileFilter allFilter = new SciFileFilter(ALL_FILES, null, 7);
1262         SciFileFilter allScilabFilter = new SciFileFilter(ALL_SCILAB, null, 8);
1263
1264         SwingScilabFileChooser fileChooser = ((SwingScilabFileChooser) ScilabFileChooser.createFileChooser().getAsSimpleFileChooser());
1265
1266         fileChooser.setAcceptAllFileFilterUsed(false);
1267         fileChooser.setInitialDirectory(initialDirectoryPath);
1268         fileChooser.setUiDialogType(Juigetfile.SAVE_DIALOG);
1269
1270         // order is also important here
1271         fileChooser.addChoosableFileFilter(sceFilter);
1272         fileChooser.addChoosableFileFilter(sciFilter);
1273         fileChooser.addChoosableFileFilter(scxFilter);
1274         fileChooser.addChoosableFileFilter(tstFilter);
1275         fileChooser.addChoosableFileFilter(startFilter);
1276         fileChooser.addChoosableFileFilter(quitFilter);
1277         fileChooser.addChoosableFileFilter(demFilter);
1278         fileChooser.addChoosableFileFilter(allFilter);
1279         fileChooser.addChoosableFileFilter(allScilabFilter);
1280
1281         String name = initialDirectoryPath;
1282         File tempFile = new File(name);
1283
1284         // Select default file type
1285         SciFileFilter fileFilter = sceFilter;
1286         // Look for a supported extension
1287         for (FileFilter filter : fileChooser.getChoosableFileFilters()) {
1288             if (((SciFileFilter) filter).accept(tempFile)) {
1289                 fileFilter = (SciFileFilter) filter;
1290                 break;
1291             }
1292         }
1293         fileChooser.setFileFilter(fileFilter);
1294         fileChooser.setTitle(title);
1295
1296         if (name == null) {
1297             name = ((ScilabDocument) getTextPane().getDocument()).getFirstFunctionName();
1298             if (name != null) {
1299                 name += SCI_EXTENSION;
1300             }
1301         }
1302
1303         if (name != null) {
1304             fileChooser.setSelectedFile(new File(name));
1305         }
1306
1307         int retval = fileChooser.showSaveDialog(this);
1308
1309         if (retval == JFileChooser.APPROVE_OPTION) {
1310             File f = fileToCanonicalFile(fileChooser.getSelectedFile());
1311             initialDirectoryPath = f.getPath();
1312             if (f.exists()) {
1313                 if (ScilabModalDialog.show(this, SciNotesMessages.REPLACE_FILE_TITLE, SciNotesMessages.FILE_ALREADY_EXIST, IconType.QUESTION_ICON,
1314                                            ButtonType.YES_NO) == AnswerOption.NO_OPTION) {
1315                     return chooseFileToSave(SciNotesMessages.SAVE);
1316                 }
1317             }
1318
1319             /* we test if the file has already a scilab extension */
1320             boolean hasNoExtension = true;
1321
1322             // if the file name is like this : any character , a dot , then
1323             // 2,3or 4 characters, then
1324             // we consider the file has already an extension
1325             // we previously only check for .sci and .sce extension, but what if
1326             // the user open a txt file
1327             String fileName = f.getName();
1328             if (fileName.lastIndexOf(DOT) != -1) {
1329                 if (fileName.substring(fileName.lastIndexOf(DOT), fileName.length()).length() >= 2
1330                         && fileName.substring(fileName.lastIndexOf(DOT), fileName.length()).length() <= 4) {
1331                     hasNoExtension = false;
1332                 }
1333             }
1334
1335             /* if no extension , we add it */
1336             if (hasNoExtension) {
1337                 if (fileChooser.getFileFilter() == sciFilter) {
1338                     extension = SCI_EXTENSION;
1339                 } else if (fileChooser.getFileFilter() == sceFilter) {
1340                     extension = SCE_EXTENSION;
1341                 } else if (fileChooser.getFileFilter() == scxFilter) {
1342                     extension = SCE_EXTENSION;
1343                 } else if (fileChooser.getFileFilter() == tstFilter) {
1344                     extension = TST_EXTENSION;
1345                 } else if (fileChooser.getFileFilter() == startFilter) {
1346                     extension = START_EXTENSION;
1347                 } else if (fileChooser.getFileFilter() == quitFilter) {
1348                     extension = QUIT_EXTENSION;
1349                 } else if (fileChooser.getFileFilter() == demFilter) {
1350                     extension = DEM_EXTENSION;
1351                 } else {
1352                     extension = "";
1353                 }
1354                 return f.getPath() + extension;
1355             }
1356
1357             if (initialDirectoryPath != null) {
1358                 ConfigManager.saveLastOpenedDirectory(initialDirectoryPath);
1359             }
1360
1361             return f.getPath();
1362         } else if (retval == JFileChooser.CANCEL_OPTION) {
1363             return "";
1364         }
1365
1366         return null;
1367     }
1368
1369     /**
1370      * Save a file.
1371      *
1372      * @param path
1373      *            the initial path where the filechooser will be open
1374      * @return execution status
1375      */
1376     public boolean saveAs(String path) {
1377         String filename = chooseFileToSave(SciNotesMessages.SAVE_AS, path);
1378         if (filename == null || filename.length() == 0) {
1379             return true;
1380         }
1381
1382         File f = new File(filename);
1383         ScilabDocument styledDocument = (ScilabDocument) getTextPane().getDocument();
1384
1385         if (!SaveFile.doSave(getTextPane(), getTabPane().getSelectedIndex(), f, editorKit)) {
1386             return false;
1387         }
1388
1389         if (getTextPane().getName() == null) {
1390             String name = getTabPane().getScilabTitleAt(getTabPane().getSelectedIndex());
1391             String index = name.substring(name.length() - 1, name.length());
1392             tabList.remove(Integer.valueOf(index));
1393             closedTabList.add(Integer.valueOf(index));
1394         }
1395
1396         firstOpen = false;
1397         ConfigManager.saveLastOpenedDirectory(f.getPath());
1398         ConfigSciNotesManager.saveToRecentOpenedFiles(f.getPath());
1399         ConfigSciNotesManager.renameOpenFilesItem(f.getPath(), this, getTextPane());
1400         getTextPane().setName(f.getPath());
1401         getTabPane().setTitleAt(getTabPane().getSelectedIndex(), f.getName());
1402         setTitle(getTextPane().getTitle());
1403
1404         RecentFileAction.updateRecentOpenedFilesMenu(this);
1405
1406         if (navigator != null) {
1407             navigator.update(styledDocument);
1408         }
1409
1410         styledDocument.setContentModified(false);
1411         getTextPane().setLastModified(f.lastModified());
1412         getTextPane().setReadOnly(false);
1413         getInfoBar().setText(getTextPane().getInfoBarText());
1414
1415         return true;
1416     }
1417
1418     /**
1419      * Create a new tab in SciNotes.
1420      *
1421      * @param title
1422      *            the title of the tab
1423      * @return the text component inside the tab
1424      */
1425     public ScilabEditorPane addTab(String title) {
1426         return addTab(title, Integer.MAX_VALUE);
1427     }
1428
1429     /**
1430      * Create a new tab in SciNotes.
1431      *
1432      * @param title
1433      *            the title of the tab
1434      * @param index
1435      *            the index where to put the new tab
1436      * @return the text component inside the tab
1437      */
1438     public ScilabEditorPane addTab(String title, int index) {
1439         return addTab(title, index, 0);
1440     }
1441
1442     /**
1443      * Create a new tab in SciNotes.
1444      *
1445      * @param title
1446      *            the title of the tab
1447      * @param index
1448      *            the index where to put the new tab
1449      * @return the text component inside the tab
1450      */
1451     public ScilabEditorPane addTab(String title, int index, int caretPos) {
1452         ScilabEditorPane sep = new ScilabEditorPane(this);
1453         initPane(sep);
1454         int ind = Math.min(Math.max(0, index), tabPane.getTabCount());
1455         tabPane.insertTab(title, null, sep.getEditorComponent(), "", ind);
1456         tabPane.setSelectedIndex(ind);
1457         initInputMap(sep);
1458         updateTabTitle();
1459         getInfoBar().setText(sep.getInfoBarText());
1460         repaint();
1461         sep.init(caretPos);
1462         return sep;
1463     }
1464
1465     public void addRestoreTab() {
1466         try {
1467             JPanel panel = RestoreOpenedFilesAction.getTab(this, getUUID().toString());
1468             if (panel != null) {
1469                 tabPane.addTab("Restore", panel);
1470             }
1471         } catch (Exception e) {
1472             System.err.println(e);
1473         }
1474     }
1475
1476     /**
1477      * Init a pane
1478      *
1479      * @param pane
1480      *            the pane to init
1481      */
1482     public void initPane(ScilabEditorPane pane) {
1483         initPane(pane, !SciNotesOptions.getSciNotesDisplay().wrapLines);
1484     }
1485
1486     /**
1487      * Init the EditorPane.
1488      *
1489      * @param pane
1490      *            the EditorPane
1491      * @param plain
1492      *            true for a plain view or false for a wrapped view
1493      */
1494     public void initPane(ScilabEditorPane pane, boolean plain) {
1495         setHighlight(pane);
1496         ScilabEditorKit kit = new ScilabEditorKit(plain);
1497         pane.setEditorKit(kit);
1498
1499         // Panel of line number for the text pane
1500         pane.getXln().setWhereamiLineNumbering(SciNotesOptions.getSciNotesDisplay().showLineNumbers, SciNotesOptions.getSciNotesDisplay().whereami);
1501         activateHelpOnTyping(pane);
1502
1503         pane.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
1504         pane.setFont(kit.getStylePreferences().tokenFonts[0]);
1505
1506         pane.setBackground(SciNotesOptions.getSciNotesDisplay().backgroundColor);
1507         pane.setCaretColor(SciNotesOptions.getSciNotesDisplay().caretColor);
1508
1509         pane.setFocusable(true);
1510         pane.setRequestFocusEnabled(true);
1511         pane.setDragEnabled(true); /* Bug 5497 */
1512
1513         DropFilesListener dndTarget = new DropFilesListener(pane);
1514
1515         pane.setComponentPopupMenu(SciNotesGUI.generateRightClickPopup(this));
1516     }
1517
1518     /**
1519      * Init the EditorPane with the InputMap found in ConfigSciNotesManager
1520      *
1521      * @param pane
1522      *            the EditorPane
1523      */
1524     public void initInputMap(ScilabEditorPane pane) {
1525         setKeyStrokeAction(pane, this);
1526         LineBeautifierAction.putInInputMap(pane);
1527         InsertOverwriteAction.putInInputMap(pane);
1528     }
1529
1530     /**
1531      * Split the EditorPane
1532      *
1533      * @param vertical
1534      *            true for a vertical split
1535      */
1536     public void splitTab(boolean vertical) {
1537         ScilabEditorPane pane = getTextPane();
1538         Component bottom = pane.getEditorComponent().getBottom();
1539         int state = pane.getXln().getState();
1540         ScilabEditorPane leftPane = new ScilabEditorPane(editor);
1541         ScilabEditorPane rightPane = new ScilabEditorPane(editor);
1542         if (navigator != null) {
1543             navigator.changePaneOnSplit(pane, leftPane);
1544         }
1545         initPane(leftPane, true);
1546         initPane(rightPane, true);
1547         leftPane.setOtherPaneInSplit(rightPane);
1548         rightPane.setOtherPaneInSplit(leftPane);
1549         pane.copyProps(leftPane);
1550         pane.copyProps(rightPane);
1551         ScilabDocument doc = (ScilabDocument) pane.getDocument();
1552         leftPane.setDocument(doc);
1553         rightPane.setDocument(doc);
1554         leftPane.setCaretPosition(0);
1555         rightPane.setCaretPosition(0);
1556         JSplitPane split;
1557         if (vertical) {
1558             split = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
1559         } else {
1560             split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
1561         }
1562         leftPane.getXln().setWhereamiLineNumbering(state);
1563         rightPane.getXln().setWhereamiLineNumbering(state);
1564         split.setLeftComponent(leftPane.getScrollPane());
1565         split.setRightComponent(rightPane.getScrollPane());
1566         split.setResizeWeight(0.5);
1567         rightPane.setEditorComponent(leftPane.getEditorComponent());
1568         leftPane.setSplitPane(split);
1569         rightPane.setSplitPane(split);
1570
1571         activateHelpOnTyping(leftPane);
1572         activateHelpOnTyping(rightPane);
1573         initInputMap(leftPane);
1574         initInputMap(rightPane);
1575         if (doc.getBinary()) {
1576             leftPane.setBinary(true);
1577             rightPane.setBinary(true);
1578         }
1579         getInfoBar().setText(leftPane.getInfoBarText());
1580         updateTabTitle();
1581         tabPane.setComponentAt(tabPane.getSelectedIndex(), leftPane.getEditorComponent());
1582         leftPane.getEditorComponent().insertBottomComponent(bottom);
1583         leftPane.requestFocus();
1584     }
1585
1586     /**
1587      * Remove a split
1588      */
1589     public void removeSplit() {
1590         if (((EditorComponent) tabPane.getSelectedComponent()).isSplited()) {
1591             ScilabEditorPane pane = new ScilabEditorPane(editor);
1592             ScilabEditorPane textpane = getTextPane();
1593             Component bottom = textpane.getEditorComponent().getBottom();
1594             if (navigator != null) {
1595                 navigator.changePaneOnSplit(textpane, pane);
1596             }
1597             initPane(pane);
1598             textpane.setOtherPaneInSplit(null);
1599             textpane.copyProps(pane);
1600             ScilabDocument doc = (ScilabDocument) textpane.getDocument();
1601             pane.setDocument(doc);
1602             pane.setCaretPosition(0);
1603             activateHelpOnTyping(pane);
1604             tabPane.setComponentAt(tabPane.getSelectedIndex(), pane.getEditorComponent());
1605             initInputMap(pane);
1606             if (doc.getBinary()) {
1607                 pane.setBinary(true);
1608             }
1609             getInfoBar().setText(pane.getInfoBarText());
1610             updateTabTitle();
1611             pane.getEditorComponent().insertBottomComponent(bottom);
1612             pane.requestFocus();
1613         }
1614     }
1615
1616     /**
1617      * Create an empty tab inside SciNotes.
1618      *
1619      * @return the text component inside the tab
1620      */
1621     public ScilabEditorPane addEmptyTab() {
1622         ScilabEditorPane sep;
1623         int n = getNumberForEmptyTab();
1624         sep = addTab(SciNotesMessages.UNTITLED + n);
1625         sep.setShortName(SciNotesMessages.UNTITLED + n);
1626         sep.setTitle(SciNotesMessages.UNTITLED + n);
1627         setTitle(sep.getTitle());
1628         SciNotesOptions.Header header = SciNotesOptions.getSciNotesHeader();
1629         if (header.header != null) {
1630             ((ScilabDocument) sep.getDocument()).disableUndoManager();
1631             try {
1632                 sep.getDocument().insertString(0, header.header, null);
1633             } catch (BadLocationException e) { }
1634             sep.init(header.header.length());
1635             ((ScilabDocument) sep.getDocument()).setContentModified(false);
1636             ((ScilabDocument) sep.getDocument()).enableUndoManager();
1637         }
1638
1639         return sep;
1640     }
1641
1642     /**
1643      * Get an integer used for untitled document
1644      */
1645     public int getNumberForEmptyTab() {
1646         if (closedTabList.size() > 0) {
1647             Integer n = Collections.min(closedTabList);
1648             closedTabList.remove(n);
1649             return n.intValue();
1650         } else {
1651             numberOfUntitled++;
1652             tabList.add(Integer.valueOf(numberOfUntitled));
1653             return numberOfUntitled;
1654         }
1655     }
1656
1657     /**
1658      * Add or remove '*' prefix in current tab tile according to
1659      * isContentModified().
1660      */
1661     public void updateTabTitle() {
1662         updateTabTitle(getTabPane().getSelectedIndex());
1663     }
1664
1665     /**
1666      * Add or remove '*' prefix in tab title (corresponding to the given index) according to
1667      * isContentModified().
1668      */
1669     public void updateTabTitle(int index) {
1670         StringBuffer newTitle = new StringBuffer();
1671         ScilabEditorPane currentTextPane = getTextPane(index);
1672         if (((ScilabDocument) currentTextPane.getDocument()).isContentModified()) {
1673             newTitle.append('*');
1674         }
1675
1676         String textPaneName = currentTextPane.getName();
1677         try {
1678             File f = new File(textPaneName);
1679             newTitle.append(f.getName());
1680         } catch (NullPointerException e) { // not a file name, no path prefix to
1681             // remove, but maybe a '*'
1682             textPaneName = getTabPane().getScilabTitleAt(index);
1683             if (textPaneName.charAt(0) == '*') {
1684                 newTitle.append(textPaneName.substring(1, textPaneName.length()));
1685             } else {
1686                 newTitle.append(textPaneName);
1687             }
1688         }
1689         getTabPane().setTitleAt(index, newTitle.toString());
1690     }
1691
1692     /**
1693      * @param button
1694      *            the UndoButton used in this editor
1695      */
1696     public void setUndoButton(JButton button) {
1697         undoButton = button;
1698         enableUndoButton(false);
1699     }
1700
1701     /**
1702      * @param b
1703      *            true to enable the button
1704      */
1705     public void enableUndoButton(boolean b) {
1706         if (undoButton != null) {
1707             undoButton.setEnabled(b);
1708         }
1709     }
1710
1711     /**
1712      * Undo last modification.
1713      */
1714     public void undo() {
1715         ScilabDocument doc = (ScilabDocument) getTextPane().getDocument();
1716         synchronized (doc) {
1717             doc.getUndoManager().undo();
1718         }
1719     }
1720
1721     /**
1722      * @param button
1723      *            the RedoButton used in this editor
1724      */
1725     public void setRedoButton(JButton button) {
1726         redoButton = button;
1727         enableRedoButton(false);
1728     }
1729
1730     /**
1731      * @param b
1732      *            true to enable the button
1733      */
1734     public void enableRedoButton(boolean b) {
1735         if (redoButton != null) {
1736             redoButton.setEnabled(b);
1737         }
1738     }
1739
1740     /**
1741      * Redo last modification.
1742      */
1743     public void redo() {
1744         ScilabDocument doc = (ScilabDocument) getTextPane().getDocument();
1745         synchronized (doc) {
1746             doc.getUndoManager().redo();
1747         }
1748     }
1749
1750     /**
1751      * Reload a file inside SciNotes.
1752      *
1753      * @param index
1754      *            the index
1755      */
1756     public void reload(int index) {
1757         ScilabEditorPane textPaneAt = getTextPane(index);
1758         if (textPaneAt != null && textPaneAt.getName() != null) {
1759             if ((index == 0) && (getTabPane().getTabCount() == 1)) {
1760                 for (int j = 0; j < tabPane.getChangeListeners().length; j++) {
1761                     tabPane.removeChangeListener(tabPane.getChangeListeners()[j]);
1762                 }
1763             }
1764             ConfigSciNotesManager.removeFromOpenFiles(this, textPaneAt);
1765             tabPane.remove(index);
1766             File f = new File(textPaneAt.getName());
1767             if (f.exists()) {
1768                 loadFile(f, index);
1769             } else {
1770                 createNewFile(f);
1771             }
1772         }
1773     }
1774
1775     /**
1776      * Load a file inside SciNotes.
1777      *
1778      * @param f
1779      *            the file to open
1780      */
1781     public void readFile(File f) {
1782         /** Is this file already opened */
1783         boolean alreadyOpened = false;
1784         for (int i = 0; i < tabPane.getTabCount(); i++) {
1785             ScilabEditorPane textPaneAt = getTextPane(i);
1786             if (f.getAbsolutePath().equals(textPaneAt.getName())) {
1787                 /* File is already opnened */
1788                 tabPane.setSelectedIndex(i);
1789                 alreadyOpened = true;
1790                 break;
1791             }
1792         }
1793
1794         if (!alreadyOpened) {
1795             if (f.exists()) {
1796                 loadFile(f);
1797             } else {
1798                 createNewFile(f);
1799             }
1800         }
1801     }
1802
1803     /**
1804      * Load a file inside SciNotes.
1805      *
1806      * @param file
1807      *            the file to open
1808      */
1809     public void readFileAndWait(File file) {
1810         /** Is this file already opened */
1811         File f = file;
1812         boolean alreadyOpened = false;
1813         int index = -1;
1814         for (int i = 0; i < tabPane.getTabCount(); i++) {
1815             ScilabEditorPane textPaneAt = getTextPane(i);
1816             if (textPaneAt != null && f.getAbsolutePath().equals(textPaneAt.getName())) {
1817                 /* File is already opened */
1818                 tabPane.setSelectedIndex(i);
1819                 if (f.lastModified() > textPaneAt.getLastModified()) {
1820
1821                     /*
1822                      * Create a new messagebox to know what the user wants to do
1823                      * if the file has been modified outside SciNotes
1824                      */
1825                     MessageBox messageBox = ScilabMessageBox.createMessageBox();
1826                     messageBox.setTitle(SciNotesMessages.REPLACE_FILE_TITLE);
1827                     messageBox.setMessage(String.format(SciNotesMessages.EXTERNAL_MODIFICATION, textPaneAt.getName()));
1828
1829                     String[] labels = new String[] { SciNotesMessages.RELOAD, SciNotesMessages.OVERWRITE, SciNotesMessages.IGNORE };
1830                     messageBox.setButtonsLabels(labels);
1831
1832                     messageBox.setIcon("question"); // Question icon
1833
1834                     messageBox.setParentForLocation(this); // Centered on
1835                     // SciNotes main
1836                     // window
1837
1838                     messageBox.displayAndWait(); // Waits for a user action
1839
1840                     switch (messageBox.getSelectedButton()) {
1841                         case 1: // Reload
1842                             if ((i == 0) && (getTabPane().getTabCount() == 1)) {
1843                                 for (int j = 0; j < tabPane.getChangeListeners().length; j++) {
1844                                     tabPane.removeChangeListener(tabPane.getChangeListeners()[j]);
1845                                 }
1846                             }
1847                             tabPane.remove(i);
1848                             f = new File(textPaneAt.getName());
1849                             index = i;
1850                             break;
1851                         case 2: // Overwrite 2
1852                             overwrite(i);
1853                             alreadyOpened = true;
1854                             break;
1855                         default: // Ignore
1856                             alreadyOpened = true;
1857                     }
1858                 } else {
1859                     alreadyOpened = true;
1860                 }
1861                 break;
1862             }
1863         }
1864
1865         if (!alreadyOpened) {
1866             if (f.exists()) {
1867                 loadFile(f, index);
1868             } else {
1869                 createNewFile(f);
1870             }
1871         }
1872     }
1873
1874     public int getTextPaneIndex(ScilabEditorPane sep) {
1875         int n = tabPane.getTabCount();
1876         for (int i = 0; i < n; ++i) {
1877             ScilabEditorPane pane = getTextPane(i);
1878             if (pane != null && (pane == sep || pane.getOtherPaneInSplit() == sep)) {
1879                 return i;
1880             }
1881         }
1882
1883         return -1;
1884     }
1885
1886     /**
1887      * Get current text component. If the window is splitted, then return the
1888      * focused text component.
1889      *
1890      * @return the text component
1891      */
1892     public ScilabEditorPane getTextPane() {
1893         try {
1894             if (tabPane.getSelectedComponent() instanceof EditorComponent) {
1895                 EditorComponent c = (EditorComponent) tabPane.getSelectedComponent();
1896                 ScilabEditorPane pane = c.getEditorPane();
1897                 if (ScilabEditorPane.getFocusedPane() == pane.getOtherPaneInSplit()) {
1898                     return pane.getOtherPaneInSplit();
1899                 }
1900
1901                 return pane;
1902             }
1903         } catch (NullPointerException e) {
1904         } catch (ArrayIndexOutOfBoundsException e) {
1905         }
1906
1907         return null;
1908     }
1909
1910     /**
1911      * Get text component at index.
1912      *
1913      * @param index
1914      *            the index of the textpane
1915      * @return the text component
1916      */
1917     public ScilabEditorPane getTextPane(int index) {
1918         try {
1919             if (tabPane.getComponentAt(index) instanceof EditorComponent) {
1920                 EditorComponent c = (EditorComponent) tabPane.getComponentAt(index);
1921                 ScilabEditorPane pane = c.getEditorPane();
1922                 if (ScilabEditorPane.getFocusedPane() == pane.getOtherPaneInSplit()) {
1923                     return pane.getOtherPaneInSplit();
1924                 }
1925
1926                 return pane;
1927             }
1928         } catch (NullPointerException e) {
1929         } catch (ArrayIndexOutOfBoundsException e) {
1930         }
1931
1932         return null;
1933     }
1934
1935     /**
1936      * Set the keystroke actions
1937      */
1938     public static void setAllMenus() {
1939         for (SciNotes ed : scinotesList) {
1940             SciNotesGUI.reinitMenus(ed);
1941             int n = ed.getTabPane().getTabCount();
1942             for (int i = 0; i < n; i++) {
1943                 ScilabEditorPane sep = ed.getTextPane(i);
1944                 sep.setComponentPopupMenu(SciNotesGUI.generateRightClickPopup(ed));
1945                 if (sep.getOtherPaneInSplit() != null) {
1946                     sep.getOtherPaneInSplit().setComponentPopupMenu(SciNotesGUI.generateRightClickPopup(ed));
1947                 }
1948             }
1949         }
1950     }
1951
1952     /**
1953      * Set the keystroke actions
1954      */
1955     public static void setKeyStrokeActions() {
1956         for (SciNotes ed : scinotesList) {
1957             int n = ed.getTabPane().getTabCount();
1958             for (int i = 0; i < n; i++) {
1959                 ScilabEditorPane sep = ed.getTextPane(i);
1960                 ed.initInputMap(sep);
1961                 if (sep.getOtherPaneInSplit() != null) {
1962                     ed.initInputMap(sep.getOtherPaneInSplit());
1963                 }
1964             }
1965         }
1966     }
1967
1968     /**
1969      * Enable the whereami-line numbering
1970      *
1971      * @param state
1972      *            int
1973      */
1974     public static void setWhereamiLineNumbering() {
1975         for (SciNotes ed : scinotesList) {
1976             int n = ed.getTabPane().getTabCount();
1977             for (int i = 0; i < n; i++) {
1978                 ScilabEditorPane sep = ed.getTextPane(i);
1979                 sep.getXln().setWhereamiLineNumbering(SciNotesOptions.getSciNotesDisplay().showLineNumbers, SciNotesOptions.getSciNotesDisplay().whereami);
1980                 if (sep.getOtherPaneInSplit() != null) {
1981                     sep.getOtherPaneInSplit().getXln().setWhereamiLineNumbering(SciNotesOptions.getSciNotesDisplay().showLineNumbers, SciNotesOptions.getSciNotesDisplay().whereami);
1982                 }
1983             }
1984             ed.repaint();
1985         }
1986     }
1987
1988     /**
1989      * Auto-indent mode management
1990      *
1991      * @param b
1992      *            true to activate auto-indent mode
1993      */
1994     public static void setAutoIndent() {
1995         for (SciNotes ed : scinotesList) {
1996             int n = ed.getTabPane().getTabCount();
1997             for (int i = 0; i < n; i++) {
1998                 ScilabEditorPane sep = ed.getTextPane(i);
1999                 ((ScilabDocument) sep.getDocument()).setAutoIndent(SciNotesOptions.getSciNotesDisplay().automaticIndent);
2000                 if (sep.getOtherPaneInSplit() != null) {
2001                     ((ScilabDocument) sep.getOtherPaneInSplit().getDocument()).setAutoIndent(SciNotesOptions.getSciNotesDisplay().automaticIndent);
2002                 }
2003             }
2004         }
2005     }
2006
2007     /**
2008      * Horizontal Wrap mode management
2009      *
2010      * @param b
2011      *            true to activate horizontal wrapping mode
2012      */
2013     public static void setHorizontalWrap() {
2014         if (SciNotesOptions.getSciNotesDisplay().wrapLines != mustWrapLines) {
2015             mustWrapLines = SciNotesOptions.getSciNotesDisplay().wrapLines;
2016             for (SciNotes ed : scinotesList) {
2017                 int n = ed.getTabPane().getTabCount();
2018                 for (int i = 0; i < n; i++) {
2019                     ScilabEditorPane sep = ed.getTextPane(i);
2020                     if (sep.getOtherPaneInSplit() == null) {
2021                         ScilabEditorPane pane = new ScilabEditorPane(editor);
2022                         ed.initPane(pane, !mustWrapLines);
2023                         sep.copyProps(pane);
2024                         pane.setDocument(sep.getDocument());
2025                         pane.setCaretPosition(sep.getCaretPosition());
2026                         pane.getXln().setWhereamiLineNumbering(SciNotesOptions.getSciNotesDisplay().showLineNumbers, SciNotesOptions.getSciNotesDisplay().whereami);
2027                         ed.tabPane.setComponentAt(i, pane.getEditorComponent());
2028                         SciNotes.activateHelpOnTyping(pane);
2029                         ed.initInputMap(pane);
2030                         if (((ScilabDocument) sep.getDocument()).getBinary()) {
2031                             pane.setBinary(true);
2032                         }
2033                         ed.getInfoBar().setText(pane.getInfoBarText());
2034                     }
2035                 }
2036             }
2037         }
2038     }
2039
2040     /**
2041      * Set a line numbering compatible with the whereami function
2042      * @param state 0 for nothing, 1 for normal and 2 for whereami
2043      */
2044
2045     /**
2046      * Enable the highlighted line in this editor
2047      *
2048      * @param b
2049      *            boolean
2050      */
2051     public static void enableHighlightedLine(boolean b) {
2052         for (SciNotes ed : scinotesList) {
2053             int n = ed.getTabPane().getTabCount();
2054             for (int i = 0; i < n; i++) {
2055                 ScilabEditorPane sep = ed.getTextPane(i);
2056                 sep.enableHighlightedLine(SciNotesOptions.getSciNotesDisplay().highlightCurrentLine);
2057                 if (sep.getOtherPaneInSplit() != null) {
2058                     sep.getOtherPaneInSplit().enableHighlightedLine(SciNotesOptions.getSciNotesDisplay().highlightCurrentLine);
2059                 }
2060             }
2061         }
2062     }
2063
2064     /**
2065      * Enable the help on typing in the current textPane
2066      *
2067      * @param pane
2068      *            the pane
2069      */
2070     public static void activateHelpOnTyping(ScilabEditorPane pane) {
2071         pane.activateHelpOnTyping();
2072     }
2073
2074     /**
2075      * Enable the help on typing in this editor
2076      */
2077     public static void activateHelpOnTyping() {
2078         for (SciNotes ed : scinotesList) {
2079             int n = ed.getTabPane().getTabCount();
2080             for (int i = 0; i < n; i++) {
2081                 ScilabEditorPane sep = ed.getTextPane(i);
2082                 sep.activateHelpOnTyping();
2083                 if (sep.getOtherPaneInSplit() != null) {
2084                     sep.getOtherPaneInSplit().activateHelpOnTyping();
2085                 }
2086             }
2087         }
2088     }
2089
2090     /**
2091      * Set the color of the highlighted line in this editor
2092      *
2093      * @param c
2094      *            Color
2095      */
2096     public static void setDefaultTabulation() {
2097         TabManager.Tabulation tab = new TabManager.Tabulation();
2098         for (SciNotes ed : scinotesList) {
2099             int n = ed.getTabPane().getTabCount();
2100             for (int i = 0; i < n; i++) {
2101                 ScilabEditorPane sep = ed.getTextPane(i);
2102                 sep.getTabManager().setTabulation(tab);
2103                 View view = ((ScilabDocument) sep.getDocument()).getView();
2104                 if (view != null) {
2105                     if (view instanceof ScilabView) {
2106                         ((ScilabView) view).setTabRepresentation(tab);
2107                         ((ScilabView) view).reinitialize();
2108                     } else {
2109                         ((ScilabPlainView) view).setTabRepresentation(tab);
2110                         ((ScilabPlainView) view).reinitialize();
2111                     }
2112                 }
2113             }
2114         }
2115     }
2116
2117     /**
2118      * Set the color of the highlighted line in this editor
2119      *
2120      * @param c
2121      *            Color
2122      */
2123     public static void updatePanes(SciNotesConfiguration.Conf conf) {
2124         for (SciNotes ed : scinotesList) {
2125             int n = ed.getTabPane().getTabCount();
2126             for (int i = 0; i < n; i++) {
2127                 ScilabEditorPane sep = ed.getTextPane(i);
2128                 sep.configurationChanged(conf);
2129                 if (sep.getOtherPaneInSplit() != null) {
2130                     sep.getOtherPaneInSplit().configurationChanged(conf);
2131                 }
2132                 sep.repaint();
2133             }
2134         }
2135     }
2136
2137     public static void updateFontSize(int inc) {
2138         Font baseFont = null;
2139         for (SciNotes ed : scinotesList) {
2140             int n = ed.getTabPane().getTabCount();
2141             for (int i = 0; i < n; i++) {
2142                 ScilabEditorPane sep = ed.getTextPane(i);
2143                 ((ScilabEditorKit) sep.getEditorKit()).getStylePreferences().changeBaseFontSize(inc);
2144                 if (baseFont == null) {
2145                     baseFont = ((ScilabEditorKit) sep.getEditorKit()).getStylePreferences().getBaseFont();
2146                 }
2147                 if (sep.getOtherPaneInSplit() != null) {
2148                     ((ScilabEditorKit) sep.getOtherPaneInSplit().getEditorKit()).getStylePreferences().changeBaseFontSize(n);
2149                     sep.getOtherPaneInSplit().resetFont();
2150                 }
2151                 sep.resetFont();
2152             }
2153         }
2154
2155         if (baseFont != null) {
2156             ScilabContext.saveFont(baseFont);
2157         }
2158     }
2159
2160     /**
2161      * Set the color of the highlighted line in this editor
2162      *
2163      * @param c
2164      *            Color
2165      */
2166     public static void setHighlightedLineColor() {
2167         for (SciNotes ed : scinotesList) {
2168             int n = ed.getTabPane().getTabCount();
2169             for (int i = 0; i < n; i++) {
2170                 ScilabEditorPane sep = ed.getTextPane(i);
2171                 sep.setHighlightedLineColor(SciNotesOptions.getSciNotesDisplay().currentLineColor);
2172                 if (sep.getOtherPaneInSplit() != null) {
2173                     sep.getOtherPaneInSplit().setHighlightedLineColor(SciNotesOptions.getSciNotesDisplay().currentLineColor);
2174                 }
2175             }
2176         }
2177     }
2178
2179     /**
2180      * Set the color of the contour of the highlighted line in this editor
2181      *
2182      * @param c
2183      *            Color
2184      */
2185     public static void setHighlightedContourColor() {
2186         for (SciNotes ed : scinotesList) {
2187             int n = ed.getTabPane().getTabCount();
2188             for (int i = 0; i < n; i++) {
2189                 ScilabEditorPane sep = ed.getTextPane(i);
2190                 sep.setHighlightedContourColor(null);
2191                 if (sep.getOtherPaneInSplit() != null) {
2192                     sep.getOtherPaneInSplit().setHighlightedContourColor(null);
2193                 }
2194             }
2195         }
2196     }
2197
2198     /**
2199      * Set the highlighted line in this textPane
2200      *
2201      * @param sep
2202      *            ScilabEditorPane
2203      */
2204     public static void setHighlight(ScilabEditorPane sep) {
2205         sep.enableHighlightedLine(SciNotesOptions.getSciNotesDisplay().highlightCurrentLine);
2206         sep.setHighlightedLineColor(SciNotesOptions.getSciNotesDisplay().currentLineColor);
2207         sep.setHighlightedContourColor(null);
2208     }
2209
2210     /**
2211      * Get SciNotes as a Tab.
2212      *
2213      * @return SciNotes instance
2214      * @see org.scilab.modules.gui.tab.Tab#getAsSimpleTab()
2215      */
2216     public SimpleTab getAsSimpleTab() {
2217         return this;
2218     }
2219
2220     /**
2221      * Get SciNotes parent Window.
2222      *
2223      * @return parent Window
2224      * @see org.scilab.modules.gui.tab.Tab#getParentWindow()
2225      */
2226     public SwingScilabWindow getParentWindow() {
2227         if (parentWindow == null) {
2228             return super.getParentWindow();
2229         }
2230         return parentWindow;
2231     }
2232
2233     /**
2234      * Get the UUID associated with the editor instance.
2235      *
2236      * @return unique identifier
2237      */
2238     public UUID getUUID() {
2239         return uuid;
2240     }
2241
2242     /**
2243      * Add a status bar to SciNotes.
2244      *
2245      * @param infoBarToAdd
2246      *            the status bar to be added
2247      * @see org.scilab.modules.gui.uielement.UIElement#addInfoBar(org.scilab.modules.gui.textbox.TextBox)
2248      */
2249     public void addInfoBar(TextBox infoBarToAdd) {
2250         setInfoBar(infoBarToAdd);
2251     }
2252
2253     /**
2254      * Add a menu bar to SciNotes.
2255      *
2256      * @param menuBarToAdd
2257      *            the menu bar to be added
2258      * @see org.scilab.modules.gui.uielement.UIElement#addMenuBar(org.scilab.modules.gui.menubar.MenuBar)
2259      */
2260     public void addMenuBar(MenuBar menuBarToAdd) {
2261         setMenuBar(menuBarToAdd);
2262     }
2263
2264     /**
2265      * Add a tool bar to SciNotes.
2266      *
2267      * @param toolBarToAdd
2268      *            the tool bar to be added
2269      * @see org.scilab.modules.gui.uielement.UIElement#addToolBar(org.scilab.modules.gui.toolbar.ToolBar)
2270      */
2271     public void addToolBar(ToolBar toolBarToAdd) {
2272         setToolBar(toolBarToAdd);
2273     }
2274
2275     /**
2276      * Get SciNotes main ScilabTabbedPane.
2277      *
2278      * @return SciNotes main ScilabTabbedPane
2279      */
2280     public ScilabTabbedPane getTabPane() {
2281         return tabPane;
2282     }
2283
2284     /**
2285      * Set SciNotes main ScilabTabbedPane.
2286      *
2287      * @param tabPane
2288      *            SciNotes main ScilabTabbedPane
2289      */
2290     public void setTabPane(ScilabTabbedPane tabPane) {
2291         this.tabPane = tabPane;
2292     }
2293
2294     /**
2295      * Load a file and add it at the end
2296      *
2297      * @param f
2298      *            the file to load
2299      */
2300     public void loadFile(File f) {
2301         loadFile(f, -1);
2302     }
2303
2304     /**
2305      * Load a file and add it at the index
2306      *
2307      * @param f
2308      *            the file to load
2309      * @param index
2310      *            the index where to put the file
2311      */
2312     public void loadFile(File f, int index) {
2313         ScilabDocument styleDocument = null;
2314         ScilabEditorPane theTextPane;
2315
2316         // File exist
2317         if (f.exists()) {
2318             if (!f.canRead()) {
2319                 ScilabModalDialog.show(this, SciNotesMessages.NOTREADABLE, SciNotesMessages.SCINOTES_ERROR, IconType.ERROR_ICON);
2320                 if (getTabPane().getTabCount() == 0) {
2321                     addEmptyTab();
2322                 }
2323                 return;
2324             }
2325
2326             getInfoBar().setText(SciNotesMessages.LOADING);
2327
2328             if (index != -1) {
2329                 theTextPane = addTab(f.getName(), index);
2330             } else {
2331                 theTextPane = addTab(f.getName());
2332             }
2333             styleDocument = (ScilabDocument) theTextPane.getDocument();
2334             styleDocument.disableUndoManager();
2335             theTextPane.setLastModified(f.lastModified());
2336
2337             try {
2338                 styleDocument.setUpdater(false);
2339                 boolean indentMode = styleDocument.getAutoIndent();
2340                 styleDocument.setAutoIndent(false);
2341                 try {
2342                     ((ScilabEditorKit) editorKit).read(this, f, styleDocument, 0);
2343                 } catch (BadLocationException e) {
2344                     e.printStackTrace();
2345                 }
2346                 styleDocument.setAutoIndent(indentMode);
2347                 styleDocument.setUpdater(true);
2348             } catch (IOException ioex) {
2349                 ioex.printStackTrace();
2350             }
2351
2352             theTextPane.setName(f.getAbsolutePath());
2353             getTabPane().setTitleAt(getTabPane().getSelectedIndex(), f.getName());
2354             setTitle(theTextPane.getTitle());
2355             styleDocument.setContentModified(false);
2356             styleDocument.enableUndoManager();
2357
2358             if (styleDocument.getBinary()) {
2359                 theTextPane.setBinary(true);
2360             }
2361
2362             if (!f.canWrite()) {
2363                 getTextPane().setReadOnly(true);
2364                 JOptionPane.showMessageDialog(SciNotes.this, SciNotesMessages.READONLY);
2365             }
2366
2367             getInfoBar().setText(theTextPane.getInfoBarText());
2368
2369             EncodingAction.updateEncodingMenu((ScilabDocument) getTextPane().getDocument());
2370
2371             firstOpen = false;
2372             ConfigManager.saveLastOpenedDirectory(f.getPath());
2373             ConfigSciNotesManager.saveToRecentOpenedFiles(f.getPath());
2374             ConfigSciNotesManager.saveToOpenFiles(f.getPath(), this, getTextPane());
2375
2376             // Empty the undo Manager
2377             UndoManager undo = ((ScilabDocument) getTextPane().getDocument()).getUndoManager();
2378             undo.discardAllEdits();
2379
2380             if (getTabPane().getTabCount() == 2) {
2381                 ScilabEditorPane pane = getTextPane(0);
2382                 if (pane != null && pane.getName() == null && !((ScilabDocument) pane.getDocument()).isContentModified()) {
2383                     closeTabAt(0);
2384                 }
2385             }
2386         }
2387     }
2388
2389     /**
2390      * Creates a file if it doesn't exist
2391      *
2392      * @param f
2393      *            the file to create
2394      */
2395     public void createNewFile(File f) {
2396         ScilabEditorPane theTextPane = addEmptyTab();
2397         ScilabDocument styleDocument = null;
2398         int choice = JOptionPane.showConfirmDialog(SciNotes.this, String.format(SciNotesMessages.FILE_DOESNT_EXIST, f.getName()), SCINOTES,
2399                      JOptionPane.YES_NO_OPTION);
2400         if (choice == 0) { // OK
2401             styleDocument = (ScilabDocument) theTextPane.getDocument();
2402             styleDocument.disableUndoManager();
2403
2404             BufferedWriter bw = null;
2405             OutputStreamWriter osw = null;
2406             FileOutputStream fos = null;
2407
2408             try {
2409                 fos = new FileOutputStream(f);
2410                 osw = new OutputStreamWriter(fos, styleDocument.getEncoding());
2411                 bw = new BufferedWriter(osw);
2412                 editorKit.write(bw, styleDocument, 0, styleDocument.getLength());
2413                 bw.flush();
2414             } catch (IOException e) {
2415                 System.err.println(e);
2416             } catch (BadLocationException e) {
2417                 System.err.println(e);
2418             } finally {
2419                 try {
2420                     if (fos != null) {
2421                         fos.close();
2422                     }
2423                     if (osw != null) {
2424                         osw.close();
2425                     }
2426                     if (bw != null) {
2427                         bw.close();
2428                     }
2429                 } catch (IOException e) {
2430                     System.err.println(e);
2431                 }
2432             }
2433
2434             firstOpen = false;
2435             ConfigManager.saveLastOpenedDirectory(f.getPath());
2436             ConfigSciNotesManager.saveToRecentOpenedFiles(f.getPath());
2437             ConfigSciNotesManager.saveToOpenFiles(theTextPane.getName(), this, theTextPane);
2438
2439             theTextPane.setName(f.getPath());
2440             getTabPane().setTitleAt(getTabPane().getSelectedIndex(), f.getName());
2441             setTitle(theTextPane.getTitle());
2442             RecentFileAction.updateRecentOpenedFilesMenu(this);
2443
2444             styleDocument.setContentModified(false);
2445             styleDocument.enableUndoManager();
2446             theTextPane.setLastModified(f.lastModified());
2447         }
2448
2449         getInfoBar().setText("");
2450     }
2451
2452     /**
2453      * EditorKit Getter
2454      *
2455      * @return EditorKit
2456      */
2457     public EditorKit getEditorKit() {
2458         return editorKit;
2459     }
2460
2461     /**
2462      * @param scinotes
2463      *            the focused editor
2464      */
2465     public static void setEditor(SciNotes scinotes) {
2466         editor = scinotes;
2467     }
2468
2469     /**
2470      * @return the focused editor
2471      */
2472     public static SciNotes getEditor() {
2473         return editor;
2474     }
2475
2476     /**
2477      * EditorKit Setter
2478      *
2479      * @param editorKit
2480      *            EditorKit
2481      */
2482     public void setEditorKit(EditorKit editorKit) {
2483         this.editorKit = editorKit;
2484     }
2485
2486     /**
2487      * Close scinotes from scilab.
2488      *
2489      * This method can be called outside the EDT thread.
2490      */
2491     public static void closeSciNotesFromScilab() {
2492         try {
2493             SwingUtilities.invokeAndWait(new Runnable() {
2494
2495                 @Override
2496                 public void run() {
2497                     SciNotes[] arr = scinotesList.toArray(new SciNotes[0]);
2498                     for (int i = 0; i < arr.length; i++) {
2499                         arr[i].setProtectOpenFileList(true);
2500                         ExitAction.doExit(arr[i]);
2501                     }
2502                     scinotesList.clear();
2503                 }
2504             });
2505         } catch (InterruptedException e) {
2506             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
2507         } catch (InvocationTargetException e) {
2508             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
2509         }
2510     }
2511
2512     /**
2513      * @param f
2514      *            the file
2515      * @return the canonical file if possible
2516      */
2517     public static File fileToCanonicalFile(File f) {
2518         /* Fix bug 5648 */
2519         try {
2520             return f.getCanonicalFile();
2521         } catch (IOException e) {
2522             return f;
2523         }
2524     }
2525
2526     /**
2527      * Set the shortcuts in the pane relatively to the file
2528      * keysConfiguration.xml
2529      *
2530      * @param sep
2531      *            the textpane
2532      * @param ed
2533      *            the SciNotes editor
2534      */
2535     private static void setKeyStrokeAction(ScilabEditorPane sep, SciNotes ed) {
2536         ScilabEditorPane s = ed.getTextPane(0);
2537         if (s != null && s != sep) {
2538             sep.setInputMap(JComponent.WHEN_FOCUSED, s.getInputMap());
2539             return;
2540         }
2541
2542         Map<String, KeyStroke> map = getActionKeys();
2543         ClassLoader loader = ClassLoader.getSystemClassLoader();
2544
2545         for (Map.Entry<String, KeyStroke> entry : map.entrySet()) {
2546             String actionName = entry.getKey();
2547             KeyStroke key = entry.getValue();
2548             String action = actionToName.get(actionName);
2549             if (key != null) {
2550                 if (!action.equals("SciNotesCompletionAction")) {
2551                     String className;
2552                     if (action.lastIndexOf(DOT) != -1) {
2553                         className = action;
2554                     } else {
2555                         className = DEFAULTACTIONPATH + DOT + action;
2556                     }
2557                     try {
2558                         Class clazz = loader.loadClass(className);
2559                         Constructor constructor = clazz.getConstructor(new Class[] { String.class, SciNotes.class });
2560                         Object act = constructor.newInstance(new Object[] { "", ed });
2561                         sep.getInputMap().put(key, act);
2562                     } catch (ClassNotFoundException e) {
2563                         System.err.println("No action: " + className);
2564                     } catch (InstantiationException e) {
2565                         System.err.println("Problem to instantiate in action: " + className);
2566                     } catch (NoSuchMethodException e) {
2567                         System.err.println("No valid constructor in action: " + className);
2568                     } catch (IllegalAccessException e) {
2569                         System.err.println("The constructor must be public: " + className);
2570                     } catch (InvocationTargetException e) {
2571                         System.err.println("The constructor in " + className + " threw an exception :");
2572                         e.printStackTrace();
2573                     }
2574                 } else {
2575                     sep.getInputMap().put(key, new SciNotesCompletionAction(sep, ed));
2576                 }
2577             }
2578         }
2579
2580         // Add default common shortcuts
2581         sep.getInputMap().put(KeyStroke.getKeyStroke("shift DELETE"), sep.getInputMap().get(map.get("scinotes-cut")));
2582         sep.getInputMap().put(KeyStroke.getKeyStroke("CUT"), sep.getInputMap().get(map.get("scinotes-cut")));
2583         sep.getInputMap().put(ScilabKeyStroke.getKeyStroke("OSSCKEY INSERT"), sep.getInputMap().get(map.get("scinotes-copy")));
2584         sep.getInputMap().put(KeyStroke.getKeyStroke("COPY"), sep.getInputMap().get(map.get("scinotes-copy")));
2585         sep.getInputMap().put(KeyStroke.getKeyStroke("shift INSERT"), sep.getInputMap().get(map.get("scinotes-paste")));
2586         sep.getInputMap().put(KeyStroke.getKeyStroke("PASTE"), sep.getInputMap().get(map.get("scinotes-paste")));
2587     }
2588
2589     /**
2590      * Execute an action on file
2591      * @param fileName the name of the file
2592      * @param action the action
2593      */
2594     public static void executeAction(String fileName, ActionOnDocument action) throws IOException {
2595         Charset charset = null;
2596         try {
2597             charset = ScilabEditorKit.tryToGuessEncoding(new File(fileName));
2598         } catch (CharacterCodingException e) {
2599             throw new IOException(SciNotesMessages.CANNOT_GUESS_ENCODING + ": " + fileName);
2600         }
2601
2602         ScilabDocument doc = new ScilabDocument();
2603         ScilabEditorKit kit = new ScilabEditorKit();
2604
2605         try ( FileInputStream fis = new FileInputStream(fileName);
2606                     InputStreamReader isr = new InputStreamReader(fis, charset);
2607                     BufferedReader reader = new BufferedReader(isr) ) {
2608
2609             kit.read(reader, doc, 0);
2610
2611         } catch (BadLocationException e) {
2612             System.err.println(e);
2613         } catch (IOException ioe) {
2614             System.err.println(ioe);
2615         }
2616
2617         doc.addDocumentListener(doc);
2618         if (!doc.getBinary()) {
2619             action.actionOn(doc);
2620         }
2621
2622         if (doc.isContentModified()) {
2623             SaveFile.doSave(doc, new File(fileName), kit);
2624         }
2625
2626     }
2627
2628     /**
2629      * Execute an action on file
2630      * @param fileName the name of the file
2631      * @param actionsName the actions as an array
2632      */
2633     public static boolean executeAction(String fileName, final String[] actionsName) throws IOException {
2634         final boolean[] hasAction = new boolean[] { false };
2635         ActionOnDocument action = new ActionOnDocument() {
2636             public void actionOn(ScilabDocument doc) throws IOException {
2637                 for (String act : actionsName) {
2638                     if (act.equalsIgnoreCase("indent")) {
2639                         hasAction[0] = true;
2640                         org.scilab.modules.scinotes.actions.IndentAction.getActionOnDocument().actionOn(doc);
2641                     } else if (act.equalsIgnoreCase("trailing")) {
2642                         hasAction[0] = true;
2643                         org.scilab.modules.scinotes.actions.RemoveTrailingWhiteAction.getActionOnDocument().actionOn(doc);
2644                     } else if (act.equalsIgnoreCase("quote")) {
2645                         hasAction[0] = true;
2646                         org.scilab.modules.scinotes.actions.DoubleQuoteStringAction.getActionOnDocument().actionOn(doc);
2647                     }
2648                 }
2649             }
2650         };
2651
2652         executeAction(fileName, action);
2653
2654         return hasAction[0];
2655     }
2656
2657     /**
2658      * Execute an action on file
2659      * @param fileName the name of the file
2660      * @param acts actions separated with , or ;
2661      */
2662     public static void executeAction(String fileName, String acts) throws IOException {
2663         StringTokenizer toks = new StringTokenizer(acts, ",;");
2664         String[] actions = new String[toks.countTokens()];
2665         for (int i = 0; i < actions.length; i++) {
2666             actions[i] = toks.nextToken();
2667         }
2668         executeAction(fileName, actions);
2669     }
2670
2671     /**
2672      * An interface to implement to execute an action on a document
2673      */
2674     public static interface ActionOnDocument {
2675
2676         public void actionOn(ScilabDocument doc) throws IOException;
2677     }
2678 }