summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCalixte DENIZET <calixte@contrib.scilab.org>2011-04-14 14:34:50 +0200
committerVincent COUVERT <vincent.couvert@scilab.org>2011-05-06 13:20:37 +0200
commit4e37a6fde8b9af45e3cbeb86a41b9cbcd277959e (patch)
tree0606f1b8388722823ee922a947b583d89571df07
parentfd6848aa7dd9604b78cb0eae520bc021292ebf1a (diff)
downloadscilab-4e37a6fde8b9af45e3cbeb86a41b9cbcd277959e.zip
scilab-4e37a6fde8b9af45e3cbeb86a41b9cbcd277959e.tar.gz
Wishes 7720,7721 fullfilled: Add a kind of find/grep in SciNotes
Cherry-pick for version 5.3.2 Change-Id: I06eb5753a0ff2018555b803e1ea877a494302be5 Change-Id: Ib00a3806d4bf070a23949a211ccfd92994dc99ac
-rw-r--r--scilab/CHANGES_5.3.X2
-rw-r--r--scilab/modules/gui/Makefile.am5
-rw-r--r--scilab/modules/gui/Makefile.in5
-rw-r--r--scilab/modules/gui/images/icons/16x16/search/file.pngbin0 -> 617 bytes
-rw-r--r--scilab/modules/gui/images/icons/16x16/search/folder.pngbin0 -> 711 bytes
-rw-r--r--scilab/modules/gui/images/icons/16x16/search/line-found.pngbin0 -> 484 bytes
-rw-r--r--scilab/modules/gui/images/icons/16x16/search/scilab-file.pngbin0 -> 710 bytes
-rw-r--r--scilab/modules/gui/images/icons/32x32/apps/system-search.pngbin0 -> 2215 bytes
-rw-r--r--scilab/modules/scinotes/etc/keysConfiguration.xml2
-rw-r--r--scilab/modules/scinotes/etc/scinotesConfiguration.xml2
-rw-r--r--scilab/modules/scinotes/etc/scinotesGUIConfiguration.xml3
-rw-r--r--scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/SciNotes.java12
-rw-r--r--scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/ScilabEditorPane.java144
-rw-r--r--scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/SearchManager.java572
-rw-r--r--scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/FindAction.java26
-rw-r--r--scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/SearchFilesAction.java46
-rw-r--r--scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/SearchWordInFilesAction.java637
-rw-r--r--scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/ConfigSciNotesManager.java149
-rw-r--r--scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/SciNotesMessages.java26
-rw-r--r--scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/SearchFile.java515
20 files changed, 2113 insertions, 33 deletions
diff --git a/scilab/CHANGES_5.3.X b/scilab/CHANGES_5.3.X
index e1f498f..13e0cb1 100644
--- a/scilab/CHANGES_5.3.X
+++ b/scilab/CHANGES_5.3.X
@@ -16,6 +16,8 @@ Scinotes:
16 16
17* Add the possibility to replace single quoted by double quoted strings. 17* Add the possibility to replace single quoted by double quoted strings.
18 18
19* Add tools 'Find Files' (ctrl+shift+B) and 'Find word in Files' (ctrl+shift+F).
20
19* Add the possibility to save and execute the code with F5 key. 21* Add the possibility to save and execute the code with F5 key.
20 22
21* Add the possibility to remove the comments when executing the code in the 23* Add the possibility to remove the comments when executing the code in the
diff --git a/scilab/modules/gui/Makefile.am b/scilab/modules/gui/Makefile.am
index 37db037..7d2f251 100644
--- a/scilab/modules/gui/Makefile.am
+++ b/scilab/modules/gui/Makefile.am
@@ -289,10 +289,15 @@ libscigui_la_iconsdir=$(mydatadir)/
289nobase_libscigui_la_icons_DATA = images/icons/32x32/apps/accessories-text-editor.png \ 289nobase_libscigui_la_icons_DATA = images/icons/32x32/apps/accessories-text-editor.png \
290images/icons/32x32/apps/rrze_table.png \ 290images/icons/32x32/apps/rrze_table.png \
291images/icons/32x32/apps/utilities-system-monitor.png \ 291images/icons/32x32/apps/utilities-system-monitor.png \
292images/icons/32x32/apps/system-search.png \
292images/icons/16x16/actions/go-bottom.png \ 293images/icons/16x16/actions/go-bottom.png \
293images/icons/16x16/actions/go-top.png \ 294images/icons/16x16/actions/go-top.png \
294images/icons/16x16/actions/view-refresh.png \ 295images/icons/16x16/actions/view-refresh.png \
295images/icons/16x16/actions/save-and-execute.png \ 296images/icons/16x16/actions/save-and-execute.png \
297images/icons/16x16/search/folder.png \
298images/icons/16x16/search/file.png \
299images/icons/16x16/search/line-found.png \
300images/icons/16x16/search/scilab-file.png \
296images/icons/aboutscilab.png \ 301images/icons/aboutscilab.png \
297images/icons/accessories-text-editor.png \ 302images/icons/accessories-text-editor.png \
298images/icons/applications-system.png \ 303images/icons/applications-system.png \
diff --git a/scilab/modules/gui/Makefile.in b/scilab/modules/gui/Makefile.in
index 323103d..fd262b7 100644
--- a/scilab/modules/gui/Makefile.in
+++ b/scilab/modules/gui/Makefile.in
@@ -841,10 +841,15 @@ libscigui_la_iconsdir = $(mydatadir)/
841nobase_libscigui_la_icons_DATA = images/icons/32x32/apps/accessories-text-editor.png \ 841nobase_libscigui_la_icons_DATA = images/icons/32x32/apps/accessories-text-editor.png \
842images/icons/32x32/apps/rrze_table.png \ 842images/icons/32x32/apps/rrze_table.png \
843images/icons/32x32/apps/utilities-system-monitor.png \ 843images/icons/32x32/apps/utilities-system-monitor.png \
844images/icons/32x32/apps/system-search.png \
844images/icons/16x16/actions/go-bottom.png \ 845images/icons/16x16/actions/go-bottom.png \
845images/icons/16x16/actions/go-top.png \ 846images/icons/16x16/actions/go-top.png \
846images/icons/16x16/actions/view-refresh.png \ 847images/icons/16x16/actions/view-refresh.png \
847images/icons/16x16/actions/save-and-execute.png \ 848images/icons/16x16/actions/save-and-execute.png \
849images/icons/16x16/search/folder.png \
850images/icons/16x16/search/file.png \
851images/icons/16x16/search/line-found.png \
852images/icons/16x16/search/scilab-file.png \
848images/icons/aboutscilab.png \ 853images/icons/aboutscilab.png \
849images/icons/accessories-text-editor.png \ 854images/icons/accessories-text-editor.png \
850images/icons/applications-system.png \ 855images/icons/applications-system.png \
diff --git a/scilab/modules/gui/images/icons/16x16/search/file.png b/scilab/modules/gui/images/icons/16x16/search/file.png
new file mode 100644
index 0000000..d072d3cb
--- /dev/null
+++ b/scilab/modules/gui/images/icons/16x16/search/file.png
Binary files differ
diff --git a/scilab/modules/gui/images/icons/16x16/search/folder.png b/scilab/modules/gui/images/icons/16x16/search/folder.png
new file mode 100644
index 0000000..ca24a36
--- /dev/null
+++ b/scilab/modules/gui/images/icons/16x16/search/folder.png
Binary files differ
diff --git a/scilab/modules/gui/images/icons/16x16/search/line-found.png b/scilab/modules/gui/images/icons/16x16/search/line-found.png
new file mode 100644
index 0000000..46b3407
--- /dev/null
+++ b/scilab/modules/gui/images/icons/16x16/search/line-found.png
Binary files differ
diff --git a/scilab/modules/gui/images/icons/16x16/search/scilab-file.png b/scilab/modules/gui/images/icons/16x16/search/scilab-file.png
new file mode 100644
index 0000000..5c82600
--- /dev/null
+++ b/scilab/modules/gui/images/icons/16x16/search/scilab-file.png
Binary files differ
diff --git a/scilab/modules/gui/images/icons/32x32/apps/system-search.png b/scilab/modules/gui/images/icons/32x32/apps/system-search.png
new file mode 100644
index 0000000..950d792
--- /dev/null
+++ b/scilab/modules/gui/images/icons/32x32/apps/system-search.png
Binary files differ
diff --git a/scilab/modules/scinotes/etc/keysConfiguration.xml b/scilab/modules/scinotes/etc/keysConfiguration.xml
index 3acc0b0..00a1203 100644
--- a/scilab/modules/scinotes/etc/keysConfiguration.xml
+++ b/scilab/modules/scinotes/etc/keysConfiguration.xml
@@ -61,6 +61,8 @@
61 <entry key="GotoNextAnchorAction">OSSCKEY shift LESS</entry> 61 <entry key="GotoNextAnchorAction">OSSCKEY shift LESS</entry>
62 <entry key="GotoPreviousAnchorAction">OSSCKEY LESS</entry> 62 <entry key="GotoPreviousAnchorAction">OSSCKEY LESS</entry>
63 <entry key="CodeNavigatorAction">OSSCKEY G</entry> 63 <entry key="CodeNavigatorAction">OSSCKEY G</entry>
64 <entry key="SearchWordInFilesAction">OSSCKEY shift F</entry>
65 <entry key="SearchFilesAction">OSSCKEY shift B</entry>
64 66
65 <entry key="SciNotesCompletionAction">OSSCKEY SPACE</entry> 67 <entry key="SciNotesCompletionAction">OSSCKEY SPACE</entry>
66 68
diff --git a/scilab/modules/scinotes/etc/scinotesConfiguration.xml b/scilab/modules/scinotes/etc/scinotesConfiguration.xml
index d2cbd00..8f46153 100644
--- a/scilab/modules/scinotes/etc/scinotesConfiguration.xml
+++ b/scilab/modules/scinotes/etc/scinotesConfiguration.xml
@@ -12,7 +12,7 @@
12 * 12 *
13 --> 13 -->
14 14
15<Setting version="0.35"> 15<Setting version="0.36">
16 16
17 <!-- SCINOTES configuration --> 17 <!-- SCINOTES configuration -->
18 <Profile name="scinotes"> 18 <Profile name="scinotes">
diff --git a/scilab/modules/scinotes/etc/scinotesGUIConfiguration.xml b/scilab/modules/scinotes/etc/scinotesGUIConfiguration.xml
index 18d3c50..d152b47 100644
--- a/scilab/modules/scinotes/etc/scinotesGUIConfiguration.xml
+++ b/scilab/modules/scinotes/etc/scinotesGUIConfiguration.xml
@@ -74,6 +74,9 @@
74 <menuitem action="FindPreviousAction" label="Find Previous"/> 74 <menuitem action="FindPreviousAction" label="Find Previous"/>
75 <menuitem action="IncrementalSearchAction" label="Incremental Search"/> 75 <menuitem action="IncrementalSearchAction" label="Incremental Search"/>
76 <separator/> 76 <separator/>
77 <menuitem action="SearchWordInFilesAction" label="Find word in files"/>
78 <menuitem action="SearchFilesAction" label="Find files"/>
79 <separator/>
77 <menuitem action="SetAnchorAction" label="Set anchor"/> 80 <menuitem action="SetAnchorAction" label="Set anchor"/>
78 <menuitem action="RemoveAnchorAction" label="Remove anchor"/> 81 <menuitem action="RemoveAnchorAction" label="Remove anchor"/>
79 <menuitem action="GotoNextAnchorAction" label="Go to next anchor"/> 82 <menuitem action="GotoNextAnchorAction" label="Go to next anchor"/>
diff --git a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/SciNotes.java b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/SciNotes.java
index 58806457..eb30805 100644
--- a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/SciNotes.java
+++ b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/SciNotes.java
@@ -87,9 +87,11 @@ import org.scilab.modules.scinotes.actions.RecentFileAction;
87import org.scilab.modules.scinotes.actions.RestoreOpenedFilesAction; 87import org.scilab.modules.scinotes.actions.RestoreOpenedFilesAction;
88import org.scilab.modules.scinotes.actions.SciNotesCompletionAction; 88import org.scilab.modules.scinotes.actions.SciNotesCompletionAction;
89import org.scilab.modules.scinotes.actions.SetColorsAction; 89import org.scilab.modules.scinotes.actions.SetColorsAction;
90import org.scilab.modules.scinotes.actions.SearchWordInFilesAction;
90import org.scilab.modules.scinotes.utils.ConfigSciNotesManager; 91import org.scilab.modules.scinotes.utils.ConfigSciNotesManager;
91import org.scilab.modules.scinotes.utils.DropFilesListener; 92import org.scilab.modules.scinotes.utils.DropFilesListener;
92import org.scilab.modules.scinotes.utils.NavigatorWindow; 93import org.scilab.modules.scinotes.utils.NavigatorWindow;
94import org.scilab.modules.scinotes.utils.SearchFile;
93import org.scilab.modules.scinotes.utils.SaveFile; 95import org.scilab.modules.scinotes.utils.SaveFile;
94import org.scilab.modules.scinotes.utils.ScilabTabbedPane; 96import org.scilab.modules.scinotes.utils.ScilabTabbedPane;
95import org.scilab.modules.scinotes.utils.SciNotesContents; 97import org.scilab.modules.scinotes.utils.SciNotesContents;
@@ -202,6 +204,13 @@ public class SciNotes extends SwingScilabTab implements Tab {
202 } 204 }
203 205
204 /** 206 /**
207 * @return the SwingScilabWindow containing this editor
208 */
209 public SwingScilabWindow getSwingParentWindow() {
210 return (SwingScilabWindow) SwingUtilities.getAncestorOfClass(SwingScilabWindow.class, this);
211 }
212
213 /**
205 * Launch SciNotes from command line. 214 * Launch SciNotes from command line.
206 * @param args command line args 215 * @param args command line args
207 */ 216 */
@@ -464,6 +473,7 @@ public class SciNotes extends SwingScilabTab implements Tab {
464 SetColorsAction.closeSetColorsWindow(); 473 SetColorsAction.closeSetColorsWindow();
465 OpenSourceFileOnKeywordAction.closeOpenSourceWindow(); 474 OpenSourceFileOnKeywordAction.closeOpenSourceWindow();
466 ConfigTabulationsAction.closeConfTabWindow(); 475 ConfigTabulationsAction.closeConfTabWindow();
476 SearchWordInFilesAction.closeWindow();
467 477
468 while (getTabPane().getTabCount() > 0) { 478 while (getTabPane().getTabCount() > 0) {
469 closeTabAt(0, true); 479 closeTabAt(0, true);
@@ -471,6 +481,7 @@ public class SciNotes extends SwingScilabTab implements Tab {
471 scinotesList.remove(this); 481 scinotesList.remove(this);
472 if (scinotesList.size() == 0) { 482 if (scinotesList.size() == 0) {
473 NavigatorWindow.closeCurrent(); 483 NavigatorWindow.closeCurrent();
484 SearchFile.closeCurrent();
474 } 485 }
475 editor = null; 486 editor = null;
476 SwingScilabWindow window = (SwingScilabWindow) parentWindow.getAsSimpleWindow(); 487 SwingScilabWindow window = (SwingScilabWindow) parentWindow.getAsSimpleWindow();
@@ -1818,6 +1829,7 @@ public class SciNotes extends SwingScilabTab implements Tab {
1818 } 1829 }
1819 scinotesList.clear(); 1830 scinotesList.clear();
1820 NavigatorWindow.closeCurrent(); 1831 NavigatorWindow.closeCurrent();
1832 SearchFile.closeCurrent();
1821 } 1833 }
1822 }); 1834 });
1823 } catch (InterruptedException e) { 1835 } catch (InterruptedException e) {
diff --git a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/ScilabEditorPane.java b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/ScilabEditorPane.java
index cc37d14..e438efd 100644
--- a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/ScilabEditorPane.java
+++ b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/ScilabEditorPane.java
@@ -31,6 +31,8 @@ import java.util.ArrayList;
31import java.util.EventObject; 31import java.util.EventObject;
32import java.util.List; 32import java.util.List;
33import java.util.UUID; 33import java.util.UUID;
34import java.util.regex.Matcher;
35import java.util.regex.Pattern;
34 36
35import javax.swing.JEditorPane; 37import javax.swing.JEditorPane;
36import javax.swing.JScrollBar; 38import javax.swing.JScrollBar;
@@ -635,15 +637,39 @@ public class ScilabEditorPane extends JEditorPane implements Highlighter.Highlig
635 * @param pos the position in the document 637 * @param pos the position in the document
636 */ 638 */
637 public void scrollTextToPos(int pos) { 639 public void scrollTextToPos(int pos) {
638 try { 640 scrollTextToPos(pos, true, false);
639 setCaretPosition(pos); 641 }
640 JScrollBar scrollbar = edComponent.getScrollPane().getVerticalScrollBar(); 642
641 int value = modelToView(pos).y; 643 /**
642 if (modelToView(pos).y > scrollbar.getMaximum()) { 644 * Scroll the pane to have the line containing pos on the top or centered on the pane
643 scrollbar.setMaximum(value); 645 * @param pos the position in the document
644 } 646 * @param setCaret, if true the caret is set at the given position
645 scrollbar.setValue(value); 647 * @param centered, if true the line is centered
646 } catch (BadLocationException e) { } 648 */
649 public void scrollTextToPos(final int pos, final boolean setCaret, final boolean centered) {
650 SwingUtilities.invokeLater(new Runnable() {
651 public void run() {
652 try {
653 if (setCaret) {
654 setCaretPosition(pos);
655 }
656 JScrollBar scrollbar = edComponent.getScrollPane().getVerticalScrollBar();
657 Rectangle rect = modelToView(pos);
658 if (centered) {
659 int value = scrollbar.getValue();
660 int h = scrollbar.getHeight();
661 if (rect.y < value || rect.y > value + h) {
662 scrollbar.setValue(Math.max(0, rect.y - h / 2));
663 }
664 } else {
665 if (rect.y > scrollbar.getMaximum()) {
666 scrollbar.setMaximum(rect.y);
667 }
668 scrollbar.setValue(rect.y);
669 }
670 } catch (BadLocationException e) { }
671 }
672 });
647 } 673 }
648 674
649 /** 675 /**
@@ -651,13 +677,24 @@ public class ScilabEditorPane extends JEditorPane implements Highlighter.Highlig
651 * @param lineNumber the number of the line 677 * @param lineNumber the number of the line
652 * @param highlight true to highlight the line 678 * @param highlight true to highlight the line
653 */ 679 */
654 public void scrollTextToLineNumber(int lineNumber, final boolean highlight) { 680 public void scrollTextToLineNumber(int lineNumber, boolean highlight) {
681 scrollTextToLineNumber(lineNumber, highlight, true, false);
682 }
683
684 /**
685 * Scroll the pane to have the line lineNumber on the top or centered on the pane
686 * @param lineNumber the number of the line
687 * @param highlight true to highlight the line
688 * @param setCaret, if true the caret is set at the given line
689 * @param centered, if true the line is centered
690 */
691 public void scrollTextToLineNumber(int lineNumber, final boolean highlight, final boolean setCaret, final boolean centered) {
655 Element root = getDocument().getDefaultRootElement(); 692 Element root = getDocument().getDefaultRootElement();
656 if (lineNumber >= 1 && lineNumber <= root.getElementCount()) { 693 if (lineNumber >= 1 && lineNumber <= root.getElementCount()) {
657 final int pos = root.getElement(lineNumber - 1).getStartOffset(); 694 final int pos = root.getElement(lineNumber - 1).getStartOffset();
658 SwingUtilities.invokeLater(new Runnable() { 695 SwingUtilities.invokeLater(new Runnable() {
659 public void run() { 696 public void run() {
660 scrollTextToPos(pos); 697 scrollTextToPos(pos, setCaret, centered);
661 if (highlight) { 698 if (highlight) {
662 saveHighlightContourColor = highlightContourColor; 699 saveHighlightContourColor = highlightContourColor;
663 highlightContourColor = null; 700 highlightContourColor = null;
@@ -681,6 +718,19 @@ public class ScilabEditorPane extends JEditorPane implements Highlighter.Highlig
681 * @param highlight true to highlight the line 718 * @param highlight true to highlight the line
682 */ 719 */
683 public void scrollTextToLineNumberInWhereami(int lineNumber, String funname, boolean highlight) { 720 public void scrollTextToLineNumberInWhereami(int lineNumber, String funname, boolean highlight) {
721 scrollTextToLineNumberInWhereami(lineNumber, funname, highlight, true, false);
722 }
723
724 /**
725 * Scroll the pane to have the line lineNumber on the top of the pane in whereami mode
726 * The line number is computed regarding the function named funname.
727 * @param lineNumber the number of the line
728 * @param funname the function name
729 * @param highlight true to highlight the line
730 * @param setCaret, if true the caret is set at the given line
731 * @param centered, if true the line is centered
732 */
733 public void scrollTextToLineNumberInWhereami(int lineNumber, String funname, boolean highlight, boolean setCaret, boolean centered) {
684 if (funname != null) { 734 if (funname != null) {
685 Element root = getDocument().getDefaultRootElement(); 735 Element root = getDocument().getDefaultRootElement();
686 int nlines = root.getElementCount(); 736 int nlines = root.getElementCount();
@@ -693,7 +743,7 @@ public class ScilabEditorPane extends JEditorPane implements Highlighter.Highlig
693 } 743 }
694 } 744 }
695 } 745 }
696 scrollTextToLineNumber(lineNumber, highlight); 746 scrollTextToLineNumber(lineNumber, highlight, setCaret, centered);
697 } 747 }
698 748
699 /** 749 /**
@@ -1247,19 +1297,6 @@ public class ScilabEditorPane extends JEditorPane implements Highlighter.Highlig
1247 } 1297 }
1248 1298
1249 /** 1299 /**
1250 * Remove the highlight putted to show the line (for editor('foo',123))
1251 */
1252 private void removeHighlightForLine() {
1253 highlightContourColor = saveHighlightContourColor;
1254 highlightColor = saveHighlightColor;
1255 enableHighlightedLine(false);
1256 if (saveHighlightEnable) {
1257 enableHighlightedLine(true);
1258 }
1259 hasBeenSaved = false;
1260 }
1261
1262 /**
1263 * {@inheritDoc} 1300 * {@inheritDoc}
1264 */ 1301 */
1265 public void setCaret(Caret c) { 1302 public void setCaret(Caret c) {
@@ -1284,11 +1321,31 @@ public class ScilabEditorPane extends JEditorPane implements Highlighter.Highlig
1284 } 1321 }
1285 } 1322 }
1286 1323
1324 /**
1325 * {@inheritDoc}
1326 */
1287 public void select(int start, int end) { 1327 public void select(int start, int end) {
1288 removeHighlightOnPosition(start); 1328 removeHighlightOnPosition(start);
1289 super.select(start, end); 1329 super.select(start, end);
1290 } 1330 }
1291 1331
1332 /**
1333 * Remove the highlight putted to show the line (for editor('foo',123))
1334 */
1335 private void removeHighlightForLine() {
1336 highlightContourColor = saveHighlightContourColor;
1337 highlightColor = saveHighlightColor;
1338 enableHighlightedLine(false);
1339 if (saveHighlightEnable) {
1340 enableHighlightedLine(true);
1341 }
1342 hasBeenSaved = false;
1343 }
1344
1345 /**
1346 * Remove the highlight at position start
1347 * @param start the beginning of the highlight
1348 */
1292 public void removeHighlightOnPosition(int start) { 1349 public void removeHighlightOnPosition(int start) {
1293 int pos = highlightedWordsBegin.indexOf(start); 1350 int pos = highlightedWordsBegin.indexOf(start);
1294 if (pos != -1) { 1351 if (pos != -1) {
@@ -1297,6 +1354,11 @@ public class ScilabEditorPane extends JEditorPane implements Highlighter.Highlig
1297 } 1354 }
1298 } 1355 }
1299 1356
1357 /**
1358 * Highlight a word in this textpane.
1359 * @param word the word to highlight
1360 * @param exact if true the search is case sensitive
1361 */
1300 public void highlightWords(String word, boolean exact) { 1362 public void highlightWords(String word, boolean exact) {
1301 removeHighlightedWords(); 1363 removeHighlightedWords();
1302 if (word != null && word.length() != 0) { 1364 if (word != null && word.length() != 0) {
@@ -1319,6 +1381,38 @@ public class ScilabEditorPane extends JEditorPane implements Highlighter.Highlig
1319 } 1381 }
1320 } 1382 }
1321 1383
1384 /**
1385 * Highlight a word according to a pattern in this textpane.
1386 * @param pattern the pattern to highlight
1387 * @param centered, if true the pane is centered on the first occurence
1388 */
1389 public void highlightWords(Pattern pattern, boolean centered) {
1390 if (pattern != null) {
1391 removeHighlightedWords();
1392 int first = -1;
1393 String text = getText();
1394 Matcher matcher = pattern.matcher(text);
1395
1396 Highlighter highlighter = getHighlighter();
1397 while (matcher.find()) {
1398 if (first == -1) {
1399 first = matcher.start();
1400 }
1401 try {
1402 highlightedWords.add(highlighter.addHighlight(matcher.start(), matcher.end(), HIGHLIGHTER));
1403 highlightedWordsBegin.add(matcher.start());
1404 } catch (BadLocationException e) { }
1405 }
1406
1407 if (centered && first != -1) {
1408 scrollTextToPos(first, false, true);
1409 }
1410 }
1411 }
1412
1413 /**
1414 * Remove all the highlighted words
1415 */
1322 public void removeHighlightedWords() { 1416 public void removeHighlightedWords() {
1323 Highlighter highlighter = getHighlighter(); 1417 Highlighter highlighter = getHighlighter();
1324 for (Object obj : highlightedWords) { 1418 for (Object obj : highlightedWords) {
diff --git a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/SearchManager.java b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/SearchManager.java
index 33f0440..8944769 100644
--- a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/SearchManager.java
+++ b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/SearchManager.java
@@ -12,13 +12,26 @@
12 12
13package org.scilab.modules.scinotes; 13package org.scilab.modules.scinotes;
14 14
15import java.io.BufferedReader;
16import java.io.File;
17import java.io.FileReader;
18import java.io.FilenameFilter;
19import java.io.IOException;
15import java.util.ArrayList; 20import java.util.ArrayList;
21import java.util.Arrays;
16import java.util.List; 22import java.util.List;
23import java.util.Scanner;
17import java.util.regex.Matcher; 24import java.util.regex.Matcher;
18import java.util.regex.Pattern; 25import java.util.regex.Pattern;
19 26
27import javax.swing.Icon;
28import javax.swing.ImageIcon;
29import javax.swing.SwingWorker;
20import javax.swing.text.BadLocationException; 30import javax.swing.text.BadLocationException;
21import javax.swing.text.Document; 31import javax.swing.text.Document;
32import javax.swing.tree.DefaultMutableTreeNode;
33
34import org.scilab.modules.scinotes.utils.SciNotesMessages;
22 35
23/** 36/**
24 * Class SearchManager 37 * Class SearchManager
@@ -27,6 +40,11 @@ import javax.swing.text.Document;
27 */ 40 */
28public class SearchManager { 41public class SearchManager {
29 42
43 private static final ImageIcon FILEIMAGE = new ImageIcon(System.getenv("SCI") + "/modules/gui/images/icons/16x16/search/file.png");
44 private static final ImageIcon SCILABFILEIMAGE = new ImageIcon(System.getenv("SCI") + "/modules/gui/images/icons/16x16/search/scilab-file.png");
45 private static final ImageIcon FOLDERIMAGE = new ImageIcon(System.getenv("SCI") + "/modules/gui/images/icons/16x16/search/folder.png");
46 private static final ImageIcon LINEICON = new ImageIcon(System.getenv("SCI") + "/modules/gui/images/icons/16x16/search/line-found.png");
47
30 /** 48 /**
31 * FIND AND REPLACE START 49 * FIND AND REPLACE START
32 * @param scilabDocument document 50 * @param scilabDocument document
@@ -100,4 +118,558 @@ public class SearchManager {
100 } 118 }
101 } 119 }
102 120
121 /**
122 * Search a word (with a pattern) in files selected according to their name.
123 * @param base the base directory
124 * @param recursive, if true then a recursive search is made
125 * @param ignoreCR, if true then the read file is considered as one line and regex pattern can include \n
126 * @param filePattern the pattern to use to select the files. * is equivalent to .* and ? to .?
127 * @param fileCaseSensitive, if true then the file pattern is case sensitive
128 * @param wordPattern the pattern of the word to search
129 * @param wordCaseSensitive, if true then the word pattern is case sensitive
130 * @param wholeWord, if true only whole word will be matched, e.g. in "foobar foo bar", if the pattern is "foo", then only the second "foo" will be matched
131 * @param regexp, if true the word pattern is considered as a regex
132 * @return infos with the matching positions
133 */
134 public static MatchingPositions searchInFiles(final BackgroundSearch bgs, String base, final boolean recursive, final boolean ignoreCR,
135 String filePattern, boolean fileCaseSensitive,
136 String wordPattern, boolean wordCaseSensitive, boolean wholeWord, boolean regexp) {
137 final File dir = new File(base);
138 Pattern word = null;
139 if (wordPattern != null && wordPattern.length() != 0) {
140 word = generatePattern(wordPattern, wordCaseSensitive, wholeWord, regexp);
141 }
142 filePattern = filePattern.replace(".", "\\.").replace("*", ".*").replace("?", ".?");
143 final Pattern file = generatePattern(filePattern, fileCaseSensitive, false, true);
144
145 final boolean[] killed = new boolean[]{false};
146 if (bgs == null) {
147 return searchInFiles(killed, dir, recursive, ignoreCR, file, word);
148 } else {
149 final Pattern fword = word;
150 SwingWorker worker = new SwingWorker<Object, Object>() {
151 public Object doInBackground() {
152 long begin = System.currentTimeMillis();
153 bgs.setResults(searchInFiles(killed, dir, recursive, ignoreCR, file, fword));
154 long end = System.currentTimeMillis();
155 bgs.setElapsedTime(end - begin);
156 return null;
157 }
158
159 public void done() {
160 bgs.done();
161 }
162 };
163 bgs.setKilled(killed);
164 bgs.setSwingWorker(worker);
165 worker.execute();
166 return null;
167 }
168 }
169
170 /**
171 * Search a word (with a pattern) in files selected according to their name.
172 * @param base the base directory
173 * @param recursive, if true then a recursive search is made
174 * @param ignoreCR, if true then the read file is considered as one line and regex pattern can include \n
175 * @param filePattern the pattern to use to select the files. * is equivalent to .* and ? to .?
176 * @param word the pattern of the word to search
177 * @param killed a boolean array with more than one element. It is used as a reference on a boolean set to true if the process is killed.
178 * @return infos with the matching positions
179 */
180 public static MatchingPositions searchInFiles(boolean[] killed, File base, boolean recursive, boolean ignoreCR, final Pattern file, final Pattern word) {
181 MatchingPositions pos = null;
182 if (base.exists() && base.isDirectory() && base.canRead() && !killed[0]) {
183 List<MatchingPositions> list = new ArrayList<MatchingPositions>();
184 pos = new MatchingPositions(base.getAbsolutePath(), list);
185 int occurences = 0;
186 File[] files = base.listFiles(new FilenameFilter() {
187 public boolean accept(File dir, String name) {
188 File f = new File(dir, name);
189 return f.isFile() && f.canRead() && file.matcher(name).matches();
190 }
191 });
192 Arrays.sort(files);
193
194 if (word != null) {
195 for (int i = 0; i < files.length && !killed[0]; i++) {
196 MatchingPositions wpos;
197 if (!ignoreCR) {
198 wpos = searchWordInFile(files[i], word);
199 } else {
200 wpos = searchWordInFileIgnoringCR(files[i], word);
201 }
202 if (wpos != null && wpos.getOccurences() != 0) {
203 list.add(wpos);
204 occurences += wpos.getOccurences();
205 }
206 }
207 } else {
208 for (int i = 0; i < files.length && !killed[0]; i++) {
209 list.add(new MatchingPositions(files[i].getAbsolutePath()));
210 }
211 occurences += files.length;
212 }
213
214 if (recursive) {
215 files = base.listFiles(new FilenameFilter() {
216 public boolean accept(File dir, String name) {
217 File d = new File(dir, name);
218 return d.isDirectory() && d.canRead();
219 }
220 });
221 Arrays.sort(files);
222
223 for (int i = 0; i < files.length && !killed[0]; i++) {
224 MatchingPositions rpos = searchInFiles(killed, files[i], true, ignoreCR, file, word);
225 if (rpos != null) {
226 list.add(rpos);
227 occurences += rpos.getOccurences();
228 }
229 }
230 }
231
232 pos.setOccurences(occurences);
233
234 if (list.isEmpty()) {
235 return null;
236 }
237 }
238
239 return pos;
240 }
241
242 /**
243 * Search a word (with a pattern) in a file. The search is made line by line.
244 * @param file the file where to search
245 * @param pat the pattern of the word to search
246 * @return infos with the matching positions
247 */
248 public static MatchingPositions searchWordInFile(File f, Pattern pat) {
249 if (f.exists() && f.canRead()) {
250 MatchingPositions pos = new MatchingPositions(f.getAbsolutePath());
251 try {
252 Scanner scanner = new Scanner(f);
253 int occ = 0;
254 int line = 0;
255 while (scanner.hasNextLine()) {
256 line++;
257 String str = scanner.nextLine();
258 Matcher matcher = pat.matcher(str);
259 int socc = occ;
260 while (matcher.find()) {
261 occ++;
262 }
263 if (occ != socc) {
264 pos.addLine(line, str, pat);
265 }
266 }
267 scanner.close();
268
269 pos.setOccurences(occ);
270 return pos;
271 } catch (Exception e) { }
272 }
273
274 return null;
275 }
276
277 /**
278 * Search a word (with a pattern) in a file. The file content is considered as one line (useful to search "...\n...")
279 * @param file the file where to search
280 * @param pat the pattern of the word to search
281 * @return infos with the matching positions
282 */
283 public static MatchingPositions searchWordInFileIgnoringCR(File f, Pattern pat) {
284 if (f.exists() && f.canRead()) {
285 MatchingPositions pos = new MatchingPositions(f.getAbsolutePath());
286 try {
287 Scanner scanner = new Scanner(f);
288 int occ = 0;
289 while (scanner.findWithinHorizon(pat, 0) != null) {
290 occ++;
291 }
292 pos.setOccurences(occ);
293 scanner.close();
294
295 return pos;
296 } catch (Exception e) { }
297 }
298
299 return null;
300 }
301
302 /**
303 * Count the file having a name corresponding to a pattern
304 * @param base the base directory
305 * @param pat the file name pattern
306 * @return the number of files
307 */
308 public static int countFiles(File base, Pattern pat) {
309 if (!base.isDirectory() || !base.canRead()) {
310 return -1;
311 }
312
313 int[] count = new int[]{0};
314 countFiles(base, pat, count);
315
316 return count[0];
317 }
318
319 /**
320 * Count files in a recursive way
321 */
322 private static void countFiles(File base, final Pattern pat, final int[] count) {
323 File[] files = base.listFiles(new FilenameFilter() {
324 public boolean accept(File dir, String name) {
325 File f = new File(dir, name);
326 if (f.isFile() && f.canRead() && pat.matcher(name).matches()) {
327 count[0]++;
328 } else if (f.isDirectory() && f.canRead()) {
329 countFiles(f, pat, count);
330 }
331 return false;
332 }
333 });
334 }
335
336 /**
337 * @param file the file to test
338 * @return true if it is a binary file
339 */
340 public static boolean isBinaryFile(File f) {
341 try {
342 BufferedReader reader = new BufferedReader(new FileReader(f));
343 char[] buffer = new char[8192];
344 int len = reader.read(buffer, 0, 8192);
345 reader.close();
346 int i = 0;
347 if (len != -1) {
348 for (;i < len && buffer[i] != '\0'; i++);
349 }
350
351 return len != -1 && i != len;
352 } catch (IOException e) {
353 e.printStackTrace();
354 return false;
355 }
356 }
357
358 /**
359 * MatchingPositions: inner class to store the results of a search in a file or in a directory
360 */
361 public static class MatchingPositions implements Iconable {
362
363 private String file;
364 private boolean isRoot;
365 private Icon icon;
366 private int occurences;
367 private List<MatchingPositions> children;
368 private List<Line> lines = new ArrayList<Line>();
369
370 /**
371 * Constructor
372 * @param file the file where to search is made
373 * @param children the list of the file in the directory
374 */
375 public MatchingPositions(String file, List<MatchingPositions> children) {
376 this.file = file;
377 this.children = children;
378 if (children != null) {
379 this.icon = FOLDERIMAGE;
380 } else if (file.endsWith(".sce") || file.endsWith(".sci")) {
381 this.icon = SCILABFILEIMAGE;
382 } else {
383 this.icon = FILEIMAGE;
384 }
385 }
386
387 /**
388 * Constructor
389 * @param file the file where to search is made
390 */
391 public MatchingPositions(String file) {
392 this(file, null);
393 }
394
395 /**
396 * Set this as the root directory
397 */
398 public void setRoot() {
399 isRoot = true;
400 }
401
402 /**
403 * Set the number of matches in the file or in the directory
404 * @param occ the number of matches
405 */
406 public void setOccurences(int occ) {
407 occurences = occ;
408 }
409
410 /**
411 * @return the number of matches
412 */
413 public int getOccurences() {
414 return occurences;
415 }
416
417 /**
418 * Add a line where the searched word has been found
419 * @param number the line number
420 * @param line the line content
421 * @param pat the pattern used
422 */
423 public void addLine(int number, String line, Pattern pat) {
424 this.lines.add(new Line(number, line, pat));
425 }
426
427 /**
428 * @return the file name
429 */
430 public String getFileName() {
431 return file;
432 }
433
434 /**
435 * @return true if we are in a directory
436 */
437 public boolean isDirectory() {
438 return children != null;
439 }
440
441 /**
442 * {@inheritDoc}
443 */
444 public Icon getIcon() {
445 return icon;
446 }
447
448 /**
449 * @return true if the file have matching lines
450 */
451 public boolean hasLines() {
452 return !lines.isEmpty();
453 }
454
455 /**
456 * @return the file present in this directory
457 */
458 public List<MatchingPositions> getChildren() {
459 return children;
460 }
461
462 /**
463 * Convert this MatchingPositions and its children (if they are) in a DefaultMutableTreeNode
464 * @return the coirresponding DefaultMutableTreeNode
465 */
466 public DefaultMutableTreeNode toDefaultMutableTreeNode() {
467 DefaultMutableTreeNode root = new DefaultMutableTreeNode(this);
468 if (children != null && !children.isEmpty()) {
469 for (int i = 0; i < children.size(); i++) {
470 root.add(children.get(i).toDefaultMutableTreeNode());
471 }
472 } else if (!lines.isEmpty()) {
473 for (Line l : lines) {
474 root.add(new DefaultMutableTreeNode(l));
475 }
476 }
477
478 return root;
479 }
480
481 /**
482 * {@inheritDoc}
483 */
484 public String toString() {
485 String occ = SciNotesMessages.MATCHES;
486 if (occurences <= 1) {
487 occ = SciNotesMessages.MATCH;
488 }
489
490 String filename;
491 if ((!isDirectory() && occurences != 0)) {
492 filename = new File(getFileName()).getName();
493 } else if (isRoot) {
494 filename = getFileName();
495 } else {
496 filename = new File(getFileName()).getName();
497 }
498
499 if (occurences == 0 && !isRoot) {
500 return filename;
501 }
502
503 filename = filename.replace("&", "&amp;").replace("/", "&#47;").replace("\\", "&#92;").replace("<", "&lt;").replace(">", "&gt;");
504 return String.format(occ, filename, occurences);
505 }
506 }
507
508 /**
509 * Line: inner class to store a line number and line content
510 */
511 public static class Line implements Iconable {
512
513 private int number;
514 private String content;
515
516 /**
517 * Constructor
518 * @param number the line number
519 * @param content the line content
520 * @param pattern the used pattern
521 */
522 public Line(int number, String content, Pattern pattern) {
523 this.number = number;
524 Matcher matcher = pattern.matcher(content);
525 if (content.length() > 128) {
526 content = content.substring(0, 128) + "...";
527 }
528 StringBuffer sb = new StringBuffer();
529 while (matcher.find()) {
530 /*
531 TODO: Find a better way to handle <b> and </b> around the pattern.
532 If HTML entities are put before the loop the pattern should be updated (not a funky task...).
533 Actually, it could have a bad rendering on binary files (which probably contains \0...)
534 */
535 matcher.appendReplacement(sb, "\0");
536 sb.append(matcher.group());
537 sb.append("\0\0");
538 }
539 matcher.appendTail(sb);
540 this.content = sb.toString();
541 this.content = this.content.replace("&", "&amp;").replace("/", "&#47;").replace("\\", "&#92;").replace("<", "&lt;").replace(">", "&gt;").replace("\0\0", "</b>").replace("\0", "<b>");
542 }
543
544 /**
545 * @return the line number
546 */
547 public int getNumber() {
548 return number;
549 }
550
551 /**
552 * @return the line content as HTML
553 */
554 public String getContent() {
555 return content;
556 }
557
558 /**
559 * {@inheritDoc}
560 */
561 public Icon getIcon() {
562 return LINEICON;
563 }
564
565 /**
566 * {@inheritDoc}
567 */
568 public String toString() {
569 return "<html><u>line " + number + "</u>&thinsp;: " + content + "</html>";
570 }
571 }
572
573 /**
574 * Inner interface for the JTree representation
575 */
576 public static interface Iconable {
577
578 /**
579 * @return the icon used in the JTree representation
580 */
581 public Icon getIcon();
582 }
583
584 /**
585 * Inner class to allow a background search
586 */
587 public static abstract class BackgroundSearch {
588
589 private MatchingPositions pos;
590 private SwingWorker worker;
591 private long time;
592 private boolean[] killed;
593
594 /**
595 * Default Constructor
596 */
597 public BackgroundSearch() { }
598
599 /**
600 * Stop this search
601 */
602 public void stop() {
603 if (worker != null && !isDone()) {
604 worker.cancel(true);
605 worker = null;
606 if (killed != null && killed.length >= 1) {
607 killed[0] = true;
608 }
609 }
610 }
611
612 /**
613 * Called when the work is done
614 */
615 public abstract void done();
616
617 /**
618 * @return true if the search is finished
619 */
620 public boolean isDone() {
621 if (worker != null) {
622 return worker.isDone();
623 }
624 return true;
625 }
626
627 /**
628 * Get the results
629 * @return the results
630 */
631 public MatchingPositions getResults() {
632 if (isDone()) {
633 worker = null;
634 return pos;
635 }
636 return null;
637 }
638
639 /**
640 * Set the elapsed time for this search
641 */
642 public void setElapsedTime(long t) {
643 this.time = t;
644 }
645
646 /**
647 * @return the elapsed time of this search
648 */
649 public long getElapsedTime() {
650 return time;
651 }
652
653 /**
654 * Set the SwingWorker we work with
655 * @param worker the SwingWorker
656 */
657 private void setSwingWorker(SwingWorker worker) {
658 this.worker = worker;
659 }
660
661 /**
662 * @param killed a reference on a boolean to inform the main loop that the process has been killed
663 */
664 private void setKilled(boolean[] killed) {
665 this.killed = killed;
666 }
667
668 /**
669 * @param pos the results to set
670 */
671 private void setResults(MatchingPositions pos) {
672 this.pos = pos;
673 }
674 }
103} 675}
diff --git a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/FindAction.java b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/FindAction.java
index 008a478..0efa779 100644
--- a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/FindAction.java
+++ b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/FindAction.java
@@ -27,6 +27,7 @@ import java.awt.event.KeyListener;
27import java.awt.event.MouseEvent; 27import java.awt.event.MouseEvent;
28import java.awt.event.MouseListener; 28import java.awt.event.MouseListener;
29import java.awt.event.WindowEvent; 29import java.awt.event.WindowEvent;
30import java.awt.event.WindowFocusListener;
30import java.awt.event.WindowListener; 31import java.awt.event.WindowListener;
31import java.util.List; 32import java.util.List;
32import java.util.regex.Matcher; 33import java.util.regex.Matcher;
@@ -78,7 +79,7 @@ import org.scilab.modules.scinotes.utils.SciNotesMessages;
78 * @author Vincent COUVERT 79 * @author Vincent COUVERT
79 * @author Calixte DENIZET 80 * @author Calixte DENIZET
80 */ 81 */
81public final class FindAction extends DefaultAction { 82public final class FindAction extends DefaultAction implements WindowFocusListener {
82 83
83 /** 84 /**
84 * serialVersionUID 85 * serialVersionUID
@@ -255,6 +256,24 @@ public final class FindAction extends DefaultAction {
255 } 256 }
256 257
257 /** 258 /**
259 * {@inheritedDoc}
260 */
261 public void windowGainedFocus(WindowEvent e) {
262 if (e.getWindow() == getEditor().getSwingParentWindow()) {
263 frame.setAlwaysOnTop(true);
264 }
265 }
266
267 /**
268 * {@inheritedDoc}
269 */
270 public void windowLostFocus(WindowEvent e) {
271 if (e.getOppositeWindow() != frame && e.getOppositeWindow() != getEditor().getSwingParentWindow()) {
272 frame.setAlwaysOnTop(false);
273 }
274 }
275
276 /**
258 * findReplaceBox 277 * findReplaceBox
259 */ 278 */
260 public void findReplaceBox() { 279 public void findReplaceBox() {
@@ -274,6 +293,9 @@ public final class FindAction extends DefaultAction {
274 frame.setTitle(SciNotesMessages.FIND_REPLACE); 293 frame.setTitle(SciNotesMessages.FIND_REPLACE);
275 frame.setResizable(false); 294 frame.setResizable(false);
276 295
296 getEditor().getSwingParentWindow().addWindowFocusListener(this);
297 frame.addWindowFocusListener(this);
298
277 buttonGroup1 = new ButtonGroup(); 299 buttonGroup1 = new ButtonGroup();
278 buttonGroup2 = new ButtonGroup(); 300 buttonGroup2 = new ButtonGroup();
279 panelFrame = new JPanel(); 301 panelFrame = new JPanel();
@@ -1134,6 +1156,8 @@ public final class FindAction extends DefaultAction {
1134 int end = scinotesTextPane.getSelectionEnd(); 1156 int end = scinotesTextPane.getSelectionEnd();
1135 scinotesTextPane.select(start, end); 1157 scinotesTextPane.select(start, end);
1136 } 1158 }
1159 getEditor().getSwingParentWindow().removeWindowFocusListener(this);
1160 frame.removeWindowFocusListener(this);
1137 frame.dispose(); 1161 frame.dispose();
1138 windowAlreadyExist = false; 1162 windowAlreadyExist = false;
1139 } 1163 }
diff --git a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/SearchFilesAction.java b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/SearchFilesAction.java
new file mode 100644
index 0000000..eaba69e
--- /dev/null
+++ b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/SearchFilesAction.java
@@ -0,0 +1,46 @@
1/*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2010 - Calixte DENIZET
4 *
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10 *
11 */
12
13package org.scilab.modules.scinotes.actions;
14
15import javax.swing.KeyStroke;
16
17import org.scilab.modules.gui.menuitem.MenuItem;
18import org.scilab.modules.scinotes.SciNotes;
19
20/**
21 * SearchFilesAction Class
22 * @author Calixte DENIZET
23 */
24public class SearchFilesAction extends SearchWordInFilesAction {
25
26 /**
27 * Constructor
28 * @param name the name of the action
29 * @param editor SciNotes
30 */
31 public SearchFilesAction(String name, SciNotes editor) {
32 super(name, editor);
33 searchFiles = true;
34 }
35
36 /**
37 * createMenu
38 * @param label label of the menu
39 * @param editor SciNotes
40 * @param key Keystroke
41 * @return MenuItem
42 */
43 public static MenuItem createMenu(String label, final SciNotes editor, KeyStroke key) {
44 return createMenu(label, null, new SearchFilesAction(label, editor), key);
45 }
46}
diff --git a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/SearchWordInFilesAction.java b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/SearchWordInFilesAction.java
new file mode 100644
index 0000000..5f27108
--- /dev/null
+++ b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/actions/SearchWordInFilesAction.java
@@ -0,0 +1,637 @@
1/*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2010 - Calixte DENIZET
4 *
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10 *
11 */
12
13package org.scilab.modules.scinotes.actions;
14
15import java.awt.Color;
16import java.awt.Container;
17import java.awt.GridBagConstraints;
18import java.awt.GridBagLayout;
19import java.awt.GridLayout;
20import java.awt.Insets;
21import java.awt.event.ActionEvent;
22import java.awt.event.ActionListener;
23import java.awt.event.WindowEvent;
24import java.awt.event.WindowFocusListener;
25import java.awt.event.ItemEvent;
26import java.awt.event.ItemListener;
27import java.awt.event.KeyEvent;
28import java.awt.event.KeyListener;
29import java.awt.event.WindowEvent;
30import java.awt.event.WindowListener;
31import java.beans.PropertyChangeEvent;
32import java.beans.PropertyChangeListener;
33import java.io.File;
34import java.util.List;
35import java.util.regex.Pattern;
36import java.util.regex.PatternSyntaxException;
37
38import javax.swing.AbstractAction;
39import javax.swing.BorderFactory;
40import javax.swing.BoxLayout;
41import javax.swing.ImageIcon;
42import javax.swing.JButton;
43import javax.swing.JCheckBox;
44import javax.swing.JComboBox;
45import javax.swing.JComponent;
46import javax.swing.JFileChooser;
47import javax.swing.JFrame;
48import javax.swing.JLabel;
49import javax.swing.JPanel;
50import javax.swing.JTextField;
51import javax.swing.KeyStroke;
52import javax.swing.SwingUtilities;
53import javax.swing.event.PopupMenuEvent;
54import javax.swing.event.PopupMenuListener;
55import javax.swing.text.BadLocationException;
56import javax.swing.text.JTextComponent;
57
58import org.scilab.modules.gui.filechooser.ScilabFileChooser;
59import org.scilab.modules.gui.bridge.filechooser.SwingScilabFileChooser;
60import org.scilab.modules.gui.bridge.window.SwingScilabWindow;
61import org.scilab.modules.gui.menuitem.MenuItem;
62import org.scilab.modules.scinotes.SciNotes;
63import org.scilab.modules.scinotes.ScilabDocument;
64import org.scilab.modules.scinotes.ScilabLexer;
65import org.scilab.modules.scinotes.ScilabLexerConstants;
66import org.scilab.modules.scinotes.ScilabEditorPane;
67import org.scilab.modules.scinotes.KeywordEvent;
68import org.scilab.modules.scinotes.utils.ConfigSciNotesManager;
69import org.scilab.modules.scinotes.utils.SciNotesMessages;
70import org.scilab.modules.scinotes.utils.SearchFile;
71import org.scilab.modules.action_binding.InterpreterManagement;
72
73/**
74 * SearchWordInFilesAction Class
75 * @author Calixte DENIZET
76 */
77public class SearchWordInFilesAction extends DefaultAction implements WindowFocusListener {
78
79 private static final long serialVersionUID = 1L;
80
81 private static final int GAP = 5;
82 private static final String FILTERNEWLINES = "filterNewlines";
83 private static final String ESCAPE = "ESCAPE";
84 private static final Color ERRORCOLOR = Color.RED;
85 private static Color NORMALCOLOR;
86
87 private static boolean windowAlreadyExist;
88 private static JFrame mainFrame;
89 private static Object searcher;
90 private static SearchWordInFilesAction current;
91
92 private JButton buttonFind;
93 private JButton buttonStop;
94 private JButton buttonClose;
95 private JButton cancelButton;
96 private JButton chooseBaseDirButton;
97 private JComboBox comboBaseDir;
98 private JComboBox comboFilePattern;
99 private JComboBox comboWordPattern;
100 private JCheckBox checkRecursive;
101 private JCheckBox checkWordCase;
102 private JCheckBox checkFileCase;
103 private JCheckBox checkRegular;
104 private JCheckBox checkLineByLine;
105 private JCheckBox checkWhole;
106
107 private boolean comboBaseDirCanceled;
108 private boolean comboFilePatternCanceled;
109 private boolean comboWordPatternCanceled;
110
111 private String lastWordPattern;
112 private String lastFilePattern;
113 private String lastBaseDir;
114
115 protected boolean searchFiles;
116
117 /**
118 * Constructor
119 * @param name the name of the action
120 * @param editor SciNotes
121 */
122 public SearchWordInFilesAction(String name, SciNotes editor) {
123 super(name, editor);
124 }
125
126 /**
127 * doAction
128 */
129 public void doAction() {
130 current = this;
131 openSearchWindow();
132 }
133
134 /**
135 * createMenu
136 * @param label label of the menu
137 * @param editor SciNotes
138 * @param key Keystroke
139 * @return MenuItem
140 */
141 public static MenuItem createMenu(String label, final SciNotes editor, KeyStroke key) {
142 return createMenu(label, null, new SearchWordInFilesAction(label, editor), key);
143 }
144
145 /**
146 * Close the window
147 */
148 public static void closeWindow() {
149 if (windowAlreadyExist) {
150 stopSearch();
151 SwingScilabWindow window = current.getEditor().getSwingParentWindow();
152 if (window != null) {
153 window.removeWindowFocusListener(current);
154 }
155 mainFrame.removeWindowFocusListener(current);
156 mainFrame.dispose();
157 windowAlreadyExist = false;
158 }
159 }
160
161 /**
162 * Start a search
163 */
164 public void startSearch() {
165 if (SearchFile.isDone(searcher)) {
166 buttonStop.setEnabled(true);
167 buttonFind.setEnabled(false);
168 String baseDir = (String) comboBaseDir.getEditor().getItem();
169 boolean recursive = checkRecursive.isSelected();
170 boolean lineByLine = checkLineByLine.isSelected();
171 String filePattern = (String) comboFilePattern.getEditor().getItem();
172 boolean fileCase = checkFileCase.isSelected();
173 String wordPattern = null;
174 if (!searchFiles) {
175 wordPattern = (String) comboWordPattern.getEditor().getItem();
176 }
177 boolean wordCase = checkWordCase.isSelected();
178 boolean wholeWord = checkWhole.isSelected();
179 boolean regex = checkRegular.isSelected();
180 searcher = SearchFile.getSearchResultsWindow(buttonStop, getEditor(), baseDir, recursive, !lineByLine, filePattern, fileCase, wordPattern, wordCase, wholeWord, regex);
181 }
182 }
183
184 /**
185 * Stop the current search if exists
186 */
187 public static void stopSearch() {
188 if (searcher != null) {
189 SearchFile.stopSearch(searcher);
190 searcher = null;
191 }
192 }
193
194 /**
195 * {@inheritedDoc}
196 */
197 public void windowGainedFocus(WindowEvent e) {
198 if (e.getWindow() == getEditor().getSwingParentWindow()) {
199 mainFrame.setAlwaysOnTop(true);
200 }
201 }
202
203 /**
204 * {@inheritedDoc}
205 */
206 public void windowLostFocus(WindowEvent e) {
207 if (e.getOppositeWindow() != mainFrame && e.getOppositeWindow() != getEditor().getSwingParentWindow()) {
208 mainFrame.setAlwaysOnTop(false);
209 }
210 }
211
212 /**
213 * Open a window to get the name of the macro
214 * @param name the name of a macro
215 */
216 public void openSearchWindow() {
217 if (windowAlreadyExist) {
218 mainFrame.setVisible(true);
219 return;
220 }
221
222 mainFrame = new JFrame();
223 mainFrame.setAlwaysOnTop(true);
224 mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
225 mainFrame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE , 0), ESCAPE);
226 mainFrame.getRootPane().getActionMap().put(ESCAPE, new AbstractAction() {
227 public void actionPerformed(ActionEvent e) {
228 closeWindow();
229 }
230 });
231 mainFrame.setTitle(SciNotesMessages.SEARCHINFILES);
232 mainFrame.setIconImage(new ImageIcon(System.getenv("SCI") + "/modules/gui/images/icons/32x32/apps/system-search.png").getImage());
233
234 getEditor().getSwingParentWindow().addWindowFocusListener(this);
235 mainFrame.addWindowFocusListener(this);
236
237 windowAlreadyExist = true;
238
239 JLabel baseDirLabel = new JLabel(SciNotesMessages.BASEDIRECTORY);
240 comboBaseDir = new JComboBox();
241 comboBaseDir.setEditable(true);
242 chooseBaseDirButton = new JButton(SciNotesMessages.CHOOSEDIR);
243 JPanel panelBase = new JPanel();
244 JLabel filePatternLabel = new JLabel(SciNotesMessages.FILEPATTERN + ":");
245 JLabel filePatternExpLabel = new JLabel(SciNotesMessages.FILEPATTERNEXP);
246 comboFilePattern = new JComboBox();
247 comboFilePattern.setEditable(true);
248 ((JTextField) comboFilePattern.getEditor().getEditorComponent()).setColumns(32);
249 JLabel wordPatternLabel = new JLabel(SciNotesMessages.WORDPATTERN + ":");
250 comboWordPattern = new JComboBox();
251 comboWordPattern.setEditable(true);
252 ((JTextField) comboWordPattern.getEditor().getEditorComponent()).setColumns(32);
253 NORMALCOLOR = ((JTextField) comboWordPattern.getEditor().getEditorComponent()).getForeground();
254
255 JPanel panelOptions = new JPanel();
256 panelOptions.setBorder(BorderFactory.createTitledBorder(SciNotesMessages.OPTIONS));
257 checkWordCase = new JCheckBox(SciNotesMessages.WORDCASESENSITIVE);
258 checkFileCase = new JCheckBox(SciNotesMessages.FILECASESENSITIVE);
259 checkWhole = new JCheckBox(SciNotesMessages.WHOLE_WORD);
260 checkRegular = new JCheckBox(SciNotesMessages.REGULAR_EXPRESSIONS);
261 checkLineByLine = new JCheckBox(SciNotesMessages.FILELINEBYLINE);
262 checkRecursive = new JCheckBox(SciNotesMessages.RECURSIVESEARCH);
263 panelOptions.setLayout(new GridLayout(3, 2, GAP, GAP));
264 panelOptions.add(checkWordCase);
265 panelOptions.add(checkFileCase);
266 panelOptions.add(checkWhole);
267 panelOptions.add(checkRegular);
268 panelOptions.add(checkLineByLine);
269 panelOptions.add(checkRecursive);
270
271 buttonFind = new JButton(SciNotesMessages.FIND_BUTTON);
272 buttonStop = new JButton(SciNotesMessages.STOPBUTTON);
273 buttonStop.setEnabled(false);
274 buttonClose = new JButton(SciNotesMessages.CLOSE);
275 JPanel panelButton = new JPanel();
276 panelButton.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
277 panelButton.setLayout(new GridLayout(1, 4, GAP, GAP));
278 panelButton.add(new JLabel());
279 panelButton.add(buttonFind);
280 panelButton.add(buttonStop);
281 panelButton.add(buttonClose);
282
283 restoreConfiguration();
284 if (searchFiles) {
285 comboWordPattern.setEnabled(false);
286 checkWordCase.setEnabled(false);
287 checkWhole.setEnabled(false);
288 checkRegular.setEnabled(false);
289 checkLineByLine.setEnabled(false);
290 wordPatternLabel.setEnabled(false);
291 }
292
293 panelBase.setLayout(new GridBagLayout());
294 GridBagConstraints gbc = new GridBagConstraints();
295
296 gbc.gridx = gbc.gridy = 0;
297 gbc.gridwidth = gbc.gridheight = 1;
298 gbc.weightx = gbc.weighty = 0;
299 gbc.anchor = gbc.LINE_START;
300 panelBase.add(baseDirLabel, gbc);
301
302 gbc.gridx = 0;
303 gbc.gridy = 1;
304 gbc.gridwidth = 3;
305 gbc.weightx = 1;
306 gbc.fill = GridBagConstraints.HORIZONTAL;
307 gbc.anchor = GridBagConstraints.BASELINE;
308 gbc.insets = new Insets(0, 0, GAP, 0);
309 panelBase.add(comboBaseDir, gbc);
310
311 gbc.gridx = 3;
312 gbc.gridwidth = 1;
313 gbc.weightx = 0;
314 gbc.fill = gbc.NONE;
315 panelBase.add(chooseBaseDirButton, gbc);
316
317 gbc.gridx = 0;
318 gbc.gridy = 2;
319 gbc.anchor = gbc.LINE_START;
320 panelBase.add(filePatternLabel, gbc);
321
322 gbc.gridy = 3;
323 gbc.gridwidth = 3;
324 gbc.weightx = 1;
325 gbc.fill = GridBagConstraints.HORIZONTAL;
326 gbc.anchor = GridBagConstraints.BASELINE;
327 panelBase.add(comboFilePattern, gbc);
328
329 gbc.gridx = 1;
330 gbc.gridy = 4;
331 gbc.gridwidth = 2;
332 gbc.weightx = 1;
333 gbc.fill = GridBagConstraints.NONE;
334 gbc.anchor = GridBagConstraints.EAST;
335 gbc.insets = new Insets(0, 0, GAP, 0);
336 panelBase.add(filePatternExpLabel, gbc);
337
338 gbc.gridx = 0;
339 gbc.gridy = 5;
340 gbc.gridwidth = 1;
341 gbc.weightx = 0;
342 gbc.anchor = gbc.LINE_START;
343 panelBase.add(wordPatternLabel, gbc);
344
345 gbc.gridy = 6;
346 gbc.gridwidth = 3;
347 gbc.weightx = 1;
348 gbc.fill = GridBagConstraints.HORIZONTAL;
349 gbc.anchor = GridBagConstraints.BASELINE;
350 gbc.insets = new Insets(0, 0, GAP, 0);
351 panelBase.add(comboWordPattern, gbc);
352
353 JPanel panelFrame = new JPanel();
354 panelFrame.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
355 panelFrame.setLayout(new BoxLayout(panelFrame, BoxLayout.PAGE_AXIS));
356 panelFrame.add(panelBase);
357 panelFrame.add(panelOptions);
358 panelFrame.add(panelButton);
359
360 mainFrame.setContentPane(panelFrame);
361
362 mainFrame.addWindowListener(new WindowListener() {
363 public void windowClosed(WindowEvent arg0) { }
364 public void windowDeiconified(WindowEvent arg0) { }
365 public void windowActivated(WindowEvent arg0) { }
366
367 public void windowClosing(WindowEvent arg0) {
368 closeWindow();
369 }
370
371 public void windowDeactivated(WindowEvent arg0) { }
372 public void windowIconified(WindowEvent arg0) { };
373 public void windowOpened(WindowEvent arg0) { }
374 });
375
376 checkWordCase.addActionListener(new ActionListener() {
377 public void actionPerformed(ActionEvent e) {
378 ConfigSciNotesManager.saveCaseSensitive(checkWordCase.isSelected());
379 }
380 });
381
382 checkFileCase.addActionListener(new ActionListener() {
383 public void actionPerformed(ActionEvent e) {
384 ConfigSciNotesManager.saveFileCase(checkFileCase.isSelected());
385 }
386 });
387
388 checkWhole.addActionListener(new ActionListener() {
389 public void actionPerformed(ActionEvent e) {
390 ConfigSciNotesManager.saveWholeWord(checkWhole.isSelected());
391 }
392 });
393
394 checkRecursive.addActionListener(new ActionListener() {
395 public void actionPerformed(ActionEvent e) {
396 ConfigSciNotesManager.saveRecursive(checkRecursive.isSelected());
397 }
398 });
399
400 checkRegular.addActionListener(new ActionListener() {
401 public void actionPerformed(ActionEvent e) {
402 ConfigSciNotesManager.saveRegularExpression(checkRegular.isSelected());
403 }
404 });
405
406 checkLineByLine.addActionListener(new ActionListener() {
407 public void actionPerformed(ActionEvent e) {
408 ConfigSciNotesManager.saveLineByLine(checkLineByLine.isSelected());
409 }
410 });
411
412 chooseBaseDirButton.addActionListener(new ActionListener() {
413 public void actionPerformed(ActionEvent e) {
414 SwingScilabFileChooser fileChooser = ((SwingScilabFileChooser) ScilabFileChooser.createFileChooser().getAsSimpleFileChooser());
415 fileChooser.setDialogTitle(SciNotesMessages.CHOOSEBASEDIR);
416 fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
417 fileChooser.setAcceptAllFileFilterUsed(false);
418 if (fileChooser.showOpenDialog(getEditor()) == JFileChooser.APPROVE_OPTION) {
419 File path = fileChooser.getSelectedFile();
420 if (path == null || path.isFile()) {
421 path = fileChooser.getCurrentDirectory();
422 }
423 comboBaseDir.getEditor().setItem(path.toString());
424 updateFindButtonStatus(true);
425 }
426 }
427 });
428
429 buttonFind.addActionListener(new ActionListener() {
430 public void actionPerformed(ActionEvent e) {
431 updateCombos();
432 startSearch();
433 }
434 });
435
436 buttonStop.addActionListener(new ActionListener() {
437 public void actionPerformed(ActionEvent e) {
438 stopSearch();
439 }
440
441 });
442
443 buttonStop.addPropertyChangeListener(new PropertyChangeListener() {
444 public void propertyChange(PropertyChangeEvent e) {
445 if (mainFrame.isVisible() && e.getPropertyName().equals(SearchFile.SEARCHDONE)) {
446 buttonFind.setEnabled((Boolean) e.getNewValue());
447 buttonStop.setEnabled(!((Boolean) e.getNewValue()));
448 }
449 }
450 });
451
452 buttonClose.addActionListener(new ActionListener() {
453 public void actionPerformed(ActionEvent e) {
454 closeWindow();
455 }
456
457 });
458
459 comboBaseDir.addItemListener(new ItemListener() {
460 public void itemStateChanged(ItemEvent e) {
461 updateFindButtonStatus(true);
462 }
463 });
464
465 comboBaseDir.addPopupMenuListener(new PopupMenuListener() {
466 public void popupMenuCanceled(PopupMenuEvent e) {
467 comboBaseDirCanceled = true;
468 }
469
470 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { }
471
472 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
473 });
474
475 comboBaseDir.getEditor().getEditorComponent().addKeyListener(new KeyListener() {
476 public void keyTyped(KeyEvent e) { }
477 public void keyReleased(KeyEvent e) {
478 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
479 if (comboBaseDirCanceled) {
480 comboBaseDirCanceled = false;
481 } else {
482 closeWindow();
483 }
484 }
485 updateFindButtonStatus(true);
486 }
487
488 public void keyPressed(KeyEvent e) { }
489 });
490
491 comboFilePattern.addItemListener(new ItemListener() {
492 public void itemStateChanged(ItemEvent e) {
493 updateFindButtonStatus(false);
494 }
495 });
496
497 comboFilePattern.addPopupMenuListener(new PopupMenuListener() {
498 public void popupMenuCanceled(PopupMenuEvent e) {
499 comboFilePatternCanceled = true;
500 }
501
502 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { }
503
504 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
505 });
506
507 comboFilePattern.getEditor().getEditorComponent().addKeyListener(new KeyListener() {
508 public void keyTyped(KeyEvent e) { }
509 public void keyReleased(KeyEvent e) {
510 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
511 if (comboFilePatternCanceled) {
512 comboFilePatternCanceled = false;
513 } else {
514 closeWindow();
515 }
516 }
517 updateFindButtonStatus(false);
518 }
519
520 public void keyPressed(KeyEvent e) { }
521 });
522
523 comboWordPattern.addPopupMenuListener(new PopupMenuListener() {
524 public void popupMenuCanceled(PopupMenuEvent e) {
525 comboWordPatternCanceled = true;
526 }
527
528 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { }
529
530 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
531 });
532
533 comboWordPattern.getEditor().getEditorComponent().addKeyListener(new KeyListener() {
534 public void keyTyped(KeyEvent e) { }
535 public void keyReleased(KeyEvent e) {
536 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
537 if (comboWordPatternCanceled) {
538 comboWordPatternCanceled = false;
539 } else {
540 closeWindow();
541 }
542 }
543 if (checkRegular.isSelected()) {
544 try {
545 Pattern.compile((String) comboWordPattern.getEditor().getItem());
546 ((JTextField) comboWordPattern.getEditor().getEditorComponent()).setForeground(NORMALCOLOR);
547 buttonFind.setEnabled(true);
548 } catch (PatternSyntaxException pse) {
549 ((JTextField) comboWordPattern.getEditor().getEditorComponent()).setForeground(ERRORCOLOR);
550 buttonFind.setEnabled(false);
551 }
552 }
553 }
554
555 public void keyPressed(KeyEvent e) { }
556 });
557
558 mainFrame.pack();
559 mainFrame.setResizable(false);
560 mainFrame.setLocationRelativeTo(getEditor());
561 mainFrame.setVisible(true);
562 }
563
564 /**
565 * Update status of buttons
566 */
567 protected void updateFindButtonStatus(boolean baseDirModified) {
568 String baseDir = (String) comboBaseDir.getEditor().getItem();
569 String filePattern = (String) comboFilePattern.getEditor().getItem();
570 boolean goodBaseDir = !baseDirModified;
571 if (baseDirModified && !baseDir.isEmpty()) {
572 File dir = new File(baseDir);
573 if (dir.exists() && dir.isDirectory()) {
574 goodBaseDir = true;
575 }
576 }
577 if (goodBaseDir) {
578 ((JTextField) comboBaseDir.getEditor().getEditorComponent()).setForeground(NORMALCOLOR);
579 buttonFind.setEnabled(!filePattern.isEmpty());
580 } else {
581 ((JTextField) comboBaseDir.getEditor().getEditorComponent()).setForeground(ERRORCOLOR);
582 buttonFind.setEnabled(false);
583 }
584 }
585
586 /**
587 * Update the combos
588 */
589 public void updateCombos() {
590 lastBaseDir = updateRecent(comboBaseDir, lastBaseDir, ConfigSciNotesManager.RECENTBASEDIR, ConfigSciNotesManager.BASEDIR);
591 lastFilePattern = updateRecent(comboFilePattern, lastFilePattern, ConfigSciNotesManager.RECENTFILEPATTERN, ConfigSciNotesManager.FILEPATTERN);
592 lastWordPattern = updateRecent(comboWordPattern, lastWordPattern, ConfigSciNotesManager.RECENTWORDPATTERN, ConfigSciNotesManager.WORDPATTERN);
593 }
594
595 /**
596 * Restore configuration
597 */
598 private void restoreConfiguration() {
599 checkRegular.setSelected(ConfigSciNotesManager.getRegularExpression());
600 checkWhole.setSelected(ConfigSciNotesManager.getWholeWord());
601 checkWordCase.setSelected(ConfigSciNotesManager.getCaseSensitive());
602 checkFileCase.setSelected(ConfigSciNotesManager.getFileCase());
603 checkRecursive.setSelected(ConfigSciNotesManager.getRecursive());
604 checkLineByLine.setSelected(ConfigSciNotesManager.getLineByLine());
605 fillCombo(comboBaseDir, ConfigSciNotesManager.RECENTBASEDIR, ConfigSciNotesManager.BASEDIR);
606 fillCombo(comboFilePattern, ConfigSciNotesManager.RECENTFILEPATTERN, ConfigSciNotesManager.FILEPATTERN);
607 fillCombo(comboWordPattern, ConfigSciNotesManager.RECENTWORDPATTERN, ConfigSciNotesManager.WORDPATTERN);
608 }
609
610 /**
611 * fill comboBaseDir
612 */
613 private static void fillCombo(JComboBox combo, String nodeName, String childNodeName) {
614 combo.removeAllItems();
615 List<String> recent = ConfigSciNotesManager.getRecent(nodeName, childNodeName);
616 for (String item : recent) {
617 combo.addItem(item);
618 }
619 }
620
621 /**
622 * Update recent base directory
623 */
624 private static String updateRecent(JComboBox combo, String last, String nodeName, String childNodeName) {
625 String str = (String) combo.getEditor().getItem();
626 if (str != null && str.length() != 0 && !str.equals(last)) {
627 List<String> recent = ConfigSciNotesManager.getRecent(nodeName, childNodeName);
628 if (!recent.contains(str)) {
629 combo.addItem(str);
630 combo.setSelectedItem(str);
631 ConfigSciNotesManager.saveRecent(str, nodeName, childNodeName);
632 last = str;
633 }
634 }
635 return last;
636 }
637}
diff --git a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/ConfigSciNotesManager.java b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/ConfigSciNotesManager.java
index 2c05eb5..4ee7b69 100644
--- a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/ConfigSciNotesManager.java
+++ b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/ConfigSciNotesManager.java
@@ -69,6 +69,14 @@ import org.xml.sax.SAXException;
69 * Configuration class which interacts with the file etc/scinotesConfiguration.xml 69 * Configuration class which interacts with the file etc/scinotesConfiguration.xml
70 */ 70 */
71public final class ConfigSciNotesManager { 71public final class ConfigSciNotesManager {
72
73 public static final String RECENTBASEDIR = "recentBaseDir";
74 public static final String BASEDIR = "baseDir";
75 public static final String RECENTFILEPATTERN = "recentFilePattern";
76 public static final String FILEPATTERN = "filePattern";
77 public static final String RECENTWORDPATTERN = "recentWordPattern";
78 public static final String WORDPATTERN = "wordPattern";
79
72 private static final int BUFSIZE = 1024; 80 private static final int BUFSIZE = 1024;
73 81
74 private static final int MARGIN = 20; 82 private static final int MARGIN = 20;
@@ -119,6 +127,10 @@ public final class ConfigSciNotesManager {
119 private static final String SEARCH = "search"; 127 private static final String SEARCH = "search";
120 private static final String RECENT_REPLACE = "recentReplace"; 128 private static final String RECENT_REPLACE = "recentReplace";
121 private static final String REPLACE = "replace"; 129 private static final String REPLACE = "replace";
130 private static final String RECURSIVE = "recursiveSearch";
131 private static final String LINEBYLINE = "readLineByLine";
132 private static final String FILECASE = "fileCase";
133
122 private static final String EXPRESSION = "exp"; 134 private static final String EXPRESSION = "exp";
123 private static final String REGULAR_EXPRESION = "regularExp"; 135 private static final String REGULAR_EXPRESION = "regularExp";
124 private static final String CIRCULAR = "circularSearch"; 136 private static final String CIRCULAR = "circularSearch";
@@ -164,9 +176,7 @@ public final class ConfigSciNotesManager {
164 private static final int DEFAULT_WIDTH = 650; 176 private static final int DEFAULT_WIDTH = 650;
165 private static final int DEFAULT_HEIGHT = 550; 177 private static final int DEFAULT_HEIGHT = 550;
166 178
167 private static final int MAX_RECENT_FILES = 10; 179 private static final int MAXRECENT = 20;
168 private static final int MAX_RECENT_SEARCH = 20;
169 private static final int MAX_RECENT_REPLACE = 20;
170 180
171 private static Document document; 181 private static Document document;
172 private static Properties keysMap; 182 private static Properties keysMap;
@@ -1681,7 +1691,7 @@ public final class ConfigSciNotesManager {
1681 } 1691 }
1682 1692
1683 // if we have reached the maximun , we remove the oldest files 1693 // if we have reached the maximun , we remove the oldest files
1684 while (recentFiles.getLength() >= MAX_RECENT_FILES) { 1694 while (recentFiles.getLength() >= MAXRECENT) {
1685 root.removeChild(root.getFirstChild()); 1695 root.removeChild(root.getFirstChild());
1686 } 1696 }
1687 1697
@@ -2144,7 +2154,7 @@ public final class ConfigSciNotesManager {
2144 2154
2145 List<Node> search = getNodeChildren(recents, SEARCH); 2155 List<Node> search = getNodeChildren(recents, SEARCH);
2146 2156
2147 while (search.size() >= MAX_RECENT_SEARCH) { 2157 while (search.size() >= MAXRECENT) {
2148 removeRecentSearch(((Element) search.get(0)).getAttribute(EXPRESSION)); 2158 removeRecentSearch(((Element) search.get(0)).getAttribute(EXPRESSION));
2149 search = getNodeChildren(recents, SEARCH); 2159 search = getNodeChildren(recents, SEARCH);
2150 } 2160 }
@@ -2212,6 +2222,91 @@ public final class ConfigSciNotesManager {
2212 } 2222 }
2213 2223
2214 /** 2224 /**
2225 * Add a file to recent Opened Files
2226 * @param exp the path of the files to add
2227 */
2228 public static void saveRecent(String exp, String nodeName, String childNodeName) {
2229 Node root = getXcosRoot();
2230 if (root == null || exp == null || exp.compareTo("") == 0) {
2231 return;
2232 }
2233
2234 Node recents = getNodeChild(root, nodeName);
2235 if (recents == null) {
2236 recents = document.createElement(nodeName);
2237 root.appendChild(recents);
2238 }
2239
2240 List<Node> list = getNodeChildren(recents, childNodeName);
2241
2242 while (list.size() >= MAXRECENT) {
2243 removeRecent(((Element) list.get(0)).getAttribute(EXPRESSION), nodeName, childNodeName);
2244 list = getNodeChildren(recents, childNodeName);
2245 }
2246 //if path already in file no need to add it
2247 for (Node item : list) {
2248 if (exp.compareTo(((Element) item).getAttribute(EXPRESSION)) == 0) {
2249 return;
2250 }
2251 }
2252
2253 Element newNode = document.createElement(childNodeName);
2254 newNode.setAttribute(EXPRESSION, exp);
2255 recents.appendChild((Node) newNode);
2256
2257 clean(recents);
2258 writeDocument();
2259 }
2260
2261 /**
2262 * @param exp the expression to remove
2263 */
2264 public static void removeRecent(String exp, String nodeName, String childNodeName) {
2265 Node root = getXcosRoot();
2266 if (root == null) {
2267 return;
2268 }
2269
2270 Node recent = getNodeChild(root, nodeName);
2271 List<Node> list = getNodeChildren(recent, childNodeName);
2272
2273 // remove node if exists
2274 for (Node item : list) {
2275 if (exp.compareTo(((Element) item).getAttribute(EXPRESSION)) == 0) {
2276 recent.removeChild(item);
2277 break;
2278 }
2279 }
2280
2281 clean(recent);
2282 writeDocument();
2283 }
2284
2285 /**
2286 * @return a list of the recent searches
2287 */
2288 public static List<String> getRecent(String nodeName, String childNodeName) {
2289 List<String> files = new ArrayList<String>();
2290
2291 Node root = getXcosRoot();
2292 if (root == null) {
2293 return files;
2294 }
2295
2296 Node recent = getNodeChild(root, nodeName);
2297 List<Node> list = getNodeChildren(recent, childNodeName);
2298 for (Node node : list) {
2299 String exp = ((Element) node).getAttribute(EXPRESSION);
2300 if (exp != null && exp.compareTo("") != 0) {
2301 files.add(exp);
2302 }
2303 }
2304
2305 return files;
2306 }
2307
2308
2309 /**
2215 * @param exp the recent expression for a replacement 2310 * @param exp the recent expression for a replacement
2216 */ 2311 */
2217 public static void saveRecentReplace(String exp) { 2312 public static void saveRecentReplace(String exp) {
@@ -2228,7 +2323,7 @@ public final class ConfigSciNotesManager {
2228 2323
2229 List<Node> replace = getNodeChildren(recent, REPLACE); 2324 List<Node> replace = getNodeChildren(recent, REPLACE);
2230 2325
2231 while (replace.size() >= MAX_RECENT_REPLACE) { 2326 while (replace.size() >= MAXRECENT) {
2232 removeRecentReplace(((Element) replace.get(0)).getAttribute(EXPRESSION)); 2327 removeRecentReplace(((Element) replace.get(0)).getAttribute(EXPRESSION));
2233 replace = getNodeChildren(recent, REPLACE); 2328 replace = getNodeChildren(recent, REPLACE);
2234 } 2329 }
@@ -2326,6 +2421,48 @@ public final class ConfigSciNotesManager {
2326 } 2421 }
2327 2422
2328 /** 2423 /**
2424 * @return true for a recursive search
2425 */
2426 public static boolean getRecursive() {
2427 return getBooleanAttribute(RECURSIVE, STATE_FLAG, true);
2428 }
2429
2430 /**
2431 * @param recursive for a recursive search
2432 */
2433 public static void saveRecursive(boolean recursive) {
2434 saveBooleanAttribute(RECURSIVE, STATE_FLAG, recursive);
2435 }
2436
2437 /**
2438 * @return true for a line by line search
2439 */
2440 public static boolean getLineByLine() {
2441 return getBooleanAttribute(LINEBYLINE, STATE_FLAG, true);
2442 }
2443
2444 /**
2445 * @param lineByLine for a line by line search
2446 */
2447 public static void saveLineByLine(boolean lineByLine) {
2448 saveBooleanAttribute(LINEBYLINE, STATE_FLAG, lineByLine);
2449 }
2450
2451 /**
2452 * @return true for a case sensitive file name
2453 */
2454 public static boolean getFileCase() {
2455 return getBooleanAttribute(FILECASE, STATE_FLAG, false);
2456 }
2457
2458 /**
2459 * @param fileCase for a case sensitive file name
2460 */
2461 public static void saveFileCase(boolean fileCase) {
2462 saveBooleanAttribute(FILECASE, STATE_FLAG, fileCase);
2463 }
2464
2465 /**
2329 * @return true for a circular search 2466 * @return true for a circular search
2330 */ 2467 */
2331 public static boolean getCircularSearch() { 2468 public static boolean getCircularSearch() {
diff --git a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/SciNotesMessages.java b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/SciNotesMessages.java
index 557c2f8..35956e2 100644
--- a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/SciNotesMessages.java
+++ b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/SciNotesMessages.java
@@ -299,4 +299,30 @@ public class SciNotesMessages {
299 * Incremental search 299 * Incremental search
300 */ 300 */
301 public static final String EXACT = Messages.gettext("Exact"); 301 public static final String EXACT = Messages.gettext("Exact");
302
303 /**
304 * Find in files
305 */
306 public static final String SEARCHFILES = Messages.gettext("Search Files...");
307 public static final String SEARCHINFILES = Messages.gettext("Search in Files...");
308 public static final String MATCHES = Messages.gettext("<html>%s <i>(%s matches)</i></html>");
309 public static final String MATCH = Messages.gettext("<html>%s <i>(%s match)</i></html>");
310 public static final String ELAPSEDTIME = Messages.gettext("Elapsed time: %s seconds.");
311 public static final String ELAPSEDTIMELESSONESEC = Messages.gettext("Elapsed time: %s second.");
312 public static final String BASEDIRECTORY = Messages.gettext("Base directory:");
313 public static final String RECURSIVE = Messages.gettext("Recursive");
314 public static final String FILEPATTERN = Messages.gettext("File pattern");
315 public static final String FILEPATTERNEXP = Messages.gettext("(* for any string and ? for any character)");
316 public static final String WORDPATTERN = Messages.gettext("Word pattern");
317 public static final String FILELINEBYLINE = Messages.gettext("Read file line by line");
318 public static final String CHOOSEDIR = Messages.gettext("Choose...");
319 public static final String STOPBUTTON = Messages.gettext("Stop");
320 public static final String REGEXPATTERN = Messages.gettext("Regex");
321 public static final String WORD = Messages.gettext("Word");
322 public static final String WORDCASESENSITIVE = Messages.gettext("Case-sensitivity (Word)");
323 public static final String FILECASESENSITIVE = Messages.gettext("Case-sensitivity (File name)");
324 public static final String RECURSIVESEARCH = Messages.gettext("Recursive search");
325 public static final String LINEBYLINE = Messages.gettext("Line by line");
326 public static final String WORDREGEX = Messages.gettext("Regular expression (Word)");
327 public static final String CHOOSEBASEDIR = Messages.gettext("Choose the search base directory");
302} 328}
diff --git a/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/SearchFile.java b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/SearchFile.java
new file mode 100644
index 0000000..b5b9de2
--- /dev/null
+++ b/scilab/modules/scinotes/src/java/org/scilab/modules/scinotes/utils/SearchFile.java
@@ -0,0 +1,515 @@
1/*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2010 - Calixte DENIZET
4 *
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10 *
11 */
12
13package org.scilab.modules.scinotes.utils;
14
15import java.awt.Component;
16import java.awt.Dimension;
17import java.awt.event.ActionEvent;
18import java.awt.event.KeyEvent;
19import java.awt.event.KeyAdapter;
20import java.awt.event.MouseAdapter;
21import java.awt.event.MouseEvent;
22import java.awt.event.MouseListener;
23import java.io.File;
24import java.util.ArrayList;
25import java.util.List;
26import java.util.regex.Pattern;
27
28import javax.swing.ImageIcon;
29import javax.swing.JComponent;
30import javax.swing.JScrollPane;
31import javax.swing.JTree;
32import javax.swing.KeyStroke;
33import javax.swing.SwingUtilities;
34import javax.swing.event.TreeSelectionEvent;
35import javax.swing.event.TreeSelectionListener;
36import javax.swing.tree.DefaultMutableTreeNode;
37import javax.swing.tree.DefaultTreeCellRenderer;
38import javax.swing.tree.TreePath;
39import javax.swing.tree.TreeSelectionModel;
40
41import org.flexdock.docking.event.DockingEvent;
42import org.flexdock.docking.defaults.DockingSplitPane;
43
44import org.scilab.modules.gui.events.callback.CallBack;
45import org.scilab.modules.gui.window.ScilabWindow;
46import org.scilab.modules.gui.bridge.window.SwingScilabWindow;
47import org.scilab.modules.gui.window.Window;
48import org.scilab.modules.gui.tab.SimpleTab;
49import org.scilab.modules.gui.tab.Tab;
50import org.scilab.modules.gui.bridge.menuitem.SwingScilabMenuItem;
51import org.scilab.modules.gui.bridge.tab.SwingScilabTab;
52import org.scilab.modules.gui.menu.Menu;
53import org.scilab.modules.gui.menu.ScilabMenu;
54import org.scilab.modules.gui.menuitem.MenuItem;
55import org.scilab.modules.gui.menuitem.ScilabMenuItem;
56import org.scilab.modules.gui.menubar.MenuBar;
57import org.scilab.modules.gui.menubar.ScilabMenuBar;
58import org.scilab.modules.gui.toolbar.ToolBar;
59import org.scilab.modules.gui.textbox.ScilabTextBox;
60import org.scilab.modules.gui.textbox.TextBox;
61import org.scilab.modules.gui.utils.UIElementMapper;
62
63import org.scilab.modules.scinotes.ScilabEditorPane;
64import org.scilab.modules.scinotes.SciNotesGUI;
65import org.scilab.modules.scinotes.SciNotes;
66import org.scilab.modules.scinotes.SearchManager;
67
68/**
69 * Class SearchFile: open a window with a JTree to show the results of a search in files.
70 * @author Calixte DENIZET
71 */
72public class SearchFile extends SwingScilabTab implements Tab {
73
74 public static final String SEARCHDONE = "SearchFile.SearchDone";
75
76 private static SearchFile instance;
77
78 private Window parentWindow;
79 private SciNotes editor;
80
81 /**
82 * Default constructor
83 * @param editor the editor where to open a file
84 * @param title the window title
85 */
86 private SearchFile(SciNotes editor, String title) {
87 super(title);
88 this.editor = editor;
89 parentWindow = ScilabWindow.createWindow();
90 instance = this;
91 }
92
93 /**
94 * Get the parent window id for this tab
95 * @return the id of the parent window
96 */
97 public Window getParentWindow() {
98 return this.parentWindow;
99 }
100
101 /**
102 * {@inheritDoc}
103 */
104 public SimpleTab getAsSimpleTab() {
105 return this;
106 }
107
108 /**
109 * {@inheritDoc}
110 */
111 public void addInfoBar(TextBox infoBarToAdd) {
112 setInfoBar(infoBarToAdd);
113 }
114
115 /**
116 * {@inheritDoc}
117 */
118 public void addMenuBar(MenuBar menuBarToAdd) {
119 setMenuBar(menuBarToAdd);
120 }
121
122 /**
123 * {@inheritDoc}
124 */
125 public void addToolBar(ToolBar toolBarToAdd) {
126 setToolBar(toolBarToAdd);
127 }
128
129 /**
130 * {@inheritDoc}
131 */
132 public void dockingComplete(DockingEvent evt) {
133 super.dockingComplete(evt);
134 /* Trick to always have the editor's toolbar when the navigator
135 is docked in the editor */
136 if (evt.getNewDockingPort().getDockedComponent() instanceof DockingSplitPane) {
137 DockingSplitPane dsp = (DockingSplitPane) evt.getNewDockingPort().getDockedComponent();
138 if (dsp.getElderComponent() instanceof SciNotes) {
139 addToolBar(editor.getToolBar());
140 }
141 }
142 }
143
144 /**
145 * Close the current window if it exists
146 */
147 public static void closeCurrent() {
148 if (instance != null) {
149 instance.closeWindow();
150 }
151 }
152
153 /**
154 * Close the current window
155 */
156 public void closeWindow() {
157 ScilabWindow win = (ScilabWindow) UIElementMapper.getCorrespondingUIElement(getParentWindowId());
158 win.removeTab(this);
159 setVisible(false);
160 parentWindow = null;
161 instance = null;
162 close();
163 }
164
165 /**
166 * {@inheritDoc}
167 */
168 public void undockingComplete(DockingEvent evt) {
169 super.undockingComplete(evt);
170 addToolBar(null);
171 }
172
173 /**
174 * Get a JTree with the results of a search
175 * @param editor the editor where to open a file
176 * @param statusbar if non null the status bar where to write file info
177 * @param base the base directory
178 * @param recursive, if true then a recursive search is made
179 * @param ignoreCR, if true then the read file is considered as one line and regex pattern can include \n
180 * @param filePattern the pattern to use to select the files. * is equivalent to .* and ? to .?
181 * @param fileCaseSensitive, if true then the file pattern is case sensitive
182 * @param wordPattern the pattern of the word to search
183 * @param wordCaseSensitive, if true then the word pattern is case sensitive
184 * @param wholeWord, if true only whole word will be matched, e.g. in "foobar foo bar", if the pattern is "foo", then only the second "foo" will be matched
185 * @param regexp, if true the word pattern is considered as a regex
186 * @return the corresponding JTree
187 */
188 public static JTree getJTree(SearchManager.MatchingPositions files, final SciNotes editor, final TextBox statusbar,
189 String base, boolean recursive, boolean ignoreCR,
190 String filePattern, boolean fileCaseSensitive,
191 String wordPattern, boolean wordCaseSensitive, boolean wholeWord, boolean regexp) {
192 if (files == null) {
193 List<SearchManager.MatchingPositions> list = new ArrayList<SearchManager.MatchingPositions>();
194 files = new SearchManager.MatchingPositions(new File(base).getAbsolutePath(), list);
195 files.setRoot();
196 }
197
198 Pattern word = null;
199 if (wordPattern != null && wordPattern.length() != 0) {
200 word = SearchManager.generatePattern(wordPattern, wordCaseSensitive, wholeWord, regexp);
201 }
202 final Pattern p = word;
203
204 files.setRoot();
205 final JTree tree = new JTree(files.toDefaultMutableTreeNode());
206 MouseListener ml = new MouseAdapter() {
207 public void mousePressed(MouseEvent e) {
208 int row = tree.getRowForLocation(e.getX(), e.getY());
209 if(row != -1) {
210 if (e.getClickCount() == 2) {
211 validNode(editor, p, tree.getPathForRow(row));
212 }
213 }
214 }
215 };
216 tree.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "toggle");
217 tree.addKeyListener(new KeyAdapter() {
218 public void keyTyped(KeyEvent e) {
219 if (e.getKeyChar() == '\n') {
220 int row = tree.getMinSelectionRow();
221 if (row != -1) {
222 validNode(editor, p, tree.getPathForRow(row));
223 }
224 }
225 }
226 });
227 tree.addMouseListener(ml);
228 DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer() {
229 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected,
230 boolean expanded, boolean leaf, int row, boolean hasFocus) {
231 super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
232 DefaultMutableTreeNode mtn = (DefaultMutableTreeNode) value;
233 SearchManager.Iconable pos = (SearchManager.Iconable) mtn.getUserObject();
234 this.setIcon(pos.getIcon());
235 return this;
236 }
237 };
238 if (statusbar != null) {
239 tree.addTreeSelectionListener(new TreeSelectionListener() {
240 public void valueChanged(TreeSelectionEvent e) {
241 TreePath path = e.getNewLeadSelectionPath();
242 Object userObj = ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject();
243 if (userObj instanceof SearchManager.MatchingPositions) {
244 statusbar.setText(((SearchManager.MatchingPositions) userObj).getFileName());
245 } else if (userObj instanceof SearchManager.Line) {
246 userObj = ((DefaultMutableTreeNode) ((DefaultMutableTreeNode) path.getLastPathComponent()).getParent()).getUserObject();
247 statusbar.setText(((SearchManager.MatchingPositions) userObj).getFileName());
248 }
249 }
250 });
251 }
252 tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
253 tree.setCellRenderer(renderer);
254
255 return tree;
256 }
257
258 /**
259 * Display a window containing the results of the search.
260 * @param component the component which start the search. It is prevented that search is done via a firePropertyChange (SEARCHDONE).
261 * @param editor the editor where to open a file
262 * @param base the base directory
263 * @param recursive, if true then a recursive search is made
264 * @param ignoreCR, if true then the read file is considered as one line and regex pattern can include \n
265 * @param filePattern the pattern to use to select the files. * is equivalent to .* and ? to .?
266 * @param fileCaseSensitive, if true then the file pattern is case sensitive
267 * @param wordPattern the pattern of the word to search
268 * @param wordCaseSensitive, if true then the word pattern is case sensitive
269 * @param wholeWord, if true only whole word will be matched, e.g. in "foobar foo bar", if the pattern is "foo", then only the second "foo" will be matched
270 * @param regexp, if true the word pattern is considered as a regex
271 * @return a key, can be used to stop the search
272 */
273 public static Object getSearchResultsWindow(JComponent component, SciNotes editor, String base,
274 boolean recursive, boolean ignoreCR,
275 String filePattern, boolean fileCaseSensitive,
276 String wordPattern, boolean wordCaseSensitive, boolean wholeWord, boolean regexp) {
277 MyBackgroundSearch searcher = new MyBackgroundSearch();
278 searcher.start(component, editor, base, recursive, ignoreCR, filePattern, fileCaseSensitive, wordPattern, wordCaseSensitive, wholeWord, regexp);
279 return searcher;
280 }
281
282 /**
283 * Stop the current search
284 * @param searcher the key returned by getSearchResultsWindow
285 */
286 public static void stopSearch(Object searcher) {
287 if (searcher != null && (searcher instanceof MyBackgroundSearch)) {
288 ((MyBackgroundSearch) searcher).stop();
289 }
290 }
291
292 /**
293 * Stop the current search
294 * @param searcher the key returned by getSearchResultsWindow
295 */
296 public static boolean isDone(Object searcher) {
297 if (searcher != null && (searcher instanceof MyBackgroundSearch)) {
298 return ((MyBackgroundSearch) searcher).isDone();
299 }
300 return true;
301 }
302
303 /**
304 * If the user hits ENTER key or double-click on a node, the corresponding file is open in SciNotes.
305 * @param editor the editor where to open the file
306 * @param the word pattern used
307 * @param path the path of the node
308 */
309 private static void validNode(SciNotes editor, final Pattern pat, TreePath path) {
310 DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
311 Object userObj = node.getUserObject();
312 int lineNumber = -1;
313 String fileName = null;
314 boolean line = false;
315 if (userObj instanceof SearchManager.MatchingPositions) {
316 SearchManager.MatchingPositions pos = (SearchManager.MatchingPositions) userObj;
317 lineNumber = 0;
318 if (!pos.isDirectory()) {
319 fileName = pos.getFileName();
320 }
321 } else if (userObj instanceof SearchManager.Line) {
322 SearchManager.Line l = (SearchManager.Line) userObj;
323 lineNumber = l.getNumber();
324 fileName = ((SearchManager.MatchingPositions) ((DefaultMutableTreeNode) node.getParent()).getUserObject()).getFileName();
325 line = true;
326 }
327
328 if (fileName != null) {
329 final boolean fline = !line;
330 final int ln = lineNumber;
331 if (lineNumber != -1) {
332 editor.openFile(fileName, 0, null);
333 final ScilabEditorPane sep = editor.getTextPane();
334 if (sep.getName().equals(fileName)) {
335 SwingUtilities.invokeLater(new Runnable() {
336 public void run() {
337 sep.highlightWords(pat, fline);
338 if (ln != 0) {
339 sep.scrollTextToLineNumber(ln, false, false, true);
340 }
341 }
342 });
343 }
344 }
345 }
346 }
347
348 /**
349 * Inner class to allow the make the search as a background task (with a SwingWorker).
350 * The task does not block SciNotes and can be killed by the user.
351 */
352 private static class MyBackgroundSearch extends SearchManager.BackgroundSearch {
353
354 SciNotes editor;
355 JComponent component;
356 String base;
357 boolean recursive;
358 boolean ignoreCR;
359 String filePattern;
360 boolean fileCaseSensitive;
361 String wordPattern;
362 boolean wordCaseSensitive;
363 boolean wholeWord;
364 boolean regexp;
365
366 /**
367 * Default constructor
368 */
369 public MyBackgroundSearch() {
370 super();
371 }
372
373 /**
374 * Starts the search
375 * @param component the component which start the search. It is prevented that search is done via a firePropertyChange (SEARCHDONE).
376 * @param editor the editor where to open a file
377 * @param base the base directory
378 * @param recursive, if true then a recursive search is made
379 * @param ignoreCR, if true then the read file is considered as one line and regex pattern can include \n
380 * @param filePattern the pattern to use to select the files. * is equivalent to .* and ? to .?
381 * @param fileCaseSensitive, if true then the file pattern is case sensitive
382 * @param wordPattern the pattern of the word to search
383 * @param wordCaseSensitive, if true then the word pattern is case sensitive
384 * @param wholeWord, if true only whole word will be matched, e.g. in "foobar foo bar", if the pattern is "foo", then only the second "foo" will be matched
385 * @param regexp, if true the word pattern is considered as a regex
386 */
387 synchronized public void start(JComponent component, SciNotes editor, String base, boolean recursive, boolean ignoreCR,
388 String filePattern, boolean fileCaseSensitive,
389 String wordPattern, boolean wordCaseSensitive, boolean wholeWord, boolean regexp) {
390 this.component = component;
391 this.editor = editor;
392 this.base = base;
393 this.recursive = recursive;
394 this.ignoreCR = ignoreCR;
395 this.filePattern = filePattern;
396 this.fileCaseSensitive = fileCaseSensitive;
397 this.wordPattern = wordPattern;
398 this.wordCaseSensitive = wordCaseSensitive;
399 this.wholeWord = wholeWord;
400 this.regexp = regexp;
401 SearchManager.searchInFiles(this, base, recursive, ignoreCR, filePattern, fileCaseSensitive, wordPattern, wordCaseSensitive, wholeWord, regexp);
402 }
403
404 /**
405 * Stop the search and fire a propertyChange
406 */
407 synchronized public void stop() {
408 super.stop();
409 if (component != null) {
410 component.firePropertyChange(SEARCHDONE, false, true);
411 }
412 }
413
414 /**
415 * Called when the results are available
416 */
417 synchronized public void done() {
418 SearchManager.MatchingPositions pos = getResults();
419 if (pos == null) {
420 return;
421 }
422
423 final TextBox infobar = ScilabTextBox.createTextBox();
424 final JTree tree = getJTree(pos, editor, infobar, base, recursive, ignoreCR, filePattern, fileCaseSensitive, wordPattern, wordCaseSensitive, wholeWord, regexp);
425
426 SearchFile tab;
427 String title;
428 boolean preexist = SearchFile.instance != null;
429 if (wordPattern == null || wordPattern.isEmpty()) {
430 title = SciNotesMessages.SEARCHFILES;
431 } else {
432 title = SciNotesMessages.SEARCHINFILES;
433 }
434
435 title += " " + SciNotesMessages.FILEPATTERN + ": " + filePattern;
436 title += ", " + SciNotesMessages.FILECASESENSITIVE + ": " + fileCaseSensitive;
437 title += ", " + SciNotesMessages.RECURSIVE + ": " + recursive;
438 if (wordPattern != null && !wordPattern.isEmpty()) {
439 title += ", " + SciNotesMessages.LINEBYLINE + ": " + !ignoreCR;
440 if (regexp) {
441 title += ", " + SciNotesMessages.REGEXPATTERN + ": " + wordPattern;
442 } else {
443 title += ", " + SciNotesMessages.WORD + ": " + wordPattern;
444 }
445 title += ", " + SciNotesMessages.WORDCASESENSITIVE + ": " + wordCaseSensitive;
446 title += ", " + SciNotesMessages.WHOLE_WORD + ": " + wholeWord;
447 }
448
449 Window parentWindow;
450
451 if (!preexist) {
452 tab = new SearchFile(editor, title);
453 parentWindow = tab.getParentWindow();
454 parentWindow.setTitle(title);
455 parentWindow.addTab(tab);
456 tab.setWindowIcon(new ImageIcon(System.getenv("SCI") + "/modules/gui/images/icons/32x32/apps/system-search.png").getImage());
457 } else {
458 tab = instance;
459 parentWindow = tab.getParentWindow();
460 }
461
462 tab.updateUI();
463
464 final SearchFile ftab = tab;
465 CallBack callback = new CallBack(null) {
466 public void callBack() {
467 ftab.closeCurrent();
468 }
469
470 public void actionPerformed(ActionEvent e) {
471 callBack();
472 }
473 };
474
475 tab.setCallback(callback);
476 MenuBar menubar = ScilabMenuBar.createMenuBar();
477 Menu fileMenu = ScilabMenu.createMenu();
478 fileMenu.setText(SciNotesMessages.FILE);
479 fileMenu.setMnemonic('F');
480 MenuItem menu = ScilabMenuItem.createMenuItem();
481 menu.setCallback(callback);
482 ((SwingScilabMenuItem) menu.getAsSimpleMenuItem()).setAccelerator(SciNotesGUI.getActionKeyMap().get("ExitAction"));
483 menu.setText(SciNotesMessages.EXIT);
484 fileMenu.add(menu);
485 menubar.add(fileMenu);
486
487 tab.addMenuBar(menubar);
488 tab.addInfoBar(infobar);
489
490 JScrollPane scrollpane = new JScrollPane();
491 scrollpane.setViewportView(tree);
492 tab.setContentPane(scrollpane);
493
494 if (!preexist) {
495 tab.setPreferredSize(new Dimension(650, 250));
496 ((SwingScilabWindow) parentWindow.getAsSimpleWindow()).pack();
497 ((SwingScilabWindow) parentWindow.getAsSimpleWindow()).setVisible(true);
498 }
499
500 SwingUtilities.invokeLater(new Runnable() {
501 public void run() {
502 tree.addSelectionRow(0);
503 tree.requestFocus();
504 long time = getElapsedTime();
505 String msg = (time <= 1000) ? SciNotesMessages.ELAPSEDTIMELESSONESEC : SciNotesMessages.ELAPSEDTIME;
506 infobar.setText(String.format(msg, ((double) time) / 1000));
507 }
508 });
509
510 if (component != null) {
511 component.firePropertyChange(SEARCHDONE, false, true);
512 }
513 }
514 }
515}