From d4bfeab00d09f0abb13e4b64c9b49066efd46e3b Mon Sep 17 00:00:00 2001 From: rdavidek Date: Sun, 18 Jan 2026 16:40:35 +0100 Subject: [PATCH] fixed esc --- .../java/cz/kamma/kfmanager/ui/FilePanel.java | 13 +++++- .../cz/kamma/kfmanager/ui/FilePanelTab.java | 44 ++++++++++++++++--- .../cz/kamma/kfmanager/ui/MainWindow.java | 42 ++++++++++++++++++ .../cz/kamma/kfmanager/ui/SearchDialog.java | 12 +++++ 4 files changed, 105 insertions(+), 6 deletions(-) diff --git a/src/main/java/cz/kamma/kfmanager/ui/FilePanel.java b/src/main/java/cz/kamma/kfmanager/ui/FilePanel.java index 58c8ec7..16684f5 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/FilePanel.java +++ b/src/main/java/cz/kamma/kfmanager/ui/FilePanel.java @@ -5,6 +5,7 @@ import cz.kamma.kfmanager.model.FileItem; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; import java.io.File; import java.util.List; @@ -47,6 +48,7 @@ public class FilePanel extends JPanel { } private void initComponents() { + tabbedPane = new JTabbedPane(); setLayout(new BorderLayout()); setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); @@ -55,6 +57,16 @@ public class FilePanel extends JPanel { // Drive selection dropdown placed before the path field driveCombo = new JComboBox<>(); + // Return focus to table when ESC is pressed in the combo + driveCombo.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel-drive-selection"); + driveCombo.getActionMap().put("cancel-drive-selection", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + driveCombo.hidePopup(); + FilePanelTab tab = getCurrentTab(); + if (tab != null) tab.getFileTable().requestFocusInWindow(); + } + }); // Allow the combo to receive focus so keyboard navigation and popup interaction work driveCombo.setFocusable(true); driveCombo.setToolTipText("Select drive"); @@ -156,7 +168,6 @@ public class FilePanel extends JPanel { add(topPanel, BorderLayout.NORTH); // JTabbedPane for tabs - tabbedPane = new JTabbedPane(); tabbedPane.setTabPlacement(JTabbedPane.TOP); // Listener for updating path and style on tab change diff --git a/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java b/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java index 796cdc3..75c0863 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java +++ b/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java @@ -62,6 +62,7 @@ public class FilePanelTab extends JPanel { // we can cleanup older temp directories when navigation changes. private Path currentArchiveTempDir = null; private File currentArchiveSourceFile = null; + private boolean inlineRenameActive = false; public FilePanelTab(String initialPath) { this(initialPath, true); @@ -88,8 +89,14 @@ public class FilePanelTab extends JPanel { editCol = 0; // name column in FULL } + // Enable editing temporarily + inlineRenameActive = true; + // Only allow editing if the cell represents a real item - if (!tableModel.isCellEditable(selRow, editCol)) return; + if (!tableModel.isCellEditable(selRow, editCol)) { + inlineRenameActive = false; + return; + } // Start editing and select all text in editor boolean started = fileTable.editCellAt(selRow, editCol); @@ -100,6 +107,8 @@ public class FilePanelTab extends JPanel { tf.requestFocusInWindow(); tf.selectAll(); } + } else { + inlineRenameActive = false; } } @@ -205,6 +214,18 @@ public class FilePanelTab extends JPanel { // Also override mouse-motion processing to suppress drag events and // prevent any drag-and-drop transfer handling. fileTable = new JTable(tableModel) { + @Override + public void editingStopped(javax.swing.event.ChangeEvent e) { + super.editingStopped(e); + inlineRenameActive = false; + } + + @Override + public void editingCanceled(javax.swing.event.ChangeEvent e) { + super.editingCanceled(e); + inlineRenameActive = false; + } + @Override protected void processMouseEvent(java.awt.event.MouseEvent e) { // Show system-like context menu on popup trigger (right-click) without @@ -586,6 +607,11 @@ public class FilePanelTab extends JPanel { } else if (e.getKeyCode() == java.awt.event.KeyEvent.VK_INSERT) { toggleSelectionAndMoveDown(); e.consume(); + } else if (e.getKeyCode() == java.awt.event.KeyEvent.VK_ESCAPE) { + if (fileTable.isEditing()) { + fileTable.getCellEditor().cancelCellEditing(); + e.consume(); + } } else if (viewMode == ViewMode.BRIEF) { handleBriefKeyNavigation(e); } else if (viewMode == ViewMode.FULL) { @@ -1156,11 +1182,17 @@ public class FilePanelTab extends JPanel { } else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) { // 3. Fallback to system default Desktop.getDesktop().open(file); + // Try to keep focus or at least set it back for when user returns + SwingUtilities.invokeLater(() -> { + fileTable.requestFocusInWindow(); + }); } } catch (Exception ex) { try { JOptionPane.showMessageDialog(this, "Error opening file: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } catch (Exception ignore) {} + } finally { + fileTable.requestFocusInWindow(); } } @@ -1196,7 +1228,7 @@ public class FilePanelTab extends JPanel { } catch (Exception ignore) {} currentArchiveTempDir = temp; currentArchiveSourceFile = item.getFile(); - loadDirectory(temp.toFile()); + loadDirectory(temp.toFile(), true, true); } } else if (item.isDirectory()) { loadDirectory(item.getFile()); @@ -1364,7 +1396,7 @@ public class FilePanelTab extends JPanel { PropertiesDialog dialog = new PropertiesDialog(parent, f); dialog.setVisible(true); // Refresh current directory after potential attribute changes - loadDirectory(getCurrentDirectory()); + loadDirectory(getCurrentDirectory(), false, true); } } catch (Exception ex) { try { JOptionPane.showMessageDialog(FilePanelTab.this, "Cannot show properties: " + ex.getMessage()); } catch (Exception ignore) {} @@ -1414,11 +1446,11 @@ public class FilePanelTab extends JPanel { } } - private void selectItemByName(String name) { + public void selectItemByName(String name) { selectItemByName(name, true); } - private void selectItemByName(String name, boolean requestFocus) { + public void selectItemByName(String name, boolean requestFocus) { if (viewMode == ViewMode.BRIEF) { // Re-calculate layout if needed before searching to ensure current mapping if (tableModel.items.size() > 0 && (tableModel.briefColumns == 0 || tableModel.briefRowsPerColumn == 0)) { @@ -2545,6 +2577,8 @@ public class FilePanelTab extends JPanel { @Override public boolean isCellEditable(int rowIndex, int columnIndex) { + if (!inlineRenameActive) return false; + if (viewMode == ViewMode.BRIEF) { FileItem it = getItemFromBriefLayout(rowIndex, columnIndex); return it != null; // allow editing name in brief cells diff --git a/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java b/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java index d58278a..5580e64 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java +++ b/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java @@ -687,6 +687,7 @@ public class MainWindow extends JFrame { dlg.setVisible(true); // After dialog closed, ensure appearance applied applyAppearanceSettings(); + requestFocusInActivePanel(); } /** @@ -839,9 +840,18 @@ public class MainWindow extends JFrame { // ESC - global escape to return focus to panels rootPane.registerKeyboardAction(e -> { + boolean textCleared = false; Object currentItem = commandLine.getEditor().getItem(); if (currentItem != null && !currentItem.toString().isEmpty()) { commandLine.getEditor().setItem(""); + textCleared = true; + } + + // If we just cleared text, or if focus is not in any table, return focus to active panel + Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + boolean inTable = (focusOwner instanceof JTable); + + if (textCleared || !inTable) { if (activePanel != null && activePanel.getFileTable() != null) { activePanel.getFileTable().requestFocusInWindow(); } @@ -1178,6 +1188,7 @@ public class MainWindow extends JFrame { "No files selected", "Copy", JOptionPane.INFORMATION_MESSAGE); + requestFocusInActivePanel(); return; } @@ -1210,6 +1221,7 @@ public class MainWindow extends JFrame { "No files selected", "Move", JOptionPane.INFORMATION_MESSAGE); + requestFocusInActivePanel(); return; } @@ -1242,6 +1254,7 @@ public class MainWindow extends JFrame { "No files selected", "Delete", JOptionPane.INFORMATION_MESSAGE); + requestFocusInActivePanel(); return; } // remember current selection index so we can restore selection after deletion @@ -1296,6 +1309,7 @@ public class MainWindow extends JFrame { "No files selected", "Zip", JOptionPane.INFORMATION_MESSAGE); + requestFocusInActivePanel(); return; } @@ -1360,6 +1374,7 @@ public class MainWindow extends JFrame { "No files selected", "Unzip", JOptionPane.INFORMATION_MESSAGE); + requestFocusInActivePanel(); return; } @@ -1369,6 +1384,7 @@ public class MainWindow extends JFrame { "Selected file is not a ZIP archive", "Unzip", JOptionPane.ERROR_MESSAGE); + requestFocusInActivePanel(); return; } @@ -1407,6 +1423,7 @@ public class MainWindow extends JFrame { "Select one file to rename", "Rename", JOptionPane.INFORMATION_MESSAGE); + requestFocusInActivePanel(); return; } FileItem item = selectedItems.get(0); @@ -1455,6 +1472,12 @@ public class MainWindow extends JFrame { */ private void showSearchDialog() { SearchDialog dialog = new SearchDialog(this, activePanel.getCurrentDirectory(), config); + dialog.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosed(java.awt.event.WindowEvent e) { + requestFocusInActivePanel(); + } + }); dialog.setVisible(true); } @@ -1543,6 +1566,12 @@ public class MainWindow extends JFrame { // Removed previous 10 MB limit: allow opening large files in the viewer (paged hex will stream large binaries). FileEditor viewer = new FileEditor(this, file, config, true); + viewer.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosed(java.awt.event.WindowEvent e) { + requestFocusInActivePanel(); + } + }); viewer.setVisible(true); } @@ -1581,6 +1610,12 @@ public class MainWindow extends JFrame { // Removed previous 10 MB limit: allow opening large files in the editor. The editor may still choose hex/paged mode for large binaries. FileEditor editor = new FileEditor(this, file, config, false); + editor.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosed(java.awt.event.WindowEvent e) { + requestFocusInActivePanel(); + } + }); editor.setVisible(true); } @@ -1846,6 +1881,7 @@ public class MainWindow extends JFrame { "Backspace - Parent directory", "About", JOptionPane.INFORMATION_MESSAGE); + requestFocusInActivePanel(); } /** @@ -2028,4 +2064,10 @@ public class MainWindow extends JFrame { private interface FileOperation { void execute(FileOperations.ProgressCallback callback) throws Exception; } + + private void requestFocusInActivePanel() { + if (activePanel != null && activePanel.getFileTable() != null) { + activePanel.getFileTable().requestFocusInWindow(); + } + } } diff --git a/src/main/java/cz/kamma/kfmanager/ui/SearchDialog.java b/src/main/java/cz/kamma/kfmanager/ui/SearchDialog.java index b1ce2b4..a0dcd38 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/SearchDialog.java +++ b/src/main/java/cz/kamma/kfmanager/ui/SearchDialog.java @@ -542,6 +542,12 @@ public class SearchDialog extends JDialog { try { Frame owner = (Frame) SwingUtilities.getWindowAncestor(this); FileEditor viewer = new FileEditor(owner, item.getFile(), config, true); + viewer.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosed(java.awt.event.WindowEvent e) { + resultsTable.requestFocusInWindow(); + } + }); viewer.setVisible(true); } catch (Exception e) { JOptionPane.showMessageDialog(this, "Chyba při otevírání souboru: " + e.getMessage(), "Chyba", JOptionPane.ERROR_MESSAGE); @@ -561,6 +567,12 @@ public class SearchDialog extends JDialog { 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) { + resultsTable.requestFocusInWindow(); + } + }); editor.setVisible(true); } catch (Exception e) { JOptionPane.showMessageDialog(this, "Chyba při otevírání souboru: " + e.getMessage(), "Chyba", JOptionPane.ERROR_MESSAGE);