diff --git a/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java b/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java index 6f408da..a1803d5 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java +++ b/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java @@ -65,6 +65,8 @@ public class FilePanelTab extends JPanel { // we can cleanup older temp directories when navigation changes. private Path currentArchiveTempDir = null; private File currentArchiveSourceFile = null; + private File archiveReturnDirectory = null; + private Point archiveReturnViewPosition = null; private boolean inlineRenameActive = false; private boolean active = false; private final Map changeTimestamps = new HashMap<>(); @@ -1397,6 +1399,7 @@ public class FilePanelTab extends JPanel { } public void showArchiveFile(File archive, String entryName) { + rememberArchiveReturnState(archive); Path temp = extractArchiveToTemp(archive); if (temp != null) { // Delete any previous temp dir if different @@ -1408,6 +1411,11 @@ public class FilePanelTab extends JPanel { currentArchiveTempDir = temp; currentArchiveSourceFile = archive; + if (entryName == null || entryName.isBlank()) { + loadDirectory(temp.toFile(), true, true); + return; + } + File targetFile = new File(temp.toFile(), entryName); File targetDir = targetFile.isDirectory() ? targetFile : targetFile.getParentFile(); @@ -1420,6 +1428,8 @@ public class FilePanelTab extends JPanel { } else { loadDirectory(temp.toFile(), true, true); } + } else { + clearArchiveReturnState(); } } @@ -1494,8 +1504,9 @@ public class FilePanelTab extends JPanel { if (item.getName().equals("..")) { navigateUp(); } else if (FileOperations.isArchiveFile(item.getFile())) { + rememberArchiveReturnState(item.getFile()); Path temp = extractArchiveToTemp(item.getFile()); - if (temp != null) { + if (temp != null) { // Delete any previous temp dir if different try { if (currentArchiveTempDir != null && !currentArchiveTempDir.equals(temp)) { @@ -1505,6 +1516,8 @@ public class FilePanelTab extends JPanel { currentArchiveTempDir = temp; currentArchiveSourceFile = item.getFile(); loadDirectory(temp.toFile()); + } else { + clearArchiveReturnState(); } } else if (item.isDirectory()) { loadDirectory(item.getFile()); @@ -1633,6 +1646,7 @@ public class FilePanelTab extends JPanel { if (item.getName().equals("..")) { navigateUp(); } else if (FileOperations.isArchiveFile(item.getFile())) { + rememberArchiveReturnState(item.getFile()); Path temp = extractArchiveToTemp(item.getFile()); if (temp != null) { try { @@ -1643,6 +1657,8 @@ public class FilePanelTab extends JPanel { currentArchiveTempDir = temp; currentArchiveSourceFile = item.getFile(); loadDirectory(temp.toFile(), true, true); + } else { + clearArchiveReturnState(); } } else if (item.isDirectory()) { loadDirectory(item.getFile()); @@ -2007,10 +2023,17 @@ public class FilePanelTab extends JPanel { deleteTempDirRecursively(currentArchiveTempDir); currentArchiveTempDir = null; currentArchiveSourceFile = null; - loadDirectory(parent, false); - - // Select the archive file we just left - SwingUtilities.invokeLater(() -> selectItemByName(archiveName)); + loadDirectory(parent, false, true, () -> { + // Restore original viewport position and keep focus on archive item. + // In BRIEF mode some selection listeners may still run later, so apply once more on EDT tail. + restoreArchiveReturnPosition(); + selectItemByName(archiveName, true, false); + SwingUtilities.invokeLater(() -> { + restoreArchiveReturnPosition(); + selectItemByName(archiveName, true, false); + clearArchiveReturnState(); + }); + }); } return; } @@ -2032,6 +2055,10 @@ public class FilePanelTab extends JPanel { } public void selectItemByName(String name, boolean requestFocus) { + selectItemByName(name, requestFocus, true); + } + + private void selectItemByName(String name, boolean requestFocus, boolean scrollToItem) { 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)) { @@ -2047,7 +2074,9 @@ public class FilePanelTab extends JPanel { if (column < fileTable.getColumnCount()) { briefCurrentColumn = column; fileTable.setRowSelectionInterval(row, row); - fileTable.scrollRectToVisible(fileTable.getCellRect(row, column, true)); + if (scrollToItem) { + fileTable.scrollRectToVisible(fileTable.getCellRect(row, column, true)); + } fileTable.repaint(); if (requestFocus) { fileTable.requestFocusInWindow(); @@ -2062,7 +2091,9 @@ public class FilePanelTab extends JPanel { FileItem item = tableModel.getItem(i); if (item != null && item.getName().equalsIgnoreCase(name)) { fileTable.setRowSelectionInterval(i, i); - fileTable.scrollRectToVisible(fileTable.getCellRect(i, 0, true)); + if (scrollToItem) { + fileTable.scrollRectToVisible(fileTable.getCellRect(i, 0, true)); + } if (requestFocus) { fileTable.requestFocusInWindow(); } @@ -2073,6 +2104,37 @@ public class FilePanelTab extends JPanel { } } + private void rememberArchiveReturnState(File archiveFile) { + if (archiveFile == null) return; + archiveReturnDirectory = archiveFile.getParentFile(); + Rectangle visibleRect = fileTable.getVisibleRect(); + archiveReturnViewPosition = (visibleRect != null) ? visibleRect.getLocation() : null; + } + + private void restoreArchiveReturnPosition() { + if (archiveReturnViewPosition == null || archiveReturnDirectory == null || currentDirectory == null) return; + if (!currentDirectory.equals(archiveReturnDirectory)) return; + + Point target = new Point(archiveReturnViewPosition); + if (fileTable.getParent() instanceof JViewport viewport) { + Dimension pref = fileTable.getPreferredSize(); + int contentW = Math.max(fileTable.getWidth(), pref != null ? pref.width : 0); + int contentH = Math.max(fileTable.getHeight(), pref != null ? pref.height : 0); + int maxX = Math.max(0, contentW - viewport.getWidth()); + int maxY = Math.max(0, contentH - viewport.getHeight()); + target.x = Math.max(0, Math.min(target.x, maxX)); + target.y = Math.max(0, Math.min(target.y, maxY)); + viewport.setViewPosition(target); + } else { + fileTable.scrollRectToVisible(new Rectangle(target.x, target.y, 1, 1)); + } + } + + private void clearArchiveReturnState() { + archiveReturnDirectory = null; + archiveReturnViewPosition = null; + } + /** * Public wrapper to select an item by name from outside this class. * Useful for other UI components to request focusing a specific file.