search in file
This commit is contained in:
parent
68fe5ca0c6
commit
26d62d2902
@ -35,11 +35,18 @@ public class FileEditor extends JDialog {
|
|||||||
// Allow loading entire file into memory up to this limit (100 MB)
|
// Allow loading entire file into memory up to this limit (100 MB)
|
||||||
private final long maxFullLoadBytes = 100L * 1024L * 1024L; // 100 MB
|
private final long maxFullLoadBytes = 100L * 1024L * 1024L; // 100 MB
|
||||||
private JPanel hexControlPanel = null;
|
private JPanel hexControlPanel = null;
|
||||||
|
private JPanel northPanel = null;
|
||||||
private JButton prevPageBtn = null;
|
private JButton prevPageBtn = null;
|
||||||
private JButton nextPageBtn = null;
|
private JButton nextPageBtn = null;
|
||||||
private JLabel pageOffsetLabel = null;
|
private JLabel pageOffsetLabel = null;
|
||||||
private javax.swing.undo.UndoManager undoManager;
|
private javax.swing.undo.UndoManager undoManager;
|
||||||
|
|
||||||
|
// Search support
|
||||||
|
private JPanel searchPanel;
|
||||||
|
private JTextField searchField;
|
||||||
|
private JLabel searchStatusLabel;
|
||||||
|
private static String lastSearchValue = "";
|
||||||
|
|
||||||
public FileEditor(Window parent, File file, AppConfig config, boolean readOnly) {
|
public FileEditor(Window parent, File file, AppConfig config, boolean readOnly) {
|
||||||
super(parent, (readOnly ? "Prohlížeč - " : "Editor - ") + file.getName(), ModalityType.MODELESS);
|
super(parent, (readOnly ? "Prohlížeč - " : "Editor - ") + file.getName(), ModalityType.MODELESS);
|
||||||
this.file = file;
|
this.file = file;
|
||||||
@ -61,9 +68,164 @@ public class FileEditor extends JDialog {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initSearchPanel() {
|
||||||
|
searchPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 2));
|
||||||
|
searchPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.GRAY));
|
||||||
|
|
||||||
|
searchField = new JTextField(20);
|
||||||
|
searchField.addActionListener(e -> findNext());
|
||||||
|
|
||||||
|
JButton nextBtn = new JButton("Dále");
|
||||||
|
nextBtn.addActionListener(e -> findNext());
|
||||||
|
|
||||||
|
JButton prevBtn = new JButton("Zpět");
|
||||||
|
prevBtn.addActionListener(e -> findPrevious());
|
||||||
|
|
||||||
|
JButton closeBtn = new JButton("X");
|
||||||
|
closeBtn.setMargin(new Insets(0, 5, 0, 5));
|
||||||
|
closeBtn.addActionListener(e -> hideSearchPanel());
|
||||||
|
|
||||||
|
searchStatusLabel = new JLabel("");
|
||||||
|
|
||||||
|
searchPanel.add(new JLabel("Hledat:"));
|
||||||
|
searchPanel.add(searchField);
|
||||||
|
searchPanel.add(nextBtn);
|
||||||
|
searchPanel.add(prevBtn);
|
||||||
|
searchPanel.add(closeBtn);
|
||||||
|
searchPanel.add(searchStatusLabel);
|
||||||
|
|
||||||
|
searchPanel.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showSearchPanel() {
|
||||||
|
searchPanel.setVisible(true);
|
||||||
|
String selection = textArea.getSelectedText();
|
||||||
|
if (selection != null && !selection.isEmpty() && !selection.contains("\n")) {
|
||||||
|
searchField.setText(selection);
|
||||||
|
lastSearchValue = selection;
|
||||||
|
} else if (!lastSearchValue.isEmpty()) {
|
||||||
|
searchField.setText(lastSearchValue);
|
||||||
|
} else if (config != null) {
|
||||||
|
java.util.List<String> hist = config.getContentSearchHistory();
|
||||||
|
if (hist != null && !hist.isEmpty()) {
|
||||||
|
lastSearchValue = hist.get(0);
|
||||||
|
searchField.setText(lastSearchValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
searchField.requestFocusInWindow();
|
||||||
|
searchField.selectAll();
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
searchField.requestFocusInWindow();
|
||||||
|
searchField.selectAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (northPanel != null) {
|
||||||
|
northPanel.revalidate();
|
||||||
|
northPanel.repaint();
|
||||||
|
}
|
||||||
|
revalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideSearchPanel() {
|
||||||
|
searchPanel.setVisible(false);
|
||||||
|
textArea.requestFocusInWindow();
|
||||||
|
revalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findNext() {
|
||||||
|
String text = searchField.getText();
|
||||||
|
if (text.isEmpty()) text = lastSearchValue;
|
||||||
|
if (text == null || text.isEmpty()) return;
|
||||||
|
lastSearchValue = text;
|
||||||
|
updateSearchHistory(text);
|
||||||
|
|
||||||
|
if (searchField.getText().isEmpty()) searchField.setText(text);
|
||||||
|
|
||||||
|
String content = textArea.getText();
|
||||||
|
int start = textArea.getCaretPosition();
|
||||||
|
|
||||||
|
// If we have a selection that matches, start after it
|
||||||
|
if (textArea.getSelectionEnd() > textArea.getSelectionStart()) {
|
||||||
|
if (content.substring(textArea.getSelectionStart(), textArea.getSelectionEnd()).equalsIgnoreCase(text)) {
|
||||||
|
start = textArea.getSelectionEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = content.toLowerCase().indexOf(text.toLowerCase(), start);
|
||||||
|
if (idx == -1) {
|
||||||
|
// wrap around
|
||||||
|
idx = content.toLowerCase().indexOf(text.toLowerCase(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx != -1) {
|
||||||
|
textArea.setSelectionStart(idx);
|
||||||
|
textArea.setSelectionEnd(idx + text.length());
|
||||||
|
textArea.getCaret().setSelectionVisible(true);
|
||||||
|
try {
|
||||||
|
Rectangle rect = textArea.modelToView2D(idx).getBounds();
|
||||||
|
textArea.scrollRectToVisible(rect);
|
||||||
|
} catch (Exception ignore) {}
|
||||||
|
searchStatusLabel.setText("");
|
||||||
|
} else {
|
||||||
|
searchStatusLabel.setText("Nenalezeno");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findPrevious() {
|
||||||
|
String text = searchField.getText();
|
||||||
|
if (text.isEmpty()) text = lastSearchValue;
|
||||||
|
if (text == null || text.isEmpty()) return;
|
||||||
|
lastSearchValue = text;
|
||||||
|
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 idx = content.toLowerCase().lastIndexOf(text.toLowerCase(), start);
|
||||||
|
if (idx == -1) {
|
||||||
|
// wrap around
|
||||||
|
idx = content.toLowerCase().lastIndexOf(text.toLowerCase(), content.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx != -1) {
|
||||||
|
textArea.setSelectionStart(idx);
|
||||||
|
textArea.setSelectionEnd(idx + text.length());
|
||||||
|
textArea.getCaret().setSelectionVisible(true);
|
||||||
|
try {
|
||||||
|
Rectangle rect = textArea.modelToView2D(idx).getBounds();
|
||||||
|
textArea.scrollRectToVisible(rect);
|
||||||
|
} catch (Exception ignore) {}
|
||||||
|
searchStatusLabel.setText("");
|
||||||
|
} else {
|
||||||
|
searchStatusLabel.setText("Nenalezeno");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSearchHistory(String text) {
|
||||||
|
if (config == null || text == null || text.isEmpty()) return;
|
||||||
|
java.util.List<String> hist = new java.util.ArrayList<>(config.getContentSearchHistory());
|
||||||
|
hist.remove(text);
|
||||||
|
hist.add(0, text);
|
||||||
|
if (hist.size() > 20) hist = hist.subList(0, 20);
|
||||||
|
config.saveContentSearchHistory(hist);
|
||||||
|
config.saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
setLayout(new BorderLayout());
|
setLayout(new BorderLayout());
|
||||||
|
|
||||||
|
northPanel = new JPanel();
|
||||||
|
northPanel.setLayout(new BoxLayout(northPanel, BoxLayout.Y_AXIS));
|
||||||
|
add(northPanel, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
initSearchPanel();
|
||||||
|
northPanel.add(searchPanel);
|
||||||
|
|
||||||
// Menu bar
|
// Menu bar
|
||||||
createMenuBar();
|
createMenuBar();
|
||||||
|
|
||||||
@ -284,6 +446,18 @@ public class FileEditor extends JDialog {
|
|||||||
selectAllItem.addActionListener(e -> textArea.selectAll());
|
selectAllItem.addActionListener(e -> textArea.selectAll());
|
||||||
editMenu.add(selectAllItem);
|
editMenu.add(selectAllItem);
|
||||||
|
|
||||||
|
editMenu.addSeparator();
|
||||||
|
|
||||||
|
JMenuItem findItem = new JMenuItem("Hledat...");
|
||||||
|
findItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK));
|
||||||
|
findItem.addActionListener(e -> showSearchPanel());
|
||||||
|
editMenu.add(findItem);
|
||||||
|
|
||||||
|
JMenuItem findNextItem = new JMenuItem("Hledat další");
|
||||||
|
findNextItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0));
|
||||||
|
findNextItem.addActionListener(e -> findNext());
|
||||||
|
editMenu.add(findNextItem);
|
||||||
|
|
||||||
// Update menu items state when menu is selected
|
// Update menu items state when menu is selected
|
||||||
editMenu.addMenuListener(new javax.swing.event.MenuListener() {
|
editMenu.addMenuListener(new javax.swing.event.MenuListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -352,8 +526,14 @@ public class FileEditor extends JDialog {
|
|||||||
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ESC - Zavřít
|
// ESC - Zavřít nebo skrýt hledání
|
||||||
rootPane.registerKeyboardAction(e -> closeEditor(),
|
rootPane.registerKeyboardAction(e -> {
|
||||||
|
if (searchPanel.isVisible()) {
|
||||||
|
hideSearchPanel();
|
||||||
|
} else {
|
||||||
|
closeEditor();
|
||||||
|
}
|
||||||
|
},
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
|
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
|
||||||
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
|
|
||||||
@ -394,6 +574,19 @@ public class FileEditor extends JDialog {
|
|||||||
rootPane.registerKeyboardAction(e -> {
|
rootPane.registerKeyboardAction(e -> {
|
||||||
if (undoManager.canRedo()) undoManager.redo();
|
if (undoManager.canRedo()) undoManager.redo();
|
||||||
}, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
}, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
|
|
||||||
|
// Hledání
|
||||||
|
rootPane.registerKeyboardAction(e -> showSearchPanel(),
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK),
|
||||||
|
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
|
|
||||||
|
rootPane.registerKeyboardAction(e -> findNext(),
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0),
|
||||||
|
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
|
|
||||||
|
rootPane.registerKeyboardAction(e -> findPrevious(),
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_F3, InputEvent.SHIFT_DOWN_MASK),
|
||||||
|
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setHexMode(boolean on) {
|
private void setHexMode(boolean on) {
|
||||||
@ -422,9 +615,10 @@ public class FileEditor extends JDialog {
|
|||||||
textArea.setFont(new Font("Monospaced", Font.PLAIN, textArea.getFont().getSize()));
|
textArea.setFont(new Font("Monospaced", Font.PLAIN, textArea.getFont().getSize()));
|
||||||
ensureHexControls();
|
ensureHexControls();
|
||||||
if (hexControlPanel.getParent() == null) {
|
if (hexControlPanel.getParent() == null) {
|
||||||
add(hexControlPanel, BorderLayout.NORTH);
|
northPanel.add(hexControlPanel);
|
||||||
}
|
}
|
||||||
hexControlPanel.setVisible(true);
|
hexControlPanel.setVisible(true);
|
||||||
|
northPanel.revalidate();
|
||||||
} else {
|
} else {
|
||||||
// switch back to text view if possible
|
// switch back to text view if possible
|
||||||
// close RA if open
|
// close RA if open
|
||||||
@ -434,6 +628,10 @@ public class FileEditor extends JDialog {
|
|||||||
loadFile();
|
loadFile();
|
||||||
textArea.setEditable(!readOnly);
|
textArea.setEditable(!readOnly);
|
||||||
textArea.setFont(config.getEditorFont());
|
textArea.setFont(config.getEditorFont());
|
||||||
|
if (hexControlPanel != null) {
|
||||||
|
hexControlPanel.setVisible(false);
|
||||||
|
northPanel.revalidate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
applyAppearance();
|
applyAppearance();
|
||||||
updateStatus();
|
updateStatus();
|
||||||
@ -593,8 +791,9 @@ public class FileEditor extends JDialog {
|
|||||||
pageOffsetBytes = 0L;
|
pageOffsetBytes = 0L;
|
||||||
loadHexPage();
|
loadHexPage();
|
||||||
ensureHexControls();
|
ensureHexControls();
|
||||||
if (hexControlPanel.getParent() == null) add(hexControlPanel, BorderLayout.NORTH);
|
if (hexControlPanel.getParent() == null) northPanel.add(hexControlPanel);
|
||||||
hexControlPanel.setVisible(true);
|
hexControlPanel.setVisible(true);
|
||||||
|
northPanel.revalidate();
|
||||||
textArea.setEditable(false);
|
textArea.setEditable(false);
|
||||||
textArea.setFont(new Font("Monospaced", Font.PLAIN, textArea.getFont().getSize()));
|
textArea.setFont(new Font("Monospaced", Font.PLAIN, textArea.getFont().getSize()));
|
||||||
hexMode = true;
|
hexMode = true;
|
||||||
@ -608,8 +807,9 @@ public class FileEditor extends JDialog {
|
|||||||
textArea.setEditable(false);
|
textArea.setEditable(false);
|
||||||
textArea.setFont(new Font("Monospaced", Font.PLAIN, textArea.getFont().getSize()));
|
textArea.setFont(new Font("Monospaced", Font.PLAIN, textArea.getFont().getSize()));
|
||||||
ensureHexControls();
|
ensureHexControls();
|
||||||
if (hexControlPanel.getParent() == null) add(hexControlPanel, BorderLayout.NORTH);
|
if (hexControlPanel.getParent() == null) northPanel.add(hexControlPanel);
|
||||||
hexControlPanel.setVisible(true);
|
hexControlPanel.setVisible(true);
|
||||||
|
northPanel.revalidate();
|
||||||
} else if (hexMode) {
|
} else if (hexMode) {
|
||||||
buildHexViewText(0L);
|
buildHexViewText(0L);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user