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