From 461bb7450314b50ae946a5bf71efb66159fe03d8 Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Tue, 10 Feb 2026 16:50:04 +0100 Subject: [PATCH] added new options to file search --- .../kfmanager/service/FileOperations.java | 10 +- .../cz/kamma/kfmanager/ui/FileEditor.java | 152 ++++++++++++++---- .../cz/kamma/kfmanager/ui/SearchDialog.java | 29 +++- 3 files changed, 154 insertions(+), 37 deletions(-) diff --git a/src/main/java/cz/kamma/kfmanager/service/FileOperations.java b/src/main/java/cz/kamma/kfmanager/service/FileOperations.java index 67c1d43..6c87ba0 100644 --- a/src/main/java/cz/kamma/kfmanager/service/FileOperations.java +++ b/src/main/java/cz/kamma/kfmanager/service/FileOperations.java @@ -656,7 +656,7 @@ public class FileOperations { * Search files by filename pattern and/or content text. * If both are provided, both must match. */ - public static void search(File directory, String filenamePattern, String contentText, boolean recursive, boolean searchArchives, SearchCallback callback) throws IOException { + public static void search(File directory, String filenamePattern, String contentText, boolean recursive, boolean searchArchives, boolean wholeWord, boolean caseSensitive, SearchCallback callback) throws IOException { Pattern filenameRegex = null; String filenameLower = null; if (filenamePattern != null && !filenamePattern.isEmpty()) { @@ -672,7 +672,13 @@ public class FileOperations { Pattern contentPattern = null; if (contentText != null && !contentText.isEmpty()) { - contentPattern = Pattern.compile(Pattern.quote(contentText), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); + String quote = Pattern.quote(contentText); + String regex = wholeWord ? "(? findNext()); + wholeWordCheckBox = new JCheckBox("Whole word"); + caseSensitiveCheckBox = new JCheckBox("Case sensitive"); + JButton nextBtn = new JButton("Next"); nextBtn.addActionListener(e -> findNext()); @@ -118,6 +133,8 @@ public class FileEditor extends JFrame { searchPanel.add(new JLabel("Search:")); searchPanel.add(searchField); + searchPanel.add(wholeWordCheckBox); + searchPanel.add(caseSensitiveCheckBox); searchPanel.add(nextBtn); searchPanel.add(prevBtn); searchPanel.add(closeBtn); @@ -128,6 +145,8 @@ public class FileEditor extends JFrame { private void showSearchPanel(boolean focusField) { searchPanel.setVisible(true); + wholeWordCheckBox.setSelected(lastWholeWord); + caseSensitiveCheckBox.setSelected(lastCaseSensitive); String selection = textArea.getSelectedText(); if (selection != null && !selection.isEmpty() && !selection.contains("\n")) { searchField.setText(selection); @@ -171,7 +190,10 @@ public class FileEditor extends JFrame { String text = searchField.getText(); if (text.isEmpty()) text = lastSearchValue; if (text == null || text.isEmpty()) return; + lastSearchValue = text; + lastWholeWord = wholeWordCheckBox.isSelected(); + lastCaseSensitive = caseSensitiveCheckBox.isSelected(); updateSearchHistory(text); if (searchField.getText().isEmpty()) searchField.setText(text); @@ -181,64 +203,132 @@ public class FileEditor extends JFrame { // If we have a selection that matches, start after it if (textArea.getSelectionEnd() > textArea.getSelectionStart()) { - if (content.substring(textArea.getSelectionStart(), textArea.getSelectionEnd()).equalsIgnoreCase(text)) { + String selected = content.substring(textArea.getSelectionStart(), textArea.getSelectionEnd()); + boolean match; + if (lastCaseSensitive) { + match = selected.equals(text); + } else { + match = selected.equalsIgnoreCase(text); + } + if (match) { start = textArea.getSelectionEnd(); } } - int idx = content.toLowerCase().indexOf(text.toLowerCase(), start); - if (idx == -1) { - // wrap around - idx = content.toLowerCase().indexOf(text.toLowerCase(), 0); + String quote = Pattern.quote(text); + String regex = lastWholeWord ? "(? { + dialog.dispose(); + }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + + dialog.setVisible(true); + } + private void findPrevious() { String text = searchField.getText(); if (text.isEmpty()) text = lastSearchValue; if (text == null || text.isEmpty()) return; + lastSearchValue = text; + lastWholeWord = wholeWordCheckBox.isSelected(); + lastCaseSensitive = caseSensitiveCheckBox.isSelected(); updateSearchHistory(text); if (searchField.getText().isEmpty()) searchField.setText(text); String content = textArea.getText(); - int start = textArea.getSelectionStart() - 1; - if (start < 0) start = content.length() - 1; + int start = textArea.getSelectionStart(); + if (start < 0) start = content.length(); - int idx = content.toLowerCase().lastIndexOf(text.toLowerCase(), start); - if (idx == -1) { - // wrap around - idx = content.toLowerCase().lastIndexOf(text.toLowerCase(), content.length() - 1); + String quote = Pattern.quote(text); + String regex = lastWholeWord ? "(? hist = new java.util.ArrayList<>(config.getContentSearchHistory()); diff --git a/src/main/java/cz/kamma/kfmanager/ui/SearchDialog.java b/src/main/java/cz/kamma/kfmanager/ui/SearchDialog.java index 725c19c..fc397ee 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/SearchDialog.java +++ b/src/main/java/cz/kamma/kfmanager/ui/SearchDialog.java @@ -23,6 +23,8 @@ public class SearchDialog extends JDialog { private JCheckBox recursiveCheckBox; private JCheckBox contentSearchCheckBox; private JCheckBox archiveSearchCheckBox; + private JCheckBox wholeWordCheckBox; + private JCheckBox caseSensitiveCheckBox; private JTable resultsTable; private ResultsTableModel tableModel; private JButton searchButton; @@ -175,17 +177,30 @@ public class SearchDialog extends JDialog { contentPatternCombo.setToolTipText("Text to search inside files"); searchPanel.add(contentPatternCombo, gbc); + gbc.gridx = 0; gbc.gridy = 3; gbc.gridwidth = 2; contentSearchCheckBox = new JCheckBox("Search inside file contents", false); searchPanel.add(contentSearchCheckBox, gbc); + gbc.gridx = 0; gbc.gridy = 4; + gbc.gridwidth = 1; + wholeWordCheckBox = new JCheckBox("Whole word only", false); + searchPanel.add(wholeWordCheckBox, gbc); + + gbc.gridx = 1; + caseSensitiveCheckBox = new JCheckBox("Case sensitive", false); + searchPanel.add(caseSensitiveCheckBox, gbc); + + gbc.gridx = 0; + gbc.gridy = 5; + gbc.gridwidth = 2; archiveSearchCheckBox = new JCheckBox("Search inside archives", false); archiveSearchCheckBox.setMnemonic(KeyEvent.VK_R); searchPanel.add(archiveSearchCheckBox, gbc); - gbc.gridy = 5; + gbc.gridy = 6; JLabel pathLabel = new JLabel("Directory: " + searchDirectory.getAbsolutePath()); pathLabel.setFont(pathLabel.getFont().deriveFont(Font.ITALIC)); searchPanel.add(pathLabel, gbc); @@ -543,6 +558,8 @@ public class SearchDialog extends JDialog { final String finalNamePat = namePat; final String finalContentPat = isContentSearch ? contentPat : null; final boolean searchArchives = archiveSearchCheckBox != null && archiveSearchCheckBox.isSelected(); + final boolean wholeWord = wholeWordCheckBox != null && wholeWordCheckBox.isSelected(); + final boolean caseSensitive = caseSensitiveCheckBox != null && caseSensitiveCheckBox.isSelected(); // Reset and show status foundCount = 0; @@ -556,7 +573,7 @@ public class SearchDialog extends JDialog { @Override protected Void doInBackground() throws Exception { - FileOperations.search(searchDirectory, finalNamePat, finalContentPat, recursiveCheckBox.isSelected(), searchArchives, new FileOperations.SearchCallback() { + FileOperations.search(searchDirectory, finalNamePat, finalContentPat, recursiveCheckBox.isSelected(), searchArchives, wholeWord, caseSensitive, new FileOperations.SearchCallback() { @Override public void onFileFound(File file, String virtualPath) { publish(new Object[]{"file", file, virtualPath}); @@ -701,7 +718,9 @@ public class SearchDialog extends JDialog { contentPat = cit != null ? cit.toString().trim() : ""; } catch (Exception ex) {} if (!contentPat.isEmpty()) { - FileEditor.setLastSearchValue(contentPat); + FileEditor.setLastSearchOptions(contentPat, + wholeWordCheckBox != null && wholeWordCheckBox.isSelected(), + caseSensitiveCheckBox != null && caseSensitiveCheckBox.isSelected()); } FileEditor viewer = new FileEditor(owner, item.getFile(), vPath, config, true); @@ -745,7 +764,9 @@ public class SearchDialog extends JDialog { contentPat = cit != null ? cit.toString().trim() : ""; } catch (Exception ex) {} if (!contentPat.isEmpty()) { - FileEditor.setLastSearchValue(contentPat); + FileEditor.setLastSearchOptions(contentPat, + wholeWordCheckBox != null && wholeWordCheckBox.isSelected(), + caseSensitiveCheckBox != null && caseSensitiveCheckBox.isSelected()); } FileEditor editor = new FileEditor(owner, item.getFile(), config, false);