* Bug #14416 fixed - The file extension filter in Scinotes "Save as" window now match...
[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     }
713
714     /**
715      * Create SciNotes instance
716      *
717      * @return the instance
718      */
719     public static void launchSciNotes() {
720         if (editor == null) {
721             List<String> uuids = ConfigSciNotesManager.getEditorsUUID();
722             boolean success = false;
723             if (!uuids.isEmpty()) {
724                 for (String uuid : uuids) {
725                     boolean exists = false;
726                     for (SciNotes ed : scinotesList) {
727                         if (ed.uuid.toString().equals(uuid)) {
728                             exists = true;
729                             break;
730                         }
731                     }
732                     if (!exists) {
733                         success = WindowsConfigurationManager.restoreUUID(uuid);
734                         if (success) {
735                             break;
736                         }
737                         ConfigSciNotesManager.removeEditorUUID(uuid);
738                     }
739                 }
740             }
741             if (!success) {
742                 editor = SciNotesTab.getEditorInstance(null);
743                 editor.setParentWindow();
744                 ConfigSciNotesManager.saveEditorUUID(editor.getPersistentId());
745                 SciNotesGUI.init(editor.getParentWindow(), editor, SCINOTES);
746                 WindowsConfigurationManager.unregisterEndedRestoration(editor);
747             }
748         }
749
750         if (!editor.restored) {
751             editor.restorePreviousSession();
752         }
753     }
754
755     /**
756      * Open a file.
757      *
758      * This method *must* be called on the EDT thread.
759      *
760      * @param filePath
761      *            the file path (may be null)
762      * @param lineNumber
763      *            the line number (use 0 for unspecified)
764      * @param option
765      *            the options (may be null)
766      */
767     public void openFile(String filePath, int lineNumber, String option) {
768         if (!SwingUtilities.isEventDispatchThread()) {
769             throw new RuntimeException("called outside the EDT thread.");
770         }
771
772         if (filePath == null) {
773             addEmptyTab();
774             activeRestoreTab();
775             return;
776         }
777
778         File f = fileToCanonicalFile(new File(filePath));
779         if (!f.getParentFile().exists()) {
780             JOptionPane.showMessageDialog(SciNotes.this, SciNotesMessages.OPEN_ERROR);
781             addEmptyTab();
782             activeRestoreTab();
783             return;
784         }
785
786         if (f.isDirectory()) { /* Bug 5131 */
787             ConfigManager.saveLastOpenedDirectory(f.getPath());
788             addEmptyTab();
789             activeRestoreTab();
790             return;
791         }
792
793         readFileAndWait(f);
794         if (option == null || option.length() == 0 || "readonly".equals(option.toLowerCase())) {
795             getTextPane().scrollTextToLineNumber(lineNumber, true);
796         } else {
797             getTextPane().scrollTextToLineNumberInWhereami(lineNumber, option, true);
798         }
799         if ((option != null && "readonly".equals(option.toLowerCase()))) {
800             getTextPane().setReadOnly(true);
801             getInfoBar().setText(getTextPane().getInfoBarText());
802             ConfigSciNotesManager.removeFromOpenFiles(this, getTextPane());
803         } else {
804             ConfigSciNotesManager.saveToRecentOpenedFiles(filePath);
805             RecentFileAction.updateRecentOpenedFilesMenu(this);
806         }
807
808         activeRestoreTab();
809     }
810
811     public void activeRestoreTab() {
812         if (getTextPane(0) == null) {
813             tabPane.setSelectedIndex(0);
814             getInfoBar().setText("");
815         }
816     }
817
818     /**
819      * Close SciNotes instance including all tabs.
820      */
821     public void closeSciNotes() {
822         for (int i = 0; i < getTabPane().getTabCount(); i++) {
823             ScilabEditorPane textPaneAt = getTextPane(i);
824             if (textPaneAt != null) {
825                 textPaneAt.destroy();
826             }
827         }
828
829         FindAction.close();
830         IncrementalSearchAction.close(this);
831         RecentFileAction.close(this);
832         OpenSourceFileOnKeywordAction.closeOpenSourceWindow();
833         SearchWordInFilesAction.closeWindow();
834
835         /*
836          * setProtectOpenFileList(true); while (getTabPane().getTabCount() > 0)
837          * { closeTabAt(0, true); } setProtectOpenFileList(false);
838          */
839
840         scinotesList.remove(this);
841         if (scinotesList.size() == 0) {
842             SciNotesAutosave.stopAutosave();
843             ScilabEditorPane.clean();
844             RegisterFavoriteDirsAction.close();
845             OpenSourceFileOnKeywordAction.close();
846             EncodingAction.close();
847             EndOfLineAction.close();
848             HelpOnTypingManager.close();
849         }
850
851         editor = null;
852         SciNotesGUI.clean(this);
853         close();
854         ConfigSciNotesManager.resetDocument();
855     }
856
857     public boolean canClose() {
858         int numberOfTab = getTabPane().getTabCount();
859         setProtectOpenFileList(true);
860
861         for (int i = 0; i < numberOfTab; i++) {
862             boolean ans = checkToCloseTabAt(i);
863             if (!ans) {
864                 setProtectOpenFileList(false);
865                 return false;
866             }
867         }
868         setProtectOpenFileList(false);
869
870         return true;
871     }
872
873     public String askForClosing() {
874         int numberOfTab = getTabPane().getTabCount();
875         boolean isContentModified = false;
876         for (int i = 0; i < getTabPane().getTabCount(); i++) {
877             ScilabEditorPane textPaneAt = getTextPane(i);
878             if (textPaneAt != null && ((ScilabDocument) textPaneAt.getDocument()).isContentModified()) {
879                 isContentModified = true;
880                 break;
881             }
882         }
883
884         if (isContentModified) {
885             return "SciNotes";
886         }
887
888         return null;
889     }
890
891     public static void closeEditor(SciNotes ed) {
892         if (scinotesList.size() > 1) {
893             ClosingOperationsManager.startClosingOperationWithoutSave((SwingScilabDockablePanel) ed);
894         } else {
895             ClosingOperationsManager.startClosingOperation((SwingScilabDockablePanel) ed);
896         }
897     }
898
899     /**
900      * Close a tab using its index.
901      *
902      * @param indexTab
903      *            the index of the tab
904      * @return if the tab has been really closed
905      */
906     public boolean closeTabAtWithoutConfirmation(int indexTab) {
907         return closeTabAt(indexTab, false, false);
908     }
909
910     /**
911      * Close a tab using its index.
912      *
913      * @param indexTab
914      *            the index of the tab
915      * @return if the tab has been really closed
916      */
917     public boolean closeTabAt(int indexTab) {
918         return closeTabAt(indexTab, false, true);
919     }
920
921     /**
922      * Close a tab using its index.
923      *
924      * @param indexTab
925      *            the index of the tab
926      * @param scilabClose
927      *            if true, save dialog confirmation cannot be canceled
928      * @return if the tab has been really closed
929      */
930     public boolean closeTabAt(int indexTab, boolean scilabClose, boolean confirmation) {
931         ScilabEditorPane textPaneAt = getTextPane(indexTab);
932
933         /*
934          * Test for modification added after bug 5103 fix: do not ask the user
935          * for an Untitled not-modified file saving when closing SciNotes
936          */
937         if (confirmation && ((ScilabDocument) textPaneAt.getDocument()).isContentModified()) {
938             if (!save(indexTab, false, scilabClose)) {
939                 return false;
940             }
941         }
942
943         textPaneAt.close();
944
945         if (textPaneAt.getName() == null) {
946             String closedTabName = tabPane.getScilabTitleAt(indexTab);
947             String closedTabNameIndex = closedTabName.substring(closedTabName.length() - 1, closedTabName.length());
948             tabList.remove(Integer.valueOf(closedTabNameIndex));
949             closedTabList.add(Integer.valueOf(closedTabNameIndex));
950         }
951
952         // correction for bug 5404, closing the last tabPane generate an
953         // exception
954         // that's why we need to remove ChangeListeners before closing
955         if ((indexTab == 0) && (getTabPane().getTabCount() == 1)) {
956             for (int i = 0; i < tabPane.getChangeListeners().length; i++) {
957                 tabPane.removeChangeListener(tabPane.getChangeListeners()[i]);
958             }
959         }
960
961         // Remove the filename associated with the tab from the list of open
962         // files.
963         if (!protectOpenFileList) {
964             ConfigSciNotesManager.removeFromOpenFiles(this, textPaneAt);
965         }
966
967         if (navigator != null) {
968             navigator.removePane(textPaneAt);
969         }
970
971         tabPane.remove(indexTab);
972
973         textPaneAt = getTextPane();
974         if (textPaneAt != null) {
975             if (navigator != null) {
976                 navigator.update((ScilabDocument) textPaneAt.getDocument());
977             }
978         }
979         return true;
980     }
981
982     public boolean checkToCloseTabAt(int index) {
983         ScilabEditorPane textPaneAt = getTextPane(index);
984
985         /*
986          * Test for modification added after bug 5103 fix: do not ask the user
987          * for an Untitled not-modified file saving when closing SciNotes
988          */
989         if (textPaneAt != null && ((ScilabDocument) textPaneAt.getDocument()).isContentModified()) {
990             if (!save(index, false, false)) {
991                 return false;
992             }
993         }
994
995         return true;
996     }
997
998     /**
999      * Set or unset protection of the currently open file list. Call before
1000      * closing tabs if the tabs should be restored when scinotes restarts.
1001      *
1002      * @param protect
1003      *            Enables protection of the open file list if true.
1004      */
1005     public void setProtectOpenFileList(boolean protect) {
1006         protectOpenFileList = protect;
1007     }
1008
1009     /**
1010      * Determines if this editor is the only editor instance.
1011      *
1012      * @return true if this is the last editor instance.
1013      */
1014     public boolean isOnlyInstance() {
1015         if (scinotesList.size() > 1) {
1016             return false;
1017         }
1018
1019         return true;
1020     }
1021
1022     /**
1023      * @return the list of the different openened editors
1024      */
1025     public static List<SciNotes> getSciNotesList() {
1026         return scinotesList;
1027     }
1028
1029     /**
1030      * Save a file.
1031      *
1032      * @param indexTab
1033      *            the textPane index containing the file contents
1034      * @return execution status
1035      */
1036     public boolean save(int indexTab) {
1037         return save(indexTab, false, false);
1038     }
1039
1040     /**
1041      * Save a file.
1042      *
1043      * @param indexTab
1044      *            the textPane index containing the file contents
1045      * @param force
1046      *            : force save without confirmation dialog ( SaveAction )
1047      * @return execution status
1048      */
1049     public boolean save(int indexTab, boolean force) {
1050         return save(indexTab, force, false);
1051     }
1052
1053     /**
1054      * Save a file.
1055      *
1056      * @param indexTab
1057      *            the textPane index containing the file contents
1058      * @param force
1059      *            : force save without confirmation dialog ( SaveAction )
1060      * @param scilabClose
1061      *            : if true, save dialog confirmation cannot be canceled
1062      * @return execution status
1063      */
1064     public boolean save(int indexTab, boolean force, boolean scilabClose) {
1065         ScilabEditorPane textPaneAt = getTextPane(indexTab);
1066         getTabPane().setSelectedIndex(indexTab);
1067
1068         // if the file ( empty, new or loaded ) is not modified, exit save
1069         // process and return true
1070         if (!textPaneAt.checkExternalModif() && !((ScilabDocument) textPaneAt.getDocument()).isContentModified() && (textPaneAt.getName() != null)) {
1071             /*
1072              * Bug
1073              * 5103
1074              * fix
1075              */
1076             return true;
1077         }
1078
1079         if (!force) {
1080             AnswerOption answer;
1081             if (scilabClose) {
1082                 answer = ScilabModalDialog.show(this, String.format(SciNotesMessages.MODIFIED, textPaneAt.getShortName()), SciNotesMessages.SCILAB_EDITOR,
1083                                                 IconType.QUESTION_ICON, ButtonType.YES_NO);
1084             } else {
1085                 answer = ScilabModalDialog.show(this, String.format(SciNotesMessages.MODIFIED, textPaneAt.getShortName()), SciNotesMessages.SCILAB_EDITOR,
1086                                                 IconType.QUESTION_ICON, ButtonType.YES_NO_CANCEL);
1087             }
1088
1089             switch (answer) {
1090                 case YES_OPTION: // Yes, continue
1091                     break;
1092                 case NO_OPTION:// No, exit and returns true
1093                     return true;
1094                 case CANCEL_OPTION: // Cancel, exit and return false
1095                     return false;
1096                 default:
1097                     break;
1098             }
1099         }
1100
1101         String fileToSave = textPaneAt.getName();
1102         if (fileToSave == null) {
1103             // need a filename, call chooseFileToSave
1104             fileToSave = chooseFileToSave(SciNotesMessages.SAVE);
1105         } else {
1106             // check if the file has been modified by external software
1107             fileToSave = checkExternalModification(fileToSave);
1108         }
1109
1110         if (fileToSave == null || fileToSave.length() == 0) {
1111             return true; /*
1112                           * Bug 5189: The user cancels ==> do not want an error
1113                           * message
1114                           */
1115         }
1116
1117         File newSavedFile = new File(fileToSave);
1118
1119         if (!SaveFile.doSave(textPaneAt, indexTab, newSavedFile, editorKit)) {
1120             return false;
1121         }
1122
1123         ScilabDocument styledDocument = (ScilabDocument) textPaneAt.getDocument();
1124         styledDocument.setContentModified(false);
1125
1126         textPaneAt.setLastModified(newSavedFile.lastModified());
1127
1128         if (textPaneAt.getName() == null) {
1129             String name = getTabPane().getScilabTitleAt(indexTab);
1130             String index = name.substring(name.length() - 1, name.length());
1131             tabList.remove(Integer.valueOf(index));
1132             closedTabList.add(Integer.valueOf(index));
1133         }
1134
1135         textPaneAt.setName(fileToSave);
1136         getTabPane().setTitleAt(indexTab, newSavedFile.getName());
1137
1138         setTitle(textPaneAt.getTitle());
1139         ConfigSciNotesManager.saveToOpenFiles(fileToSave, this, textPaneAt);
1140
1141         return true;
1142     }
1143
1144     /**
1145      * Overwrite the file at a given index.
1146      *
1147      * @param indexTab
1148      *            the textPane index containing the file contents
1149      * @return execution status
1150      */
1151     public boolean overwrite(int indexTab) {
1152         ScilabEditorPane textPaneAt = getTextPane(indexTab);
1153         String fileToSave = textPaneAt.getName();
1154         if (fileToSave == null) {
1155             return true;
1156         }
1157
1158         File newSavedFile = new File(fileToSave);
1159         if (!newSavedFile.exists()) {
1160             return true;
1161         }
1162
1163         if (!SaveFile.doSave(textPaneAt, indexTab, newSavedFile, editorKit)) {
1164             return false;
1165         }
1166
1167         ScilabDocument styledDocument = (ScilabDocument) textPaneAt.getDocument();
1168         styledDocument.setContentModified(false);
1169
1170         getTabPane().setTitleAt(getTabPane().getSelectedIndex(), newSavedFile.getName());
1171
1172         // Get current file path for Execute file into Scilab
1173         getTextPane().setLastModified(newSavedFile.lastModified());
1174
1175         textPaneAt.setName(fileToSave);
1176         setTitle(textPaneAt.getTitle());
1177
1178         return true;
1179     }
1180
1181     /**
1182      * Check for external modification. If it is the case, propose to select a
1183      * new file name.
1184      *
1185      * @param filename
1186      *            The name of the file
1187      * @return the filename where to save
1188      */
1189     public String checkExternalModification(String filename) {
1190         File newSavedFile = new File(filename);
1191         if (newSavedFile.lastModified() > getTextPane().getLastModified()) {
1192             if (ScilabModalDialog.show(this, String.format(SciNotesMessages.EXTERNAL_MODIFICATION, newSavedFile.getPath()),
1193                                        SciNotesMessages.REPLACE_FILE_TITLE, IconType.QUESTION_ICON, ButtonType.YES_NO) == AnswerOption.NO_OPTION) {
1194                 return chooseFileToSave(SciNotesMessages.SAVE);
1195             }
1196         }
1197         return filename;
1198     }
1199
1200     /**
1201      * Return through a file selector the name of the selected file.
1202      *
1203      * @param title
1204      *            the title for JFileChooser
1205      * @return the file picked up by the user
1206      */
1207     public String chooseFileToSave(String title) {
1208         return chooseFileToSave(title, null);
1209     }
1210
1211     /**
1212      * Return through a file selector the name of the selected file.
1213      *
1214      * @param title
1215      *            the title for JFileChooser
1216      * @param path
1217      *            the path where to open the filechooser
1218      * @return the file picked up by the user
1219      */
1220     public String chooseFileToSave(String title, String path) {
1221         String extension = new String();
1222
1223         String initialDirectoryPath = path;
1224         if (initialDirectoryPath == null) {
1225             initialDirectoryPath = getTextPane().getName();
1226         }
1227         if (initialDirectoryPath == null) {
1228             if (firstOpen) {
1229                 initialDirectoryPath = CommonFileUtils.getCWD();
1230                 firstOpen = false;
1231             } else {
1232                 initialDirectoryPath = ConfigManager.getLastOpenedDirectory();
1233             }
1234         }
1235
1236         SciFileFilter sceFilter = new SciFileFilter(ALL_SCE_FILES, null, 0);
1237         SciFileFilter sciFilter = new SciFileFilter(ALL_SCI_FILES, null, 1);
1238         SciFileFilter scxFilter = new SciFileFilter(ALL_SCX_FILES, null, 2);
1239         SciFileFilter tstFilter = new SciFileFilter(ALL_TST_FILES, null, 3);
1240         SciFileFilter startFilter = new SciFileFilter(ALL_START_FILES, null, 4);
1241         SciFileFilter quitFilter = new SciFileFilter(ALL_QUIT_FILES, null, 5);
1242         SciFileFilter demFilter = new SciFileFilter(ALL_DEM_FILES, null, 6);
1243         SciFileFilter allFilter = new SciFileFilter(ALL_FILES, null, 7);
1244         SciFileFilter allScilabFilter = new SciFileFilter(ALL_SCILAB, null, 8);
1245
1246         SwingScilabFileChooser fileChooser = ((SwingScilabFileChooser) ScilabFileChooser.createFileChooser().getAsSimpleFileChooser());
1247
1248         fileChooser.setAcceptAllFileFilterUsed(false);
1249         fileChooser.setInitialDirectory(initialDirectoryPath);
1250         fileChooser.setUiDialogType(Juigetfile.SAVE_DIALOG);
1251
1252         // order is also important here
1253         fileChooser.addChoosableFileFilter(sceFilter);
1254         fileChooser.addChoosableFileFilter(sciFilter);
1255         fileChooser.addChoosableFileFilter(scxFilter);
1256         fileChooser.addChoosableFileFilter(tstFilter);
1257         fileChooser.addChoosableFileFilter(startFilter);
1258         fileChooser.addChoosableFileFilter(quitFilter);
1259         fileChooser.addChoosableFileFilter(demFilter);
1260         fileChooser.addChoosableFileFilter(allFilter);
1261         fileChooser.addChoosableFileFilter(allScilabFilter);
1262
1263         String name = getTextPane().getName();
1264         File tempFile = new File(name);
1265
1266         // Select default file type
1267         SciFileFilter fileFilter = sceFilter;
1268         // Look for a supported extension
1269         for (FileFilter filter : fileChooser.getChoosableFileFilters()) {
1270             if (((SciFileFilter) filter).accept(tempFile)) {
1271                 fileFilter = (SciFileFilter) filter;
1272                 break;
1273             }
1274         }
1275         fileChooser.setFileFilter(fileFilter);
1276         fileChooser.setTitle(title);
1277
1278         if (name == null) {
1279             name = ((ScilabDocument) getTextPane().getDocument()).getFirstFunctionName();
1280             if (name != null) {
1281                 name += SCI_EXTENSION;
1282             }
1283         }
1284
1285         if (name != null) {
1286             fileChooser.setSelectedFile(new File(name));
1287         }
1288
1289         int retval = fileChooser.showSaveDialog(this);
1290
1291         if (retval == JFileChooser.APPROVE_OPTION) {
1292             File f = fileToCanonicalFile(fileChooser.getSelectedFile());
1293             initialDirectoryPath = f.getPath();
1294             if (f.exists()) {
1295                 if (ScilabModalDialog.show(this, SciNotesMessages.REPLACE_FILE_TITLE, SciNotesMessages.FILE_ALREADY_EXIST, IconType.QUESTION_ICON,
1296                                            ButtonType.YES_NO) == AnswerOption.NO_OPTION) {
1297                     return chooseFileToSave(SciNotesMessages.SAVE);
1298                 }
1299             }
1300
1301             /* we test if the file has already a scilab extension */
1302             boolean hasNoExtension = true;
1303
1304             // if the file name is like this : any character , a dot , then
1305             // 2,3or 4 characters, then
1306             // we consider the file has already an extension
1307             // we previously only check for .sci and .sce extension, but what if
1308             // the user open a txt file
1309             String fileName = f.getName();
1310             if (fileName.lastIndexOf(DOT) != -1) {
1311                 if (fileName.substring(fileName.lastIndexOf(DOT), fileName.length()).length() >= 2
1312                         && fileName.substring(fileName.lastIndexOf(DOT), fileName.length()).length() <= 4) {
1313                     hasNoExtension = false;
1314                 }
1315             }
1316
1317             /* if no extension , we add it */
1318             if (hasNoExtension) {
1319                 if (fileChooser.getFileFilter() == sciFilter) {
1320                     extension = SCI_EXTENSION;
1321                 } else if (fileChooser.getFileFilter() == sceFilter) {
1322                     extension = SCE_EXTENSION;
1323                 } else if (fileChooser.getFileFilter() == scxFilter) {
1324                     extension = SCE_EXTENSION;
1325                 } else if (fileChooser.getFileFilter() == tstFilter) {
1326                     extension = TST_EXTENSION;
1327                 } else if (fileChooser.getFileFilter() == startFilter) {
1328                     extension = START_EXTENSION;
1329                 } else if (fileChooser.getFileFilter() == quitFilter) {
1330                     extension = QUIT_EXTENSION;
1331                 } else if (fileChooser.getFileFilter() == demFilter) {
1332                     extension = DEM_EXTENSION;
1333                 } else {
1334                     extension = "";
1335                 }
1336                 return f.getPath() + extension;
1337             }
1338
1339             if (initialDirectoryPath != null) {
1340                 ConfigManager.saveLastOpenedDirectory(initialDirectoryPath);
1341             }
1342
1343             return f.getPath();
1344         } else if (retval == JFileChooser.CANCEL_OPTION) {
1345             return "";
1346         }
1347
1348         return null;
1349     }
1350
1351     /**
1352      * Save a file.
1353      *
1354      * @param path
1355      *            the initial path where the filechooser will be open
1356      * @return execution status
1357      */
1358     public boolean saveAs(String path) {
1359         String filename = chooseFileToSave(SciNotesMessages.SAVE_AS, path);
1360         if (filename == null || filename.length() == 0) {
1361             return true;
1362         }
1363
1364         File f = new File(filename);
1365         ScilabDocument styledDocument = (ScilabDocument) getTextPane().getDocument();
1366
1367         if (!SaveFile.doSave(getTextPane(), getTabPane().getSelectedIndex(), f, editorKit)) {
1368             return false;
1369         }
1370
1371         if (getTextPane().getName() == null) {
1372             String name = getTabPane().getScilabTitleAt(getTabPane().getSelectedIndex());
1373             String index = name.substring(name.length() - 1, name.length());
1374             tabList.remove(Integer.valueOf(index));
1375             closedTabList.add(Integer.valueOf(index));
1376         }
1377
1378         firstOpen = false;
1379         ConfigManager.saveLastOpenedDirectory(f.getPath());
1380         ConfigSciNotesManager.saveToRecentOpenedFiles(f.getPath());
1381         ConfigSciNotesManager.renameOpenFilesItem(f.getPath(), this, getTextPane());
1382         getTextPane().setName(f.getPath());
1383         getTabPane().setTitleAt(getTabPane().getSelectedIndex(), f.getName());
1384         setTitle(getTextPane().getTitle());
1385
1386         RecentFileAction.updateRecentOpenedFilesMenu(this);
1387
1388         if (navigator != null) {
1389             navigator.update(styledDocument);
1390         }
1391
1392         styledDocument.setContentModified(false);
1393         getTextPane().setLastModified(f.lastModified());
1394         getTextPane().setReadOnly(false);
1395         getInfoBar().setText(getTextPane().getInfoBarText());
1396
1397         return true;
1398     }
1399
1400     /**
1401      * Create a new tab in SciNotes.
1402      *
1403      * @param title
1404      *            the title of the tab
1405      * @return the text component inside the tab
1406      */
1407     public ScilabEditorPane addTab(String title) {
1408         return addTab(title, Integer.MAX_VALUE);
1409     }
1410
1411     /**
1412      * Create a new tab in SciNotes.
1413      *
1414      * @param title
1415      *            the title of the tab
1416      * @param index
1417      *            the index where to put the new tab
1418      * @return the text component inside the tab
1419      */
1420     public ScilabEditorPane addTab(String title, int index) {
1421         return addTab(title, index, 0);
1422     }
1423
1424     /**
1425      * Create a new tab in SciNotes.
1426      *
1427      * @param title
1428      *            the title of the tab
1429      * @param index
1430      *            the index where to put the new tab
1431      * @return the text component inside the tab
1432      */
1433     public ScilabEditorPane addTab(String title, int index, int caretPos) {
1434         ScilabEditorPane sep = new ScilabEditorPane(this);
1435         initPane(sep);
1436         int ind = Math.min(Math.max(0, index), tabPane.getTabCount());
1437         tabPane.insertTab(title, null, sep.getEditorComponent(), "", ind);
1438         tabPane.setSelectedIndex(ind);
1439         initInputMap(sep);
1440         updateTabTitle();
1441         getInfoBar().setText(sep.getInfoBarText());
1442         repaint();
1443         sep.init(caretPos);
1444         return sep;
1445     }
1446
1447     public void addRestoreTab() {
1448         try {
1449             JPanel panel = RestoreOpenedFilesAction.getTab(this, getUUID().toString());
1450             if (panel != null) {
1451                 tabPane.addTab("Restore", panel);
1452             }
1453         } catch (Exception e) {
1454             System.err.println(e);
1455         }
1456     }
1457
1458     /**
1459      * Init a pane
1460      *
1461      * @param pane
1462      *            the pane to init
1463      */
1464     public void initPane(ScilabEditorPane pane) {
1465         initPane(pane, !SciNotesOptions.getSciNotesDisplay().wrapLines);
1466     }
1467
1468     /**
1469      * Init the EditorPane.
1470      *
1471      * @param pane
1472      *            the EditorPane
1473      * @param plain
1474      *            true for a plain view or false for a wrapped view
1475      */
1476     public void initPane(ScilabEditorPane pane, boolean plain) {
1477         setHighlight(pane);
1478         ScilabEditorKit kit = new ScilabEditorKit(plain);
1479         pane.setEditorKit(kit);
1480
1481         // Panel of line number for the text pane
1482         pane.getXln().setWhereamiLineNumbering(SciNotesOptions.getSciNotesDisplay().showLineNumbers, SciNotesOptions.getSciNotesDisplay().whereami);
1483         activateHelpOnTyping(pane);
1484
1485         pane.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
1486         pane.setFont(kit.getStylePreferences().tokenFonts[0]);
1487
1488         pane.setBackground(SciNotesOptions.getSciNotesDisplay().backgroundColor);
1489         pane.setCaretColor(SciNotesOptions.getSciNotesDisplay().caretColor);
1490
1491         pane.setFocusable(true);
1492         pane.setRequestFocusEnabled(true);
1493         pane.setDragEnabled(true); /* Bug 5497 */
1494
1495         DropFilesListener dndTarget = new DropFilesListener(pane);
1496
1497         pane.setComponentPopupMenu(SciNotesGUI.generateRightClickPopup(this));
1498     }
1499
1500     /**
1501      * Init the EditorPane with the InputMap found in ConfigSciNotesManager
1502      *
1503      * @param pane
1504      *            the EditorPane
1505      */
1506     public void initInputMap(ScilabEditorPane pane) {
1507         setKeyStrokeAction(pane, this);
1508         LineBeautifierAction.putInInputMap(pane);
1509         InsertOverwriteAction.putInInputMap(pane);
1510     }
1511
1512     /**
1513      * Split the EditorPane
1514      *
1515      * @param vertical
1516      *            true for a vertical split
1517      */
1518     public void splitTab(boolean vertical) {
1519         ScilabEditorPane pane = getTextPane();
1520         Component bottom = pane.getEditorComponent().getBottom();
1521         int state = pane.getXln().getState();
1522         ScilabEditorPane leftPane = new ScilabEditorPane(editor);
1523         ScilabEditorPane rightPane = new ScilabEditorPane(editor);
1524         if (navigator != null) {
1525             navigator.changePaneOnSplit(pane, leftPane);
1526         }
1527         initPane(leftPane, true);
1528         initPane(rightPane, true);
1529         leftPane.setOtherPaneInSplit(rightPane);
1530         rightPane.setOtherPaneInSplit(leftPane);
1531         pane.copyProps(leftPane);
1532         pane.copyProps(rightPane);
1533         ScilabDocument doc = (ScilabDocument) pane.getDocument();
1534         leftPane.setDocument(doc);
1535         rightPane.setDocument(doc);
1536         leftPane.setCaretPosition(0);
1537         rightPane.setCaretPosition(0);
1538         JSplitPane split;
1539         if (vertical) {
1540             split = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
1541         } else {
1542             split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
1543         }
1544         leftPane.getXln().setWhereamiLineNumbering(state);
1545         rightPane.getXln().setWhereamiLineNumbering(state);
1546         split.setLeftComponent(leftPane.getScrollPane());
1547         split.setRightComponent(rightPane.getScrollPane());
1548         split.setResizeWeight(0.5);
1549         rightPane.setEditorComponent(leftPane.getEditorComponent());
1550         leftPane.setSplitPane(split);
1551         rightPane.setSplitPane(split);
1552
1553         activateHelpOnTyping(leftPane);
1554         activateHelpOnTyping(rightPane);
1555         initInputMap(leftPane);
1556         initInputMap(rightPane);
1557         if (doc.getBinary()) {
1558             leftPane.setBinary(true);
1559             rightPane.setBinary(true);
1560         }
1561         getInfoBar().setText(leftPane.getInfoBarText());
1562         updateTabTitle();
1563         tabPane.setComponentAt(tabPane.getSelectedIndex(), leftPane.getEditorComponent());
1564         leftPane.getEditorComponent().insertBottomComponent(bottom);
1565         leftPane.requestFocus();
1566     }
1567
1568     /**
1569      * Remove a split
1570      */
1571     public void removeSplit() {
1572         if (((EditorComponent) tabPane.getSelectedComponent()).isSplited()) {
1573             ScilabEditorPane pane = new ScilabEditorPane(editor);
1574             ScilabEditorPane textpane = getTextPane();
1575             Component bottom = textpane.getEditorComponent().getBottom();
1576             if (navigator != null) {
1577                 navigator.changePaneOnSplit(textpane, pane);
1578             }
1579             initPane(pane);
1580             textpane.setOtherPaneInSplit(null);
1581             textpane.copyProps(pane);
1582             ScilabDocument doc = (ScilabDocument) textpane.getDocument();
1583             pane.setDocument(doc);
1584             pane.setCaretPosition(0);
1585             activateHelpOnTyping(pane);
1586             tabPane.setComponentAt(tabPane.getSelectedIndex(), pane.getEditorComponent());
1587             initInputMap(pane);
1588             if (doc.getBinary()) {
1589                 pane.setBinary(true);
1590             }
1591             getInfoBar().setText(pane.getInfoBarText());
1592             updateTabTitle();
1593             pane.getEditorComponent().insertBottomComponent(bottom);
1594             pane.requestFocus();
1595         }
1596     }
1597
1598     /**
1599      * Create an empty tab inside SciNotes.
1600      *
1601      * @return the text component inside the tab
1602      */
1603     public ScilabEditorPane addEmptyTab() {
1604         ScilabEditorPane sep;
1605         int n = getNumberForEmptyTab();
1606         sep = addTab(SciNotesMessages.UNTITLED + n);
1607         sep.setShortName(SciNotesMessages.UNTITLED + n);
1608         sep.setTitle(SciNotesMessages.UNTITLED + n);
1609         setTitle(sep.getTitle());
1610         SciNotesOptions.Header header = SciNotesOptions.getSciNotesHeader();
1611         if (header.header != null) {
1612             ((ScilabDocument) sep.getDocument()).disableUndoManager();
1613             try {
1614                 sep.getDocument().insertString(0, header.header, null);
1615             } catch (BadLocationException e) { }
1616             sep.init(header.header.length());
1617             ((ScilabDocument) sep.getDocument()).setContentModified(false);
1618             ((ScilabDocument) sep.getDocument()).enableUndoManager();
1619         }
1620
1621         return sep;
1622     }
1623
1624     /**
1625      * Get an integer used for untitled document
1626      */
1627     public int getNumberForEmptyTab() {
1628         if (closedTabList.size() > 0) {
1629             Integer n = Collections.min(closedTabList);
1630             closedTabList.remove(n);
1631             return n.intValue();
1632         } else {
1633             numberOfUntitled++;
1634             tabList.add(Integer.valueOf(numberOfUntitled));
1635             return numberOfUntitled;
1636         }
1637     }
1638
1639     /**
1640      * Add or remove '*' prefix in current tab tile according to
1641      * isContentModified().
1642      */
1643     public void updateTabTitle() {
1644         updateTabTitle(getTabPane().getSelectedIndex());
1645     }
1646
1647     /**
1648      * Add or remove '*' prefix in tab title (corresponding to the given index) according to
1649      * isContentModified().
1650      */
1651     public void updateTabTitle(int index) {
1652         StringBuffer newTitle = new StringBuffer();
1653         ScilabEditorPane currentTextPane = getTextPane(index);
1654         if (((ScilabDocument) currentTextPane.getDocument()).isContentModified()) {
1655             newTitle.append('*');
1656         }
1657
1658         String textPaneName = currentTextPane.getName();
1659         try {
1660             File f = new File(textPaneName);
1661             newTitle.append(f.getName());
1662         } catch (NullPointerException e) { // not a file name, no path prefix to
1663             // remove, but maybe a '*'
1664             textPaneName = getTabPane().getScilabTitleAt(index);
1665             if (textPaneName.charAt(0) == '*') {
1666                 newTitle.append(textPaneName.substring(1, textPaneName.length()));
1667             } else {
1668                 newTitle.append(textPaneName);
1669             }
1670         }
1671         getTabPane().setTitleAt(index, newTitle.toString());
1672     }
1673
1674     /**
1675      * @param button
1676      *            the UndoButton used in this editor
1677      */
1678     public void setUndoButton(JButton button) {
1679         undoButton = button;
1680         enableUndoButton(false);
1681     }
1682
1683     /**
1684      * @param b
1685      *            true to enable the button
1686      */
1687     public void enableUndoButton(boolean b) {
1688         if (undoButton != null) {
1689             undoButton.setEnabled(b);
1690         }
1691     }
1692
1693     /**
1694      * Undo last modification.
1695      */
1696     public void undo() {
1697         ScilabDocument doc = (ScilabDocument) getTextPane().getDocument();
1698         synchronized (doc) {
1699             doc.getUndoManager().undo();
1700         }
1701     }
1702
1703     /**
1704      * @param button
1705      *            the RedoButton used in this editor
1706      */
1707     public void setRedoButton(JButton button) {
1708         redoButton = button;
1709         enableRedoButton(false);
1710     }
1711
1712     /**
1713      * @param b
1714      *            true to enable the button
1715      */
1716     public void enableRedoButton(boolean b) {
1717         if (redoButton != null) {
1718             redoButton.setEnabled(b);
1719         }
1720     }
1721
1722     /**
1723      * Redo last modification.
1724      */
1725     public void redo() {
1726         ScilabDocument doc = (ScilabDocument) getTextPane().getDocument();
1727         synchronized (doc) {
1728             doc.getUndoManager().redo();
1729         }
1730     }
1731
1732     /**
1733      * Reload a file inside SciNotes.
1734      *
1735      * @param index
1736      *            the index
1737      */
1738     public void reload(int index) {
1739         ScilabEditorPane textPaneAt = getTextPane(index);
1740         if (textPaneAt != null && textPaneAt.getName() != null) {
1741             if ((index == 0) && (getTabPane().getTabCount() == 1)) {
1742                 for (int j = 0; j < tabPane.getChangeListeners().length; j++) {
1743                     tabPane.removeChangeListener(tabPane.getChangeListeners()[j]);
1744                 }
1745             }
1746             ConfigSciNotesManager.removeFromOpenFiles(this, textPaneAt);
1747             tabPane.remove(index);
1748             File f = new File(textPaneAt.getName());
1749             if (f.exists()) {
1750                 loadFile(f, index);
1751             } else {
1752                 createNewFile(f);
1753             }
1754         }
1755     }
1756
1757     /**
1758      * Load a file inside SciNotes.
1759      *
1760      * @param f
1761      *            the file to open
1762      */
1763     public void readFile(File f) {
1764         /** Is this file already opened */
1765         boolean alreadyOpened = false;
1766         for (int i = 0; i < tabPane.getTabCount(); i++) {
1767             ScilabEditorPane textPaneAt = getTextPane(i);
1768             if (f.getAbsolutePath().equals(textPaneAt.getName())) {
1769                 /* File is already opnened */
1770                 tabPane.setSelectedIndex(i);
1771                 alreadyOpened = true;
1772                 break;
1773             }
1774         }
1775
1776         if (!alreadyOpened) {
1777             if (f.exists()) {
1778                 loadFile(f);
1779             } else {
1780                 createNewFile(f);
1781             }
1782         }
1783     }
1784
1785     /**
1786      * Load a file inside SciNotes.
1787      *
1788      * @param file
1789      *            the file to open
1790      */
1791     public void readFileAndWait(File file) {
1792         /** Is this file already opened */
1793         File f = file;
1794         boolean alreadyOpened = false;
1795         int index = -1;
1796         for (int i = 0; i < tabPane.getTabCount(); i++) {
1797             ScilabEditorPane textPaneAt = getTextPane(i);
1798             if (textPaneAt != null && f.getAbsolutePath().equals(textPaneAt.getName())) {
1799                 /* File is already opened */
1800                 tabPane.setSelectedIndex(i);
1801                 if (f.lastModified() > textPaneAt.getLastModified()) {
1802
1803                     /*
1804                      * Create a new messagebox to know what the user wants to do
1805                      * if the file has been modified outside SciNotes
1806                      */
1807                     MessageBox messageBox = ScilabMessageBox.createMessageBox();
1808                     messageBox.setTitle(SciNotesMessages.REPLACE_FILE_TITLE);
1809                     messageBox.setMessage(String.format(SciNotesMessages.EXTERNAL_MODIFICATION, textPaneAt.getName()));
1810
1811                     String[] labels = new String[] { SciNotesMessages.RELOAD, SciNotesMessages.OVERWRITE, SciNotesMessages.IGNORE };
1812                     messageBox.setButtonsLabels(labels);
1813
1814                     messageBox.setIcon("question"); // Question icon
1815
1816                     messageBox.setParentForLocation(this); // Centered on
1817                     // SciNotes main
1818                     // window
1819
1820                     messageBox.displayAndWait(); // Waits for a user action
1821
1822                     switch (messageBox.getSelectedButton()) {
1823                         case 1: // Reload
1824                             if ((i == 0) && (getTabPane().getTabCount() == 1)) {
1825                                 for (int j = 0; j < tabPane.getChangeListeners().length; j++) {
1826                                     tabPane.removeChangeListener(tabPane.getChangeListeners()[j]);
1827                                 }
1828                             }
1829                             tabPane.remove(i);
1830                             f = new File(textPaneAt.getName());
1831                             index = i;
1832                             break;
1833                         case 2: // Overwrite 2
1834                             overwrite(i);
1835                             alreadyOpened = true;
1836                             break;
1837                         default: // Ignore
1838                             alreadyOpened = true;
1839                     }
1840                 } else {
1841                     alreadyOpened = true;
1842                 }
1843                 break;
1844             }
1845         }
1846
1847         if (!alreadyOpened) {
1848             if (f.exists()) {
1849                 loadFile(f, index);
1850             } else {
1851                 createNewFile(f);
1852             }
1853         }
1854     }
1855
1856     public int getTextPaneIndex(ScilabEditorPane sep) {
1857         int n = tabPane.getTabCount();
1858         for (int i = 0; i < n; ++i) {
1859             ScilabEditorPane pane = getTextPane(i);
1860             if (pane != null && (pane == sep || pane.getOtherPaneInSplit() == sep)) {
1861                 return i;
1862             }
1863         }
1864
1865         return -1;
1866     }
1867
1868     /**
1869      * Get current text component. If the window is splitted, then return the
1870      * focused text component.
1871      *
1872      * @return the text component
1873      */
1874     public ScilabEditorPane getTextPane() {
1875         try {
1876             if (tabPane.getSelectedComponent() instanceof EditorComponent) {
1877                 EditorComponent c = (EditorComponent) tabPane.getSelectedComponent();
1878                 ScilabEditorPane pane = c.getEditorPane();
1879                 if (ScilabEditorPane.getFocusedPane() == pane.getOtherPaneInSplit()) {
1880                     return pane.getOtherPaneInSplit();
1881                 }
1882
1883                 return pane;
1884             }
1885         } catch (NullPointerException e) {
1886         } catch (ArrayIndexOutOfBoundsException e) {
1887         }
1888
1889         return null;
1890     }
1891
1892     /**
1893      * Get text component at index.
1894      *
1895      * @param index
1896      *            the index of the textpane
1897      * @return the text component
1898      */
1899     public ScilabEditorPane getTextPane(int index) {
1900         try {
1901             if (tabPane.getComponentAt(index) instanceof EditorComponent) {
1902                 EditorComponent c = (EditorComponent) tabPane.getComponentAt(index);
1903                 ScilabEditorPane pane = c.getEditorPane();
1904                 if (ScilabEditorPane.getFocusedPane() == pane.getOtherPaneInSplit()) {
1905                     return pane.getOtherPaneInSplit();
1906                 }
1907
1908                 return pane;
1909             }
1910         } catch (NullPointerException e) {
1911         } catch (ArrayIndexOutOfBoundsException e) {
1912         }
1913
1914         return null;
1915     }
1916
1917     /**
1918      * Set the keystroke actions
1919      */
1920     public static void setAllMenus() {
1921         for (SciNotes ed : scinotesList) {
1922             SciNotesGUI.reinitMenus(ed);
1923             int n = ed.getTabPane().getTabCount();
1924             for (int i = 0; i < n; i++) {
1925                 ScilabEditorPane sep = ed.getTextPane(i);
1926                 sep.setComponentPopupMenu(SciNotesGUI.generateRightClickPopup(ed));
1927                 if (sep.getOtherPaneInSplit() != null) {
1928                     sep.getOtherPaneInSplit().setComponentPopupMenu(SciNotesGUI.generateRightClickPopup(ed));
1929                 }
1930             }
1931         }
1932     }
1933
1934     /**
1935      * Set the keystroke actions
1936      */
1937     public static void setKeyStrokeActions() {
1938         for (SciNotes ed : scinotesList) {
1939             int n = ed.getTabPane().getTabCount();
1940             for (int i = 0; i < n; i++) {
1941                 ScilabEditorPane sep = ed.getTextPane(i);
1942                 ed.initInputMap(sep);
1943                 if (sep.getOtherPaneInSplit() != null) {
1944                     ed.initInputMap(sep.getOtherPaneInSplit());
1945                 }
1946             }
1947         }
1948     }
1949
1950     /**
1951      * Enable the whereami-line numbering
1952      *
1953      * @param state
1954      *            int
1955      */
1956     public static void setWhereamiLineNumbering() {
1957         for (SciNotes ed : scinotesList) {
1958             int n = ed.getTabPane().getTabCount();
1959             for (int i = 0; i < n; i++) {
1960                 ScilabEditorPane sep = ed.getTextPane(i);
1961                 sep.getXln().setWhereamiLineNumbering(SciNotesOptions.getSciNotesDisplay().showLineNumbers, SciNotesOptions.getSciNotesDisplay().whereami);
1962                 if (sep.getOtherPaneInSplit() != null) {
1963                     sep.getOtherPaneInSplit().getXln().setWhereamiLineNumbering(SciNotesOptions.getSciNotesDisplay().showLineNumbers, SciNotesOptions.getSciNotesDisplay().whereami);
1964                 }
1965             }
1966             ed.repaint();
1967         }
1968     }
1969
1970     /**
1971      * Auto-indent mode management
1972      *
1973      * @param b
1974      *            true to activate auto-indent mode
1975      */
1976     public static void setAutoIndent() {
1977         for (SciNotes ed : scinotesList) {
1978             int n = ed.getTabPane().getTabCount();
1979             for (int i = 0; i < n; i++) {
1980                 ScilabEditorPane sep = ed.getTextPane(i);
1981                 ((ScilabDocument) sep.getDocument()).setAutoIndent(SciNotesOptions.getSciNotesDisplay().automaticIndent);
1982                 if (sep.getOtherPaneInSplit() != null) {
1983                     ((ScilabDocument) sep.getOtherPaneInSplit().getDocument()).setAutoIndent(SciNotesOptions.getSciNotesDisplay().automaticIndent);
1984                 }
1985             }
1986         }
1987     }
1988
1989     /**
1990      * Horizontal Wrap mode management
1991      *
1992      * @param b
1993      *            true to activate horizontal wrapping mode
1994      */
1995     public static void setHorizontalWrap() {
1996         if (SciNotesOptions.getSciNotesDisplay().wrapLines != mustWrapLines) {
1997             mustWrapLines = SciNotesOptions.getSciNotesDisplay().wrapLines;
1998             for (SciNotes ed : scinotesList) {
1999                 int n = ed.getTabPane().getTabCount();
2000                 for (int i = 0; i < n; i++) {
2001                     ScilabEditorPane sep = ed.getTextPane(i);
2002                     if (sep.getOtherPaneInSplit() == null) {
2003                         ScilabEditorPane pane = new ScilabEditorPane(editor);
2004                         ed.initPane(pane, !mustWrapLines);
2005                         sep.copyProps(pane);
2006                         pane.setDocument(sep.getDocument());
2007                         pane.setCaretPosition(sep.getCaretPosition());
2008                         pane.getXln().setWhereamiLineNumbering(SciNotesOptions.getSciNotesDisplay().showLineNumbers, SciNotesOptions.getSciNotesDisplay().whereami);
2009                         ed.tabPane.setComponentAt(i, pane.getEditorComponent());
2010                         SciNotes.activateHelpOnTyping(pane);
2011                         ed.initInputMap(pane);
2012                         if (((ScilabDocument) sep.getDocument()).getBinary()) {
2013                             pane.setBinary(true);
2014                         }
2015                         ed.getInfoBar().setText(pane.getInfoBarText());
2016                     }
2017                 }
2018             }
2019         }
2020     }
2021
2022     /**
2023      * Set a line numbering compatible with the whereami function
2024      * @param state 0 for nothing, 1 for normal and 2 for whereami
2025      */
2026
2027     /**
2028      * Enable the highlighted line in this editor
2029      *
2030      * @param b
2031      *            boolean
2032      */
2033     public static void enableHighlightedLine(boolean b) {
2034         for (SciNotes ed : scinotesList) {
2035             int n = ed.getTabPane().getTabCount();
2036             for (int i = 0; i < n; i++) {
2037                 ScilabEditorPane sep = ed.getTextPane(i);
2038                 sep.enableHighlightedLine(SciNotesOptions.getSciNotesDisplay().highlightCurrentLine);
2039                 if (sep.getOtherPaneInSplit() != null) {
2040                     sep.getOtherPaneInSplit().enableHighlightedLine(SciNotesOptions.getSciNotesDisplay().highlightCurrentLine);
2041                 }
2042             }
2043         }
2044     }
2045
2046     /**
2047      * Enable the help on typing in the current textPane
2048      *
2049      * @param pane
2050      *            the pane
2051      */
2052     public static void activateHelpOnTyping(ScilabEditorPane pane) {
2053         pane.activateHelpOnTyping();
2054     }
2055
2056     /**
2057      * Enable the help on typing in this editor
2058      */
2059     public static void activateHelpOnTyping() {
2060         for (SciNotes ed : scinotesList) {
2061             int n = ed.getTabPane().getTabCount();
2062             for (int i = 0; i < n; i++) {
2063                 ScilabEditorPane sep = ed.getTextPane(i);
2064                 sep.activateHelpOnTyping();
2065                 if (sep.getOtherPaneInSplit() != null) {
2066                     sep.getOtherPaneInSplit().activateHelpOnTyping();
2067                 }
2068             }
2069         }
2070     }
2071
2072     /**
2073      * Set the color of the highlighted line in this editor
2074      *
2075      * @param c
2076      *            Color
2077      */
2078     public static void setDefaultTabulation() {
2079         TabManager.Tabulation tab = new TabManager.Tabulation();
2080         for (SciNotes ed : scinotesList) {
2081             int n = ed.getTabPane().getTabCount();
2082             for (int i = 0; i < n; i++) {
2083                 ScilabEditorPane sep = ed.getTextPane(i);
2084                 sep.getTabManager().setTabulation(tab);
2085                 View view = ((ScilabDocument) sep.getDocument()).getView();
2086                 if (view != null) {
2087                     if (view instanceof ScilabView) {
2088                         ((ScilabView) view).setTabRepresentation(tab);
2089                         ((ScilabView) view).reinitialize();
2090                     } else {
2091                         ((ScilabPlainView) view).setTabRepresentation(tab);
2092                         ((ScilabPlainView) view).reinitialize();
2093                     }
2094                 }
2095             }
2096         }
2097     }
2098
2099     /**
2100      * Set the color of the highlighted line in this editor
2101      *
2102      * @param c
2103      *            Color
2104      */
2105     public static void updatePanes(SciNotesConfiguration.Conf conf) {
2106         for (SciNotes ed : scinotesList) {
2107             int n = ed.getTabPane().getTabCount();
2108             for (int i = 0; i < n; i++) {
2109                 ScilabEditorPane sep = ed.getTextPane(i);
2110                 sep.configurationChanged(conf);
2111                 if (sep.getOtherPaneInSplit() != null) {
2112                     sep.getOtherPaneInSplit().configurationChanged(conf);
2113                 }
2114                 sep.repaint();
2115             }
2116         }
2117     }
2118
2119     public static void updateFontSize(int inc) {
2120         Font baseFont = null;
2121         for (SciNotes ed : scinotesList) {
2122             int n = ed.getTabPane().getTabCount();
2123             for (int i = 0; i < n; i++) {
2124                 ScilabEditorPane sep = ed.getTextPane(i);
2125                 ((ScilabEditorKit) sep.getEditorKit()).getStylePreferences().changeBaseFontSize(inc);
2126                 if (baseFont == null) {
2127                     baseFont = ((ScilabEditorKit) sep.getEditorKit()).getStylePreferences().getBaseFont();
2128                 }
2129                 if (sep.getOtherPaneInSplit() != null) {
2130                     ((ScilabEditorKit) sep.getOtherPaneInSplit().getEditorKit()).getStylePreferences().changeBaseFontSize(n);
2131                     sep.getOtherPaneInSplit().resetFont();
2132                 }
2133                 sep.resetFont();
2134             }
2135         }
2136
2137         if (baseFont != null) {
2138             ScilabContext.saveFont(baseFont);
2139         }
2140     }
2141
2142     /**
2143      * Set the color of the highlighted line in this editor
2144      *
2145      * @param c
2146      *            Color
2147      */
2148     public static void setHighlightedLineColor() {
2149         for (SciNotes ed : scinotesList) {
2150             int n = ed.getTabPane().getTabCount();
2151             for (int i = 0; i < n; i++) {
2152                 ScilabEditorPane sep = ed.getTextPane(i);
2153                 sep.setHighlightedLineColor(SciNotesOptions.getSciNotesDisplay().currentLineColor);
2154                 if (sep.getOtherPaneInSplit() != null) {
2155                     sep.getOtherPaneInSplit().setHighlightedLineColor(SciNotesOptions.getSciNotesDisplay().currentLineColor);
2156                 }
2157             }
2158         }
2159     }
2160
2161     /**
2162      * Set the color of the contour of the highlighted line in this editor
2163      *
2164      * @param c
2165      *            Color
2166      */
2167     public static void setHighlightedContourColor() {
2168         for (SciNotes ed : scinotesList) {
2169             int n = ed.getTabPane().getTabCount();
2170             for (int i = 0; i < n; i++) {
2171                 ScilabEditorPane sep = ed.getTextPane(i);
2172                 sep.setHighlightedContourColor(null);
2173                 if (sep.getOtherPaneInSplit() != null) {
2174                     sep.getOtherPaneInSplit().setHighlightedContourColor(null);
2175                 }
2176             }
2177         }
2178     }
2179
2180     /**
2181      * Set the highlighted line in this textPane
2182      *
2183      * @param sep
2184      *            ScilabEditorPane
2185      */
2186     public static void setHighlight(ScilabEditorPane sep) {
2187         sep.enableHighlightedLine(SciNotesOptions.getSciNotesDisplay().highlightCurrentLine);
2188         sep.setHighlightedLineColor(SciNotesOptions.getSciNotesDisplay().currentLineColor);
2189         sep.setHighlightedContourColor(null);
2190     }
2191
2192     /**
2193      * Get SciNotes as a Tab.
2194      *
2195      * @return SciNotes instance
2196      * @see org.scilab.modules.gui.tab.Tab#getAsSimpleTab()
2197      */
2198     public SimpleTab getAsSimpleTab() {
2199         return this;
2200     }
2201
2202     /**
2203      * Get SciNotes parent Window.
2204      *
2205      * @return parent Window
2206      * @see org.scilab.modules.gui.tab.Tab#getParentWindow()
2207      */
2208     public SwingScilabWindow getParentWindow() {
2209         if (parentWindow == null) {
2210             return super.getParentWindow();
2211         }
2212         return parentWindow;
2213     }
2214
2215     /**
2216      * Get the UUID associated with the editor instance.
2217      *
2218      * @return unique identifier
2219      */
2220     public UUID getUUID() {
2221         return uuid;
2222     }
2223
2224     /**
2225      * Add a status bar to SciNotes.
2226      *
2227      * @param infoBarToAdd
2228      *            the status bar to be added
2229      * @see org.scilab.modules.gui.uielement.UIElement#addInfoBar(org.scilab.modules.gui.textbox.TextBox)
2230      */
2231     public void addInfoBar(TextBox infoBarToAdd) {
2232         setInfoBar(infoBarToAdd);
2233     }
2234
2235     /**
2236      * Add a menu bar to SciNotes.
2237      *
2238      * @param menuBarToAdd
2239      *            the menu bar to be added
2240      * @see org.scilab.modules.gui.uielement.UIElement#addMenuBar(org.scilab.modules.gui.menubar.MenuBar)
2241      */
2242     public void addMenuBar(MenuBar menuBarToAdd) {
2243         setMenuBar(menuBarToAdd);
2244     }
2245
2246     /**
2247      * Add a tool bar to SciNotes.
2248      *
2249      * @param toolBarToAdd
2250      *            the tool bar to be added
2251      * @see org.scilab.modules.gui.uielement.UIElement#addToolBar(org.scilab.modules.gui.toolbar.ToolBar)
2252      */
2253     public void addToolBar(ToolBar toolBarToAdd) {
2254         setToolBar(toolBarToAdd);
2255     }
2256
2257     /**
2258      * Get SciNotes main ScilabTabbedPane.
2259      *
2260      * @return SciNotes main ScilabTabbedPane
2261      */
2262     public ScilabTabbedPane getTabPane() {
2263         return tabPane;
2264     }
2265
2266     /**
2267      * Set SciNotes main ScilabTabbedPane.
2268      *
2269      * @param tabPane
2270      *            SciNotes main ScilabTabbedPane
2271      */
2272     public void setTabPane(ScilabTabbedPane tabPane) {
2273         this.tabPane = tabPane;
2274     }
2275
2276     /**
2277      * Load a file and add it at the end
2278      *
2279      * @param f
2280      *            the file to load
2281      */
2282     public void loadFile(File f) {
2283         loadFile(f, -1);
2284     }
2285
2286     /**
2287      * Load a file and add it at the index
2288      *
2289      * @param f
2290      *            the file to load
2291      * @param index
2292      *            the index where to put the file
2293      */
2294     public void loadFile(File f, int index) {
2295         ScilabDocument styleDocument = null;
2296         ScilabEditorPane theTextPane;
2297
2298         // File exist
2299         if (f.exists()) {
2300             if (!f.canRead()) {
2301                 ScilabModalDialog.show(this, SciNotesMessages.NOTREADABLE, SciNotesMessages.SCINOTES_ERROR, IconType.ERROR_ICON);
2302                 if (getTabPane().getTabCount() == 0) {
2303                     addEmptyTab();
2304                 }
2305                 return;
2306             }
2307
2308             getInfoBar().setText(SciNotesMessages.LOADING);
2309
2310             if (index != -1) {
2311                 theTextPane = addTab(f.getName(), index);
2312             } else {
2313                 theTextPane = addTab(f.getName());
2314             }
2315             styleDocument = (ScilabDocument) theTextPane.getDocument();
2316             styleDocument.disableUndoManager();
2317             theTextPane.setLastModified(f.lastModified());
2318
2319             try {
2320                 styleDocument.setUpdater(false);
2321                 boolean indentMode = styleDocument.getAutoIndent();
2322                 styleDocument.setAutoIndent(false);
2323                 try {
2324                     ((ScilabEditorKit) editorKit).read(this, f, styleDocument, 0);
2325                 } catch (BadLocationException e) {
2326                     e.printStackTrace();
2327                 }
2328                 styleDocument.setAutoIndent(indentMode);
2329                 styleDocument.setUpdater(true);
2330             } catch (IOException ioex) {
2331                 ioex.printStackTrace();
2332             }
2333
2334             theTextPane.setName(f.getAbsolutePath());
2335             getTabPane().setTitleAt(getTabPane().getSelectedIndex(), f.getName());
2336             setTitle(theTextPane.getTitle());
2337             styleDocument.setContentModified(false);
2338             styleDocument.enableUndoManager();
2339
2340             if (styleDocument.getBinary()) {
2341                 theTextPane.setBinary(true);
2342             }
2343
2344             if (!f.canWrite()) {
2345                 getTextPane().setReadOnly(true);
2346                 JOptionPane.showMessageDialog(SciNotes.this, SciNotesMessages.READONLY);
2347             }
2348
2349             getInfoBar().setText(theTextPane.getInfoBarText());
2350
2351             EncodingAction.updateEncodingMenu((ScilabDocument) getTextPane().getDocument());
2352
2353             firstOpen = false;
2354             ConfigManager.saveLastOpenedDirectory(f.getPath());
2355             ConfigSciNotesManager.saveToRecentOpenedFiles(f.getPath());
2356             ConfigSciNotesManager.saveToOpenFiles(f.getPath(), this, getTextPane());
2357
2358             // Empty the undo Manager
2359             UndoManager undo = ((ScilabDocument) getTextPane().getDocument()).getUndoManager();
2360             undo.discardAllEdits();
2361
2362             if (getTabPane().getTabCount() == 2) {
2363                 ScilabEditorPane pane = getTextPane(0);
2364                 if (pane != null && pane.getName() == null && !((ScilabDocument) pane.getDocument()).isContentModified()) {
2365                     closeTabAt(0);
2366                 }
2367             }
2368         }
2369     }
2370
2371     /**
2372      * Creates a file if it doesn't exist
2373      *
2374      * @param f
2375      *            the file to create
2376      */
2377     public void createNewFile(File f) {
2378         ScilabEditorPane theTextPane = addEmptyTab();
2379         ScilabDocument styleDocument = null;
2380         int choice = JOptionPane.showConfirmDialog(SciNotes.this, String.format(SciNotesMessages.FILE_DOESNT_EXIST, f.getName()), SCINOTES,
2381                      JOptionPane.YES_NO_OPTION);
2382         if (choice == 0) { // OK
2383             styleDocument = (ScilabDocument) theTextPane.getDocument();
2384             styleDocument.disableUndoManager();
2385
2386             BufferedWriter bw = null;
2387             OutputStreamWriter osw = null;
2388             FileOutputStream fos = null;
2389
2390             try {
2391                 fos = new FileOutputStream(f);
2392                 osw = new OutputStreamWriter(fos, styleDocument.getEncoding());
2393                 bw = new BufferedWriter(osw);
2394                 editorKit.write(bw, styleDocument, 0, styleDocument.getLength());
2395                 bw.flush();
2396             } catch (IOException e) {
2397                 System.err.println(e);
2398             } catch (BadLocationException e) {
2399                 System.err.println(e);
2400             } finally {
2401                 try {
2402                     if (fos != null) {
2403                         fos.close();
2404                     }
2405                     if (osw != null) {
2406                         osw.close();
2407                     }
2408                     if (bw != null) {
2409                         bw.close();
2410                     }
2411                 } catch (IOException e) {
2412                     System.err.println(e);
2413                 }
2414             }
2415
2416             firstOpen = false;
2417             ConfigManager.saveLastOpenedDirectory(f.getPath());
2418             ConfigSciNotesManager.saveToRecentOpenedFiles(f.getPath());
2419             ConfigSciNotesManager.saveToOpenFiles(theTextPane.getName(), this, theTextPane);
2420
2421             theTextPane.setName(f.getPath());
2422             getTabPane().setTitleAt(getTabPane().getSelectedIndex(), f.getName());
2423             setTitle(theTextPane.getTitle());
2424             RecentFileAction.updateRecentOpenedFilesMenu(this);
2425
2426             styleDocument.setContentModified(false);
2427             styleDocument.enableUndoManager();
2428             theTextPane.setLastModified(f.lastModified());
2429         }
2430
2431         getInfoBar().setText("");
2432     }
2433
2434     /**
2435      * EditorKit Getter
2436      *
2437      * @return EditorKit
2438      */
2439     public EditorKit getEditorKit() {
2440         return editorKit;
2441     }
2442
2443     /**
2444      * @param scinotes
2445      *            the focused editor
2446      */
2447     public static void setEditor(SciNotes scinotes) {
2448         editor = scinotes;
2449     }
2450
2451     /**
2452      * @return the focused editor
2453      */
2454     public static SciNotes getEditor() {
2455         return editor;
2456     }
2457
2458     /**
2459      * EditorKit Setter
2460      *
2461      * @param editorKit
2462      *            EditorKit
2463      */
2464     public void setEditorKit(EditorKit editorKit) {
2465         this.editorKit = editorKit;
2466     }
2467
2468     /**
2469      * Close scinotes from scilab.
2470      *
2471      * This method can be called outside the EDT thread.
2472      */
2473     public static void closeSciNotesFromScilab() {
2474         try {
2475             SwingUtilities.invokeAndWait(new Runnable() {
2476
2477                 @Override
2478                 public void run() {
2479                     SciNotes[] arr = scinotesList.toArray(new SciNotes[0]);
2480                     for (int i = 0; i < arr.length; i++) {
2481                         arr[i].setProtectOpenFileList(true);
2482                         ExitAction.doExit(arr[i]);
2483                     }
2484                     scinotesList.clear();
2485                 }
2486             });
2487         } catch (InterruptedException e) {
2488             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
2489         } catch (InvocationTargetException e) {
2490             Logger.getLogger(SciNotes.class.getName()).severe(e.toString());
2491         }
2492     }
2493
2494     /**
2495      * @param f
2496      *            the file
2497      * @return the canonical file if possible
2498      */
2499     public static File fileToCanonicalFile(File f) {
2500         /* Fix bug 5648 */
2501         try {
2502             return f.getCanonicalFile();
2503         } catch (IOException e) {
2504             return f;
2505         }
2506     }
2507
2508     /**
2509      * Set the shortcuts in the pane relatively to the file
2510      * keysConfiguration.xml
2511      *
2512      * @param sep
2513      *            the textpane
2514      * @param ed
2515      *            the SciNotes editor
2516      */
2517     private static void setKeyStrokeAction(ScilabEditorPane sep, SciNotes ed) {
2518         ScilabEditorPane s = ed.getTextPane(0);
2519         if (s != null && s != sep) {
2520             sep.setInputMap(JComponent.WHEN_FOCUSED, s.getInputMap());
2521             return;
2522         }
2523
2524         Map<String, KeyStroke> map = getActionKeys();
2525         ClassLoader loader = ClassLoader.getSystemClassLoader();
2526
2527         for (Map.Entry<String, KeyStroke> entry : map.entrySet()) {
2528             String actionName = entry.getKey();
2529             KeyStroke key = entry.getValue();
2530             String action = actionToName.get(actionName);
2531             if (key != null) {
2532                 if (!action.equals("SciNotesCompletionAction")) {
2533                     String className;
2534                     if (action.lastIndexOf(DOT) != -1) {
2535                         className = action;
2536                     } else {
2537                         className = DEFAULTACTIONPATH + DOT + action;
2538                     }
2539                     try {
2540                         Class clazz = loader.loadClass(className);
2541                         Constructor constructor = clazz.getConstructor(new Class[] { String.class, SciNotes.class });
2542                         Object act = constructor.newInstance(new Object[] { "", ed });
2543                         sep.getInputMap().put(key, act);
2544                     } catch (ClassNotFoundException e) {
2545                         System.err.println("No action: " + className);
2546                     } catch (InstantiationException e) {
2547                         System.err.println("Problem to instantiate in action: " + className);
2548                     } catch (NoSuchMethodException e) {
2549                         System.err.println("No valid constructor in action: " + className);
2550                     } catch (IllegalAccessException e) {
2551                         System.err.println("The constructor must be public: " + className);
2552                     } catch (InvocationTargetException e) {
2553                         System.err.println("The constructor in " + className + " threw an exception :");
2554                         e.printStackTrace();
2555                     }
2556                 } else {
2557                     sep.getInputMap().put(key, new SciNotesCompletionAction(sep, ed));
2558                 }
2559             }
2560         }
2561
2562         // Add default common shortcuts
2563         sep.getInputMap().put(KeyStroke.getKeyStroke("shift DELETE"), sep.getInputMap().get(map.get("scinotes-cut")));
2564         sep.getInputMap().put(KeyStroke.getKeyStroke("CUT"), sep.getInputMap().get(map.get("scinotes-cut")));
2565         sep.getInputMap().put(ScilabKeyStroke.getKeyStroke("OSSCKEY INSERT"), sep.getInputMap().get(map.get("scinotes-copy")));
2566         sep.getInputMap().put(KeyStroke.getKeyStroke("COPY"), sep.getInputMap().get(map.get("scinotes-copy")));
2567         sep.getInputMap().put(KeyStroke.getKeyStroke("shift INSERT"), sep.getInputMap().get(map.get("scinotes-paste")));
2568         sep.getInputMap().put(KeyStroke.getKeyStroke("PASTE"), sep.getInputMap().get(map.get("scinotes-paste")));
2569     }
2570
2571     /**
2572      * Execute an action on file
2573      * @param fileName the name of the file
2574      * @param action the action
2575      */
2576     public static void executeAction(String fileName, ActionOnDocument action) throws IOException {
2577         Charset charset = null;
2578         try {
2579             charset = ScilabEditorKit.tryToGuessEncoding(new File(fileName));
2580         } catch (CharacterCodingException e) {
2581             throw new IOException(SciNotesMessages.CANNOT_GUESS_ENCODING + ": " + fileName);
2582         }
2583         FileInputStream fis = new FileInputStream(fileName);
2584         InputStreamReader isr = new InputStreamReader(fis, charset);
2585         BufferedReader reader = new BufferedReader(isr);
2586         ScilabDocument doc = new ScilabDocument();
2587         ScilabEditorKit kit = new ScilabEditorKit();
2588         try {
2589             kit.read(reader, doc, 0);
2590         } catch (BadLocationException e) {
2591             System.err.println(e);
2592         }
2593
2594         doc.addDocumentListener(doc);
2595         if (!doc.getBinary()) {
2596             action.actionOn(doc);
2597         }
2598
2599         reader.close();
2600         if (doc.isContentModified()) {
2601             SaveFile.doSave(doc, new File(fileName), kit);
2602         }
2603     }
2604
2605     /**
2606      * Execute an action on file
2607      * @param fileName the name of the file
2608      * @param actionsName the actions as an array
2609      */
2610     public static boolean executeAction(String fileName, final String[] actionsName) throws IOException {
2611         final boolean[] hasAction = new boolean[] { false };
2612         ActionOnDocument action = new ActionOnDocument() {
2613             public void actionOn(ScilabDocument doc) throws IOException {
2614                 for (String act : actionsName) {
2615                     if (act.equalsIgnoreCase("indent")) {
2616                         hasAction[0] = true;
2617                         org.scilab.modules.scinotes.actions.IndentAction.getActionOnDocument().actionOn(doc);
2618                     } else if (act.equalsIgnoreCase("trailing")) {
2619                         hasAction[0] = true;
2620                         org.scilab.modules.scinotes.actions.RemoveTrailingWhiteAction.getActionOnDocument().actionOn(doc);
2621                     } else if (act.equalsIgnoreCase("quote")) {
2622                         hasAction[0] = true;
2623                         org.scilab.modules.scinotes.actions.DoubleQuoteStringAction.getActionOnDocument().actionOn(doc);
2624                     }
2625                 }
2626             }
2627         };
2628
2629         executeAction(fileName, action);
2630
2631         return hasAction[0];
2632     }
2633
2634     /**
2635      * Execute an action on file
2636      * @param fileName the name of the file
2637      * @param acts actions separated with , or ;
2638      */
2639     public static void executeAction(String fileName, String acts) throws IOException {
2640         StringTokenizer toks = new StringTokenizer(acts, ",;");
2641         String[] actions = new String[toks.countTokens()];
2642         for (int i = 0; i < actions.length; i++) {
2643             actions[i] = toks.nextToken();
2644         }
2645         executeAction(fileName, actions);
2646     }
2647
2648     /**
2649      * An interface to implement to execute an action on a document
2650      */
2651     public static interface ActionOnDocument {
2652
2653         public void actionOn(ScilabDocument doc) throws IOException;
2654     }
2655 }