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