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