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