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