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