search results fixed
This commit is contained in:
parent
9b6b309bfe
commit
6854693492
@ -7,7 +7,6 @@ import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.*;
|
||||
|
||||
@ -493,57 +492,57 @@ public class FileOperations {
|
||||
}
|
||||
|
||||
/**
|
||||
* Search files by pattern
|
||||
* Search files by filename pattern and/or content text.
|
||||
* If both are provided, both must match.
|
||||
*/
|
||||
public static void search(File directory, String pattern, boolean recursive, boolean searchArchives, SearchCallback callback) throws IOException {
|
||||
if (pattern == null) return;
|
||||
// Prepare a compiled regex if the pattern contains wildcards to avoid recompiling per-file
|
||||
public static void search(File directory, String filenamePattern, String contentText, boolean recursive, boolean searchArchives, SearchCallback callback) throws IOException {
|
||||
Pattern filenameRegex = null;
|
||||
if (pattern.contains("*") || pattern.contains("?")) {
|
||||
String regex = pattern
|
||||
String filenameLower = null;
|
||||
if (filenamePattern != null && !filenamePattern.isEmpty()) {
|
||||
filenameLower = filenamePattern.toLowerCase();
|
||||
if (filenamePattern.contains("*") || filenamePattern.contains("?")) {
|
||||
String regex = filenamePattern
|
||||
.replace(".", "\\.")
|
||||
.replace("*", ".*")
|
||||
.replace("?", ".");
|
||||
filenameRegex = Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
|
||||
}
|
||||
searchRecursive(directory.toPath(), pattern.toLowerCase(), filenameRegex, recursive, searchArchives, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search file contents for a text fragment (case-insensitive).
|
||||
* Calls callback.onFileFound(file) when a file contains the text.
|
||||
*/
|
||||
public static void searchContents(File directory, String text, boolean recursive, boolean searchArchives, SearchCallback callback) throws IOException {
|
||||
if (text == null) return;
|
||||
// Precompile a case-insensitive pattern for content search to avoid per-line lowercasing
|
||||
Pattern contentPattern = Pattern.compile(Pattern.quote(text), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
|
||||
searchContentsRecursive(directory.toPath(), contentPattern, recursive, searchArchives, callback);
|
||||
Pattern contentPattern = null;
|
||||
if (contentText != null && !contentText.isEmpty()) {
|
||||
contentPattern = Pattern.compile(Pattern.quote(contentText), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
|
||||
}
|
||||
|
||||
private static void searchRecursive(Path directory, String patternLower, Pattern filenameRegex, boolean recursive, boolean searchArchives, SearchCallback callback) throws IOException {
|
||||
searchRecursive(directory.toPath(), filenameLower, filenameRegex, contentPattern, recursive, searchArchives, callback);
|
||||
}
|
||||
|
||||
private static void searchRecursive(Path directory, String patternLower, Pattern filenameRegex, Pattern contentPattern, boolean recursive, boolean searchArchives, SearchCallback callback) throws IOException {
|
||||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory)) {
|
||||
for (Path entry : stream) {
|
||||
if (Files.isDirectory(entry)) {
|
||||
if (recursive) {
|
||||
searchRecursive(entry, patternLower, filenameRegex, recursive, searchArchives, callback);
|
||||
searchRecursive(entry, patternLower, filenameRegex, contentPattern, recursive, searchArchives, callback);
|
||||
}
|
||||
} else {
|
||||
File file = entry.toFile();
|
||||
String fileName = file.getName();
|
||||
String fileNameLower = fileName.toLowerCase();
|
||||
boolean matched = false;
|
||||
if (fileNameLower.contains(patternLower)) matched = true;
|
||||
else if (filenameRegex != null) {
|
||||
Matcher m = filenameRegex.matcher(fileName);
|
||||
if (m.matches()) matched = true;
|
||||
boolean nameMatched = true;
|
||||
if (patternLower != null && !patternLower.isEmpty()) {
|
||||
nameMatched = matchName(file.getName(), patternLower, filenameRegex);
|
||||
}
|
||||
if (matched) {
|
||||
|
||||
boolean contentMatched = true;
|
||||
if (nameMatched && contentPattern != null) {
|
||||
contentMatched = fileMatchesContent(entry, contentPattern);
|
||||
}
|
||||
|
||||
if (nameMatched && contentMatched) {
|
||||
callback.onFileFound(file, null);
|
||||
}
|
||||
|
||||
// SEARCH IN ARCHIVES
|
||||
if (searchArchives && isArchiveFile(file)) {
|
||||
searchInArchive(file, fileNameLower, filenameRegex, callback);
|
||||
searchInArchiveCombined(file, patternLower, filenameRegex, contentPattern, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -552,39 +551,99 @@ public class FileOperations {
|
||||
}
|
||||
}
|
||||
|
||||
private static void searchContentsRecursive(Path directory, Pattern contentPattern, boolean recursive, boolean searchArchives, SearchCallback callback) throws IOException {
|
||||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory)) {
|
||||
for (Path entry : stream) {
|
||||
if (Files.isDirectory(entry)) {
|
||||
if (recursive) {
|
||||
searchContentsRecursive(entry, contentPattern, recursive, searchArchives, callback);
|
||||
private static boolean matchName(String name, String patternLower, Pattern filenameRegex) {
|
||||
String nameLower = name.toLowerCase();
|
||||
if (nameLower.contains(patternLower)) return true;
|
||||
if (filenameRegex != null) {
|
||||
return filenameRegex.matcher(name).matches();
|
||||
}
|
||||
} else {
|
||||
File file = entry.toFile();
|
||||
// Try reading file as text line-by-line and search for pattern (case-insensitive via compiled Pattern)
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean fileMatchesContent(Path entry, Pattern contentPattern) {
|
||||
try (BufferedReader br = Files.newBufferedReader(entry)) {
|
||||
String line;
|
||||
boolean found = false;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (contentPattern.matcher(line).find()) {
|
||||
found = true;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (found) callback.onFileFound(file, null);
|
||||
} catch (IOException ex) {
|
||||
// Skip files that cannot be read as text
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// SEARCH IN ARCHIVES CONTENTS
|
||||
if (searchArchives && isArchiveFile(file)) {
|
||||
searchContentsInArchive(file, contentPattern, callback);
|
||||
/**
|
||||
* Reads the content of a file from an archive.
|
||||
*/
|
||||
public static byte[] readFileFromArchive(File archive, String entryPath) throws IOException {
|
||||
String name = archive.getName().toLowerCase();
|
||||
try {
|
||||
if (name.endsWith(".zip") || name.endsWith(".jar")) {
|
||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(archive))) {
|
||||
ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (entry.getName().equals(entryPath) || (archive.getAbsolutePath() + File.separator + entry.getName()).equals(entryPath)) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[24576];
|
||||
int len;
|
||||
while ((len = zis.read(buffer)) > 0) {
|
||||
baos.write(buffer, 0, len);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (AccessDeniedException e) {
|
||||
// Ignore directories without access
|
||||
} else if (name.endsWith(".tar.gz") || name.endsWith(".tgz") || name.endsWith(".tar")) {
|
||||
InputStream is = new FileInputStream(archive);
|
||||
if (name.endsWith(".gz") || name.endsWith(".tgz")) {
|
||||
is = new org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream(is);
|
||||
}
|
||||
try (org.apache.commons.compress.archivers.tar.TarArchiveInputStream tais = new org.apache.commons.compress.archivers.tar.TarArchiveInputStream(is)) {
|
||||
org.apache.commons.compress.archivers.tar.TarArchiveEntry entry;
|
||||
while ((entry = tais.getNextTarEntry()) != null) {
|
||||
if (entry.getName().equals(entryPath) || (archive.getAbsolutePath() + File.separator + entry.getName()).equals(entryPath)) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[24576];
|
||||
int len;
|
||||
while ((len = tais.read(buffer)) > 0) {
|
||||
baos.write(buffer, 0, len);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (name.endsWith(".7z")) {
|
||||
try (org.apache.commons.compress.archivers.sevenz.SevenZFile sevenZFile = new org.apache.commons.compress.archivers.sevenz.SevenZFile(archive)) {
|
||||
org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry entry;
|
||||
while ((entry = sevenZFile.getNextEntry()) != null) {
|
||||
if (entry.getName().equals(entryPath) || (archive.getAbsolutePath() + File.separator + entry.getName()).equals(entryPath)) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[24576];
|
||||
int len;
|
||||
while ((len = sevenZFile.read(buffer)) > 0) {
|
||||
baos.write(buffer, 0, len);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (name.endsWith(".rar")) {
|
||||
try (com.github.junrar.Archive rar = new com.github.junrar.Archive(archive)) {
|
||||
for (com.github.junrar.rarfile.FileHeader fh : rar.getFileHeaders()) {
|
||||
if (fh.getFileName().equals(entryPath) || (archive.getAbsolutePath() + File.separator + fh.getFileName()).equals(entryPath)) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
rar.extractFile(fh, baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Failed to read from archive: " + e.getMessage(), e);
|
||||
}
|
||||
throw new IOException("Entry not found in archive: " + entryPath);
|
||||
}
|
||||
|
||||
private static boolean isArchiveFile(File f) {
|
||||
@ -593,18 +652,28 @@ public class FileOperations {
|
||||
return n.endsWith(".zip") || n.endsWith(".jar") || n.endsWith(".tar") || n.endsWith(".tar.gz") || n.endsWith(".tgz") || n.endsWith(".7z") || n.endsWith(".rar");
|
||||
}
|
||||
|
||||
private static void searchInArchive(File archive, String patternLower, Pattern filenameRegex, SearchCallback callback) {
|
||||
private static void searchInArchiveCombined(File archive, String patternLower, Pattern filenameRegex, Pattern contentPattern, SearchCallback callback) {
|
||||
String name = archive.getName().toLowerCase();
|
||||
try {
|
||||
if (name.endsWith(".zip") || name.endsWith(".jar")) {
|
||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(archive))) {
|
||||
ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (matchEntry(entry.getName(), patternLower, filenameRegex)) {
|
||||
if (!entry.isDirectory()) {
|
||||
boolean nameMatched = true;
|
||||
if (patternLower != null && !patternLower.isEmpty()) {
|
||||
nameMatched = matchEntry(entry.getName(), patternLower, filenameRegex);
|
||||
}
|
||||
boolean contentMatched = true;
|
||||
if (nameMatched && contentPattern != null) {
|
||||
contentMatched = searchInStream(zis, contentPattern);
|
||||
}
|
||||
if (nameMatched && contentMatched) {
|
||||
callback.onFileFound(archive, archive.getAbsolutePath() + File.separator + entry.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (name.endsWith(".tar.gz") || name.endsWith(".tgz") || name.endsWith(".tar")) {
|
||||
InputStream is = new FileInputStream(archive);
|
||||
if (name.endsWith(".gz") || name.endsWith(".tgz")) {
|
||||
@ -613,64 +682,33 @@ public class FileOperations {
|
||||
try (org.apache.commons.compress.archivers.tar.TarArchiveInputStream tais = new org.apache.commons.compress.archivers.tar.TarArchiveInputStream(is)) {
|
||||
org.apache.commons.compress.archivers.tar.TarArchiveEntry entry;
|
||||
while ((entry = tais.getNextTarEntry()) != null) {
|
||||
if (matchEntry(entry.getName(), patternLower, filenameRegex)) {
|
||||
if (!entry.isDirectory()) {
|
||||
boolean nameMatched = true;
|
||||
if (patternLower != null && !patternLower.isEmpty()) {
|
||||
nameMatched = matchEntry(entry.getName(), patternLower, filenameRegex);
|
||||
}
|
||||
boolean contentMatched = true;
|
||||
if (nameMatched && contentPattern != null) {
|
||||
contentMatched = searchInStream(tais, contentPattern);
|
||||
}
|
||||
if (nameMatched && contentMatched) {
|
||||
callback.onFileFound(archive, archive.getAbsolutePath() + File.separator + entry.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (name.endsWith(".7z")) {
|
||||
try (org.apache.commons.compress.archivers.sevenz.SevenZFile sevenZFile = new org.apache.commons.compress.archivers.sevenz.SevenZFile(archive)) {
|
||||
org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry entry;
|
||||
while ((entry = sevenZFile.getNextEntry()) != null) {
|
||||
if (matchEntry(entry.getName(), patternLower, filenameRegex)) {
|
||||
callback.onFileFound(archive, archive.getAbsolutePath() + File.separator + entry.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (name.endsWith(".rar")) {
|
||||
try (com.github.junrar.Archive rar = new com.github.junrar.Archive(archive)) {
|
||||
for (com.github.junrar.rarfile.FileHeader fh : rar.getFileHeaders()) {
|
||||
if (matchEntry(fh.getFileName(), patternLower, filenameRegex)) {
|
||||
callback.onFileFound(archive, archive.getAbsolutePath() + File.separator + fh.getFileName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
private static void searchContentsInArchive(File archive, Pattern contentPattern, SearchCallback callback) {
|
||||
String name = archive.getName().toLowerCase();
|
||||
try {
|
||||
if (name.endsWith(".zip") || name.endsWith(".jar")) {
|
||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(archive))) {
|
||||
ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (!entry.isDirectory() && searchInStream(zis, contentPattern)) {
|
||||
callback.onFileFound(archive, archive.getAbsolutePath() + File.separator + entry.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (name.endsWith(".tar.gz") || name.endsWith(".tgz") || name.endsWith(".tar")) {
|
||||
InputStream is = new FileInputStream(archive);
|
||||
if (name.endsWith(".gz") || name.endsWith(".tgz")) {
|
||||
is = new org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream(is);
|
||||
}
|
||||
try (org.apache.commons.compress.archivers.tar.TarArchiveInputStream tais = new org.apache.commons.compress.archivers.tar.TarArchiveInputStream(is)) {
|
||||
org.apache.commons.compress.archivers.tar.TarArchiveEntry entry;
|
||||
while ((entry = tais.getNextTarEntry()) != null) {
|
||||
if (!entry.isDirectory() && searchInStream(tais, contentPattern)) {
|
||||
callback.onFileFound(archive, archive.getAbsolutePath() + File.separator + entry.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (name.endsWith(".7z")) {
|
||||
try (org.apache.commons.compress.archivers.sevenz.SevenZFile sevenZFile = new org.apache.commons.compress.archivers.sevenz.SevenZFile(archive)) {
|
||||
org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry entry;
|
||||
while ((entry = sevenZFile.getNextEntry()) != null) {
|
||||
if (!entry.isDirectory()) {
|
||||
// SevenZFile.read(buffer) reads from current entry
|
||||
if (searchInStream(new InputStream() {
|
||||
boolean nameMatched = true;
|
||||
if (patternLower != null && !patternLower.isEmpty()) {
|
||||
nameMatched = matchEntry(entry.getName(), patternLower, filenameRegex);
|
||||
}
|
||||
boolean contentMatched = true;
|
||||
if (nameMatched && contentPattern != null) {
|
||||
contentMatched = searchInStream(new InputStream() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return sevenZFile.read();
|
||||
@ -679,7 +717,9 @@ public class FileOperations {
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
return sevenZFile.read(b, off, len);
|
||||
}
|
||||
}, contentPattern)) {
|
||||
}, contentPattern);
|
||||
}
|
||||
if (nameMatched && contentMatched) {
|
||||
callback.onFileFound(archive, archive.getAbsolutePath() + File.separator + entry.getName());
|
||||
}
|
||||
}
|
||||
@ -689,9 +729,17 @@ public class FileOperations {
|
||||
try (com.github.junrar.Archive rar = new com.github.junrar.Archive(archive)) {
|
||||
for (com.github.junrar.rarfile.FileHeader fh : rar.getFileHeaders()) {
|
||||
if (!fh.isDirectory()) {
|
||||
boolean nameMatched = true;
|
||||
if (patternLower != null && !patternLower.isEmpty()) {
|
||||
nameMatched = matchEntry(fh.getFileName(), patternLower, filenameRegex);
|
||||
}
|
||||
boolean contentMatched = true;
|
||||
if (nameMatched && contentPattern != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
rar.extractFile(fh, baos);
|
||||
if (contentPattern.matcher(new String(baos.toByteArray())).find()) {
|
||||
contentMatched = contentPattern.matcher(new String(baos.toByteArray())).find();
|
||||
}
|
||||
if (nameMatched && contentMatched) {
|
||||
callback.onFileFound(archive, archive.getAbsolutePath() + File.separator + fh.getFileName());
|
||||
}
|
||||
}
|
||||
@ -701,6 +749,7 @@ public class FileOperations {
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
|
||||
private static boolean matchEntry(String entryName, String patternLower, Pattern filenameRegex) {
|
||||
if (entryName == null) return false;
|
||||
String nameShort = entryName;
|
||||
|
||||
@ -19,6 +19,7 @@ public class FileEditor extends JDialog {
|
||||
private JTextArea textArea;
|
||||
private JScrollPane scrollPane;
|
||||
private File file;
|
||||
private String virtualPath;
|
||||
private java.util.List<File> imageFiles = new java.util.ArrayList<>();
|
||||
private int currentImageIndex = -1;
|
||||
private AppConfig config;
|
||||
@ -52,12 +53,17 @@ public class FileEditor extends JDialog {
|
||||
private static String lastSearchValue = "";
|
||||
|
||||
public FileEditor(Window parent, File file, AppConfig config, boolean readOnly) {
|
||||
super(parent, (readOnly ? "Prohlížeč - " : "Editor - ") + file.getName(), ModalityType.MODELESS);
|
||||
this(parent, file, null, config, readOnly);
|
||||
}
|
||||
|
||||
public FileEditor(Window parent, File file, String virtualPath, AppConfig config, boolean readOnly) {
|
||||
super(parent, (readOnly ? "Prohlížeč - " : "Editor - ") + (virtualPath != null ? virtualPath.substring(virtualPath.lastIndexOf(File.separator) + 1) : file.getName()), ModalityType.MODELESS);
|
||||
this.file = file;
|
||||
this.virtualPath = virtualPath;
|
||||
this.config = config;
|
||||
this.readOnly = readOnly;
|
||||
|
||||
if (isImageFile(file)) {
|
||||
if (isImageFile(file) && virtualPath == null) {
|
||||
initImageList();
|
||||
}
|
||||
|
||||
@ -809,6 +815,38 @@ public class FileEditor extends JDialog {
|
||||
}
|
||||
|
||||
private void loadFile() {
|
||||
if (virtualPath != null) {
|
||||
try {
|
||||
fileBytes = cz.kamma.kfmanager.service.FileOperations.readFileFromArchive(file, virtualPath);
|
||||
boolean binary = isBinary(fileBytes);
|
||||
if (binary && readOnly) {
|
||||
hexMode = true;
|
||||
buildHexViewText(0L);
|
||||
textArea.setEditable(false);
|
||||
textArea.setFont(new Font("Monospaced", Font.PLAIN, textArea.getFont().getSize()));
|
||||
ensureHexControls();
|
||||
if (hexControlPanel.getParent() == null) northPanel.add(hexControlPanel);
|
||||
hexControlPanel.setVisible(true);
|
||||
northPanel.revalidate();
|
||||
} else if (hexMode) {
|
||||
buildHexViewText(0L);
|
||||
} else {
|
||||
String content = new String(fileBytes, "UTF-8");
|
||||
textArea.setText(content);
|
||||
textArea.setCaretPosition(0);
|
||||
}
|
||||
if (undoManager != null) undoManager.discardAllEdits();
|
||||
modified = false;
|
||||
updateTitle();
|
||||
updateStatus();
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
JOptionPane.showMessageDialog(this, "Chyba při čtení z archivu: " + e.getMessage(), "Chyba", JOptionPane.ERROR_MESSAGE);
|
||||
dispose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isImageFile(file)) {
|
||||
loadImage();
|
||||
return;
|
||||
|
||||
@ -204,16 +204,30 @@ public class SearchDialog extends JDialog {
|
||||
}
|
||||
});
|
||||
|
||||
// Enter pro otevření umístění
|
||||
resultsTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "openLocation");
|
||||
resultsTable.getActionMap().put("openLocation", new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(java.awt.event.ActionEvent e) {
|
||||
openSelectedFile();
|
||||
}
|
||||
});
|
||||
|
||||
// Enable/disable view/edit buttons depending on selection
|
||||
resultsTable.getSelectionModel().addListSelectionListener(e -> {
|
||||
int sel = resultsTable.getSelectedRow();
|
||||
boolean ok = false;
|
||||
boolean canEdit = false;
|
||||
if (sel >= 0) {
|
||||
FileItem it = tableModel.getResult(sel);
|
||||
ok = it != null && !it.isDirectory() && !"..".equals(it.getName());
|
||||
if (ok) {
|
||||
boolean inArchive = it.getPath() != null && !it.getPath().equals(it.getFile().getAbsolutePath());
|
||||
canEdit = !inArchive;
|
||||
}
|
||||
}
|
||||
viewButton.setEnabled(ok);
|
||||
editButton.setEnabled(ok);
|
||||
editButton.setEnabled(canEdit);
|
||||
});
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(resultsTable);
|
||||
@ -262,6 +276,9 @@ public class SearchDialog extends JDialog {
|
||||
bottomPanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
add(bottomPanel, BorderLayout.SOUTH);
|
||||
|
||||
// Set search button as default so Enter starts search
|
||||
getRootPane().setDefaultButton(searchButton);
|
||||
|
||||
// Require explicit Enter to start search when choosing from history.
|
||||
// Bind Enter on the combo editor component so selecting an item from the
|
||||
// popup does not automatically trigger search until user confirms.
|
||||
@ -273,17 +290,16 @@ public class SearchDialog extends JDialog {
|
||||
@Override
|
||||
public void actionPerformed(java.awt.event.ActionEvent e) {
|
||||
try {
|
||||
// If the popup is visible, treat Enter as "confirm selection": fill editor and close popup
|
||||
// If the popup is visible, treat Enter as "confirm selection" and proceed to search
|
||||
if (patternCombo.isPopupVisible()) {
|
||||
Object sel = patternCombo.getSelectedItem();
|
||||
if (sel != null) {
|
||||
patternCombo.getEditor().setItem(sel.toString());
|
||||
}
|
||||
patternCombo.hidePopup();
|
||||
return; // do not start search yet
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
// Popup not visible -> actual confirm to start search
|
||||
// Actual confirm to start search
|
||||
performSearch();
|
||||
}
|
||||
});
|
||||
@ -303,7 +319,6 @@ public class SearchDialog extends JDialog {
|
||||
Object sel = contentPatternCombo.getSelectedItem();
|
||||
if (sel != null) contentPatternCombo.getEditor().setItem(sel.toString());
|
||||
contentPatternCombo.hidePopup();
|
||||
return;
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
performSearch();
|
||||
@ -446,62 +461,64 @@ public class SearchDialog extends JDialog {
|
||||
|
||||
final boolean isContentSearch = contentSearchCheckBox != null && contentSearchCheckBox.isSelected();
|
||||
|
||||
if (isContentSearch) {
|
||||
if (contentPat.isEmpty()) {
|
||||
if (namePat.isEmpty() && (!isContentSearch || contentPat.isEmpty())) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
"Zadejte hledaný text",
|
||||
"Zadejte hledaný vzor nebo text",
|
||||
"Chyba",
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (namePat.isEmpty()) {
|
||||
|
||||
if (isContentSearch && contentPat.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
"Zadejte hledaný vzor",
|
||||
"Zadejte hledaný text pro vyhledávání v obsahu",
|
||||
"Chyba",
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tableModel.clear();
|
||||
searchButton.setEnabled(false);
|
||||
searching = true;
|
||||
|
||||
// Persist the chosen pattern into the appropriate history (most-recent-first)
|
||||
// Persist the chosen patterns into history
|
||||
if (config != null) {
|
||||
try {
|
||||
if (isContentSearch) {
|
||||
java.util.List<String> chist = new java.util.ArrayList<>(config.getContentSearchHistory());
|
||||
chist.remove(contentPat);
|
||||
chist.add(0, contentPat);
|
||||
int max = 20;
|
||||
while (chist.size() > max) chist.remove(chist.size() - 1);
|
||||
config.saveContentSearchHistory(chist);
|
||||
config.saveConfig();
|
||||
// update content combo model
|
||||
javax.swing.DefaultComboBoxModel<String> cm = (javax.swing.DefaultComboBoxModel<String>) contentPatternCombo.getModel();
|
||||
cm.removeAllElements();
|
||||
for (String s : chist) cm.addElement(s);
|
||||
contentPatternCombo.setSelectedItem(contentPat);
|
||||
} else {
|
||||
if (!namePat.isEmpty()) {
|
||||
java.util.List<String> hist = new java.util.ArrayList<>(config.getSearchHistory());
|
||||
hist.remove(namePat);
|
||||
hist.add(0, namePat);
|
||||
int max = 20;
|
||||
while (hist.size() > max) hist.remove(hist.size() - 1);
|
||||
config.saveSearchHistory(hist);
|
||||
config.saveConfig();
|
||||
|
||||
// update combo model
|
||||
javax.swing.DefaultComboBoxModel<String> m = (javax.swing.DefaultComboBoxModel<String>) patternCombo.getModel();
|
||||
m.removeAllElements();
|
||||
for (String s : hist) m.addElement(s);
|
||||
patternCombo.setSelectedItem(namePat);
|
||||
}
|
||||
|
||||
if (isContentSearch && !contentPat.isEmpty()) {
|
||||
java.util.List<String> chist = new java.util.ArrayList<>(config.getContentSearchHistory());
|
||||
chist.remove(contentPat);
|
||||
chist.add(0, contentPat);
|
||||
int max = 20;
|
||||
while (chist.size() > max) chist.remove(chist.size() - 1);
|
||||
config.saveContentSearchHistory(chist);
|
||||
|
||||
// update content combo model
|
||||
javax.swing.DefaultComboBoxModel<String> cm = (javax.swing.DefaultComboBoxModel<String>) contentPatternCombo.getModel();
|
||||
cm.removeAllElements();
|
||||
for (String s : chist) cm.addElement(s);
|
||||
contentPatternCombo.setSelectedItem(contentPat);
|
||||
}
|
||||
config.saveConfig();
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
final String pattern = isContentSearch ? contentPat : namePat;
|
||||
final String finalNamePat = namePat;
|
||||
final String finalContentPat = isContentSearch ? contentPat : null;
|
||||
final boolean searchArchives = archiveSearchCheckBox != null && archiveSearchCheckBox.isSelected();
|
||||
|
||||
// Reset and show status
|
||||
@ -514,17 +531,10 @@ public class SearchDialog extends JDialog {
|
||||
SwingWorker<Void, Object[]> worker = new SwingWorker<Void, Object[]>() {
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
if (isContentSearch) {
|
||||
FileOperations.searchContents(searchDirectory, pattern, recursiveCheckBox.isSelected(), searchArchives, (file, virtualPath) -> {
|
||||
FileOperations.search(searchDirectory, finalNamePat, finalContentPat, recursiveCheckBox.isSelected(), searchArchives, (file, virtualPath) -> {
|
||||
if (!searching) return;
|
||||
publish(new Object[]{file, virtualPath});
|
||||
});
|
||||
} else {
|
||||
FileOperations.search(searchDirectory, pattern, recursiveCheckBox.isSelected(), searchArchives, (file, virtualPath) -> {
|
||||
if (!searching) return;
|
||||
publish(new Object[]{file, virtualPath});
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -613,11 +623,18 @@ public class SearchDialog extends JDialog {
|
||||
if (item != null && !item.isDirectory() && !"..".equals(item.getName())) {
|
||||
try {
|
||||
Frame owner = (Frame) SwingUtilities.getWindowAncestor(this);
|
||||
FileEditor viewer = new FileEditor(owner, item.getFile(), config, true);
|
||||
String vPath = null;
|
||||
if (item.getPath() != null && !item.getPath().equals(item.getFile().getAbsolutePath())) {
|
||||
vPath = item.getPath();
|
||||
}
|
||||
FileEditor viewer = new FileEditor(owner, item.getFile(), vPath, config, true);
|
||||
viewer.addWindowListener(new java.awt.event.WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosed(java.awt.event.WindowEvent e) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
SearchDialog.this.toFront();
|
||||
resultsTable.requestFocusInWindow();
|
||||
});
|
||||
}
|
||||
});
|
||||
viewer.setVisible(true);
|
||||
@ -636,13 +653,21 @@ public class SearchDialog extends JDialog {
|
||||
if (sel >= 0) {
|
||||
FileItem item = tableModel.getResult(sel);
|
||||
if (item != null && !item.isDirectory() && !"..".equals(item.getName())) {
|
||||
boolean inArchive = item.getPath() != null && !item.getPath().equals(item.getFile().getAbsolutePath());
|
||||
if (inArchive) {
|
||||
JOptionPane.showMessageDialog(this, "Editace souborů přímo v archivu není podporována. Použijte 'Otevřít umístění' pro přístup k archivu.", "Informace", JOptionPane.INFORMATION_MESSAGE);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Frame owner = (Frame) SwingUtilities.getWindowAncestor(this);
|
||||
FileEditor editor = new FileEditor(owner, item.getFile(), config, false);
|
||||
editor.addWindowListener(new java.awt.event.WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosed(java.awt.event.WindowEvent e) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
SearchDialog.this.toFront();
|
||||
resultsTable.requestFocusInWindow();
|
||||
});
|
||||
}
|
||||
});
|
||||
editor.setVisible(true);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user