From 2c32493e73329ac7574086ebc4d83fcdf4505e95 Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Fri, 16 Jan 2026 15:57:26 +0100 Subject: [PATCH] command history, translate to english --- src/main/java/com/kfmanager/MainApp.java | 6 +- .../java/com/kfmanager/config/AppConfig.java | 36 +++- .../java/com/kfmanager/model/FileItem.java | 2 +- .../com/kfmanager/service/FileOperations.java | 4 +- src/main/java/com/kfmanager/ui/FilePanel.java | 28 +-- .../java/com/kfmanager/ui/FilePanelTab.java | 44 ++--- .../java/com/kfmanager/ui/MainWindow.java | 171 ++++++++++++------ 7 files changed, 190 insertions(+), 101 deletions(-) diff --git a/src/main/java/com/kfmanager/MainApp.java b/src/main/java/com/kfmanager/MainApp.java index a75971d..e7fea68 100644 --- a/src/main/java/com/kfmanager/MainApp.java +++ b/src/main/java/com/kfmanager/MainApp.java @@ -5,21 +5,21 @@ import com.kfmanager.ui.MainWindow; import javax.swing.*; /** - * Hlavní třída aplikace KF File Manager + * Main application class for KF File Manager */ public class MainApp { public static final String APP_VERSION = "0.0.2"; public static void main(String[] args) { - // Nastavení look and feel podle systému + // Set look and feel to system default try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { e.printStackTrace(); } - // Spuštění GUI v Event Dispatch Thread + // Start GUI in Event Dispatch Thread SwingUtilities.invokeLater(() -> { MainWindow mainWindow = new MainWindow(); mainWindow.setVisible(true); diff --git a/src/main/java/com/kfmanager/config/AppConfig.java b/src/main/java/com/kfmanager/config/AppConfig.java index c84220d..b52c5f7 100644 --- a/src/main/java/com/kfmanager/config/AppConfig.java +++ b/src/main/java/com/kfmanager/config/AppConfig.java @@ -28,7 +28,7 @@ public class AppConfig { try (FileInputStream fis = new FileInputStream(configFile)) { properties.load(fis); } catch (IOException e) { - System.err.println("Nepodařilo se načíst konfiguraci: " + e.getMessage()); + System.err.println("Could not load configuration: " + e.getMessage()); } } } @@ -48,7 +48,7 @@ public class AppConfig { try (FileOutputStream fos = new FileOutputStream(configFile)) { properties.store(fos, "KF File Manager Configuration"); } catch (IOException e) { - System.err.println("Nepodařilo se uložit konfiguraci: " + e.getMessage()); + System.err.println("Could not save configuration: " + e.getMessage()); } } @@ -110,7 +110,7 @@ public class AppConfig { properties.setProperty("rightPanel.path", path); } - // ViewMode konfigurace + // ViewMode configuration public String getLeftPanelViewMode() { return properties.getProperty("leftPanel.viewMode", "FULL"); } @@ -178,7 +178,7 @@ public class AppConfig { properties.setProperty("rightPanel.selectedIndex", String.valueOf(selectedIndex)); } - // Font konfigurace + // Font configuration public String getEditorFontName() { return properties.getProperty("editor.font.name", "Monospaced"); } @@ -533,4 +533,32 @@ public class AppConfig { properties.remove("search.content.history." + i); } } + + // --- Command line history persistence --- + public java.util.List getCommandLineHistory() { + java.util.List list = new java.util.ArrayList<>(); + int count = Integer.parseInt(properties.getProperty("cmd.history.count", "0")); + for (int i = 0; i < count; i++) { + String v = properties.getProperty("cmd.history." + i, null); + if (v != null && !v.isEmpty()) list.add(v); + } + return list; + } + + public void saveCommandLineHistory(java.util.List history) { + if (history == null) { + properties.setProperty("cmd.history.count", "0"); + return; + } + int limit = Math.min(history.size(), 50); + properties.setProperty("cmd.history.count", String.valueOf(limit)); + for (int i = 0; i < limit; i++) { + properties.setProperty("cmd.history." + i, history.get(i)); + } + // remove old entries beyond limit + int old = Integer.parseInt(properties.getProperty("cmd.history.count", "0")); + for (int i = limit; i < old; i++) { + properties.remove("cmd.history." + i); + } + } } diff --git a/src/main/java/com/kfmanager/model/FileItem.java b/src/main/java/com/kfmanager/model/FileItem.java index 545aeb2..a7b65e8 100644 --- a/src/main/java/com/kfmanager/model/FileItem.java +++ b/src/main/java/com/kfmanager/model/FileItem.java @@ -27,7 +27,7 @@ public class FileItem { this.isDirectory = file.isDirectory(); this.marked = false; - // Načíst ikonu ze systému + // Load icon from system this.icon = FileSystemView.getFileSystemView().getSystemIcon(file); } diff --git a/src/main/java/com/kfmanager/service/FileOperations.java b/src/main/java/com/kfmanager/service/FileOperations.java index af22f8f..caaf3b3 100644 --- a/src/main/java/com/kfmanager/service/FileOperations.java +++ b/src/main/java/com/kfmanager/service/FileOperations.java @@ -367,7 +367,7 @@ public class FileOperations { // legacy matchesPattern removed — filename wildcard handling is done via a precompiled Pattern /** - * Callback pro progress operací + * Callback for operation progress */ public interface ProgressCallback { void onProgress(long current, long total, String currentFile); @@ -375,7 +375,7 @@ public class FileOperations { } /** - * Callback pro vyhledávání + * Callback for search */ public interface SearchCallback { void onFileFound(File file); diff --git a/src/main/java/com/kfmanager/ui/FilePanel.java b/src/main/java/com/kfmanager/ui/FilePanel.java index d7535cf..e638826 100644 --- a/src/main/java/com/kfmanager/ui/FilePanel.java +++ b/src/main/java/com/kfmanager/ui/FilePanel.java @@ -144,11 +144,11 @@ public class FilePanel extends JPanel { add(topPanel, BorderLayout.NORTH); - // JTabbedPane pro taby + // JTabbedPane for tabs tabbedPane = new JTabbedPane(); tabbedPane.setTabPlacement(JTabbedPane.TOP); - // Listener pro aktualizaci cesty a stylu při změně tabu + // Listener for updating path and style on tab change tabbedPane.addChangeListener(e -> { updatePathField(); updateTabStyles(); @@ -174,19 +174,19 @@ public class FilePanel extends JPanel { * Add a new tab with a directory */ public void addNewTab(String path) { - // Získat view mode z aktuálního tabu + // Get view mode from current tab ViewMode currentMode = getViewMode(); FilePanelTab tab = new FilePanelTab(path); if (appConfig != null) tab.setAppConfig(appConfig); - // Nastavit callback pro aktualizaci názvu tabu při změně adresáře + // Set callback for updating tab title on directory change tab.setOnDirectoryChanged(() -> updateTabTitle(tab)); // Forward switchPanel callback to the tab so TAB works from any tab tab.setOnSwitchPanelRequested(switchPanelCallback); - // Nastavit stejný view mode jako má aktuální tab + // Set same view mode as current tab if (currentMode != null) { tab.setViewMode(currentMode); } @@ -196,11 +196,11 @@ public class FilePanel extends JPanel { tabbedPane.addTab(tabTitle, tab); tabbedPane.setSelectedComponent(tab); - // Aktualizovat path field + // Update path field updatePathField(); updateTabStyles(); - // Nastavit focus na tabulku v novém tabu + // Set focus to the table in the new tab SwingUtilities.invokeLater(() -> { tab.getFileTable().requestFocusInWindow(); // Ensure renderers are attached now that the tab is added to the UI @@ -209,7 +209,7 @@ public class FilePanel extends JPanel { } /** - * Přidá nový tab a explicitně nastaví ViewMode pro tento tab. + * Add a new tab and explicitly set the ViewMode for this tab. */ public void addNewTabWithMode(String path, ViewMode mode) { FilePanelTab tab = new FilePanelTab(path); @@ -278,7 +278,7 @@ public class FilePanel extends JPanel { } /** - * Obnoví sadu tabů podle zadaných cest a view módů. Pokud je seznam prázdný, nic se nestane. + * Restore the set of tabs according to specified paths and view modes. If the list is empty, nothing happens. */ public void restoreTabs(java.util.List paths, java.util.List viewModes, int selectedIndex) { if (paths == null || paths.isEmpty()) return; @@ -338,7 +338,7 @@ public class FilePanel extends JPanel { private String getTabTitle(String path) { String tabTitle = new File(path).getName(); if (tabTitle.isEmpty()) { - tabTitle = path; // Pro root cesty jako "C:\" + tabTitle = path; // For root paths like "C:\" } return tabTitle; } @@ -351,7 +351,7 @@ public class FilePanel extends JPanel { } /** - * Aktualizuje styl tabů - zvýrazní aktivní tab tučným písmem a barvou. + * Updates tab style - highlights the active tab with bold font and color. */ private void updateTabStyles() { if (tabbedPane == null) return; @@ -364,11 +364,11 @@ public class FilePanel extends JPanel { String title = getTabTitle(dir != null ? dir.getAbsolutePath() : ""); if (i == selectedIndex) { - // Aktivní tab: tučné písmo a tmavě modrá barva + // Active tab: bold font and dark blue color tabbedPane.setTitleAt(i, "" + title + ""); tabbedPane.setForegroundAt(i, new Color(0, 51, 153)); } else { - // Neaktivní tab: normální písmo a výchozí barva + // Inactive tab: normal font and default color tabbedPane.setTitleAt(i, title); tabbedPane.setForegroundAt(i, null); } @@ -479,7 +479,7 @@ public class FilePanel extends JPanel { } } - // Delegování metod na aktuální tab + // Delegation of methods to current tab /** * Switch to the next tab in this panel. diff --git a/src/main/java/com/kfmanager/ui/FilePanelTab.java b/src/main/java/com/kfmanager/ui/FilePanelTab.java index 8164d33..11ff245 100644 --- a/src/main/java/com/kfmanager/ui/FilePanelTab.java +++ b/src/main/java/com/kfmanager/ui/FilePanelTab.java @@ -355,16 +355,16 @@ public class FilePanelTab extends JPanel { // remain visible. fileTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); - // Nastavit Cell Selection mode pouze v BRIEF režimu + // Set Cell Selection mode only in BRIEF mode fileTable.setCellSelectionEnabled(false); fileTable.setRowSelectionAllowed(true); fileTable.setColumnSelectionAllowed(false); - // Odstranit bordery z tabulky + // Remove table borders fileTable.setShowGrid(false); fileTable.setIntercellSpacing(new java.awt.Dimension(0, 0)); - // Nastavit pozadí tabulky stejné jako pozadí panelu + // Set table background same as panel background fileTable.setBackground(this.getBackground()); fileTable.setOpaque(true); @@ -383,9 +383,9 @@ public class FilePanelTab extends JPanel { @Override public void componentResized(java.awt.event.ComponentEvent e) { if (viewMode == ViewMode.BRIEF) { - // Při změně velikosti v BRIEF módu přepočítat layout + // Recalculate layout on resize in BRIEF mode SwingUtilities.invokeLater(() -> { - // Zapamatovat si vybranou položku + // Remember selected item String selectedItemName = null; int selectedRow = fileTable.getSelectedRow(); if (selectedRow >= 0) { @@ -395,13 +395,13 @@ public class FilePanelTab extends JPanel { } } - // Přepočítat layout + // Recalculate layout tableModel.calculateBriefLayout(); tableModel.fireTableStructureChanged(); updateColumnRenderers(); updateColumnWidths(); - // Znovu vybrat položku + // Re-select item if (selectedItemName != null) { selectItemByName(selectedItemName); } @@ -716,7 +716,7 @@ public class FilePanelTab extends JPanel { updateStatus(); - // Oznámit změnu adresáře + // Notify directory change if (onDirectoryChanged != null) { onDirectoryChanged.run(); } @@ -1207,8 +1207,8 @@ public class FilePanelTab extends JPanel { private void updateColumnRenderers() { int columnCount = tableModel.getColumnCount(); if (columnCount == 0 || fileTable.getColumnModel().getColumnCount() != columnCount) { - // Sloupce tabulky se možná ještě nepřevedly po změně struktury. - // Zkusíme to znovu asynchronně po krátkém odložení. + // Table columns might not have been converted yet after structure change. + // Try again asynchronously after a short delay. SwingUtilities.invokeLater(() -> updateColumnRenderers()); return; } @@ -1296,7 +1296,7 @@ public class FilePanelTab extends JPanel { } } - // Zobrazit ikonu pro názvy souborů + // Show icon for file names Icon icon = item.getIcon(); if (item.getName().equals("..")) { icon = new UpArrowIcon(getForeground()); @@ -1305,10 +1305,10 @@ public class FilePanelTab extends JPanel { } if (viewMode == ViewMode.BRIEF) { - // V BRIEF módu jsou všechny sloupce názvy + // In BRIEF mode all columns are names setIcon(icon); } else if (viewMode == ViewMode.FULL && column == 0) { - // V FULL módu je ikona pouze v prvním sloupci (názvy) + // In FULL mode the icon is only in the first column (names) setIcon(icon); } else { setIcon(null); @@ -1340,9 +1340,9 @@ public class FilePanelTab extends JPanel { return; } - // Pokud se ColumnModel ještě nepřizpůsobil nové struktuře (např. po fireTableStructureChanged()), - // počkej a zkus nastavit renderery později - jinak nové sloupce nedostanou renderer a ikony se - // neprojeví v FULL módu. + // If ColumnModel has not yet adapted to the new structure (e.g. after fireTableStructureChanged()), + // wait and try to set renderers later - otherwise new columns won't get a renderer and icons won't + // show up in FULL mode. if (fileTable.getColumnModel().getColumnCount() != columnCount) { SwingUtilities.invokeLater(() -> updateColumnRenderers()); return; @@ -1423,7 +1423,7 @@ public class FilePanelTab extends JPanel { } if (markedCount > 0) { - statusLabel.setText(String.format(" Označeno: %d souborů, %d adresářů (%s)", + statusLabel.setText(String.format(" Selected: %d files, %d directories (%s)", fileCount, dirCount, formatSize(totalSize))); } else { int selectedRow = fileTable.getSelectedRow(); @@ -1448,10 +1448,10 @@ public class FilePanelTab extends JPanel { item.getFormattedDate())); } } else { - statusLabel.setText(String.format(" Položek: %d", tableModel.items.size())); + statusLabel.setText(String.format(" Items: %d", tableModel.items.size())); } } else { - statusLabel.setText(String.format(" Položek: %d", tableModel.items.size())); + statusLabel.setText(String.format(" Items: %d", tableModel.items.size())); } } } @@ -1794,7 +1794,7 @@ public class FilePanelTab extends JPanel { } } - // Gettery + // Getters public JTable getFileTable() { return fileTable; } @@ -1807,10 +1807,10 @@ public class FilePanelTab extends JPanel { return viewMode; } - // FileTableModel - stejný jako v původním FilePanel + // FileTableModel private class FileTableModel extends AbstractTableModel { private List items = new ArrayList<>(); - private String[] columnNames = {"Název", "Velikost", "Datum"}; + private String[] columnNames = {"Name", "Size", "Date"}; public int briefColumns = 1; public int briefRowsPerColumn = 10; diff --git a/src/main/java/com/kfmanager/ui/MainWindow.java b/src/main/java/com/kfmanager/ui/MainWindow.java index 1aa6c42..aa7598e 100644 --- a/src/main/java/com/kfmanager/ui/MainWindow.java +++ b/src/main/java/com/kfmanager/ui/MainWindow.java @@ -20,7 +20,7 @@ public class MainWindow extends JFrame { private FilePanel rightPanel; private FilePanel activePanel; private JPanel buttonPanel; - private JTextField commandLine; + private JComboBox commandLine; private AppConfig config; public MainWindow() { @@ -75,7 +75,7 @@ public class MainWindow extends JFrame { ViewMode leftViewMode = ViewMode.valueOf(config.getLeftPanelViewMode()); leftPanel.setViewMode(leftViewMode); } catch (IllegalArgumentException e) { - // Výchozí hodnota FULL je již nastavena + // Default value FULL is already set } // Right panel - load path and ViewMode from configuration @@ -91,7 +91,7 @@ public class MainWindow extends JFrame { ViewMode rightViewMode = ViewMode.valueOf(config.getRightPanelViewMode()); rightPanel.setViewMode(rightViewMode); } catch (IllegalArgumentException e) { - // Výchozí hodnota FULL je již nastavena + // Default value FULL is already set } mainPanel.add(leftPanel); @@ -146,19 +146,19 @@ public class MainWindow extends JFrame { public void focusGained(FocusEvent e) { activePanel = leftPanel; updateActivePanelBorder(); - // Zajistit, že je vybrán nějaký řádek + // Ensure some row is selected JTable leftTable = leftPanel.getFileTable(); if (leftTable.getSelectedRow() == -1 && leftTable.getRowCount() > 0) { leftTable.setRowSelectionInterval(0, 0); } - // Překreslit oba panely + // Repaint both panels leftPanel.getFileTable().repaint(); rightPanel.getFileTable().repaint(); } @Override public void focusLost(FocusEvent e) { - // Překreslit při ztrátě focusu + // Repaint on focus loss leftPanel.getFileTable().repaint(); } }); @@ -168,19 +168,19 @@ public class MainWindow extends JFrame { public void focusGained(FocusEvent e) { activePanel = rightPanel; updateActivePanelBorder(); - // Zajistit, že je vybrán nějaký řádek + // Ensure some row is selected JTable rightTable = rightPanel.getFileTable(); if (rightTable.getSelectedRow() == -1 && rightTable.getRowCount() > 0) { rightTable.setRowSelectionInterval(0, 0); } - // Překreslit oba panely + // Repaint both panels leftPanel.getFileTable().repaint(); rightPanel.getFileTable().repaint(); } @Override public void focusLost(FocusEvent e) { - // Překreslit při ztrátě focusu + // Repaint on focus loss rightPanel.getFileTable().repaint(); } }); @@ -218,28 +218,42 @@ public class MainWindow extends JFrame { cmdLabel.setFont(new Font("Monospaced", Font.BOLD, 12)); cmdPanel.add(cmdLabel, BorderLayout.WEST); - commandLine = new JTextField(); + commandLine = new JComboBox<>(); + commandLine.setEditable(true); commandLine.setFont(new Font("Monospaced", Font.PLAIN, 12)); - commandLine.setFocusTraversalKeysEnabled(false); - commandLine.addActionListener(e -> executeCommand(commandLine.getText())); - // Let the panels catch focus back if user presses ESC or TAB in command line - commandLine.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { - commandLine.setText(""); - activePanel.getFileTable().requestFocusInWindow(); - e.consume(); - } else if (e.getKeyCode() == KeyEvent.VK_TAB) { - activePanel.getFileTable().requestFocusInWindow(); - e.consume(); + // Handle the editor component (usually a JTextField) + Component editorComp = commandLine.getEditor().getEditorComponent(); + if (editorComp instanceof JTextField) { + JTextField tf = (JTextField) editorComp; + tf.setFocusTraversalKeysEnabled(false); + tf.addActionListener(e -> executeCommand(tf.getText())); + + // Let the panels catch focus back if user presses ESC or TAB in command line + tf.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + tf.setText(""); + activePanel.getFileTable().requestFocusInWindow(); + e.consume(); + } else if (e.getKeyCode() == KeyEvent.VK_TAB) { + activePanel.getFileTable().requestFocusInWindow(); + e.consume(); + } } - } - }); + }); + } cmdPanel.add(commandLine, BorderLayout.CENTER); + // Load history from config + java.util.List history = config.getCommandLineHistory(); + for (int i = 0; i < history.size(); i++) { + commandLine.addItem(history.get(i)); + } + commandLine.getEditor().setItem(""); // Ensure it starts empty + bottomContainer.add(cmdPanel, BorderLayout.NORTH); // Bottom panel with buttons @@ -285,7 +299,7 @@ public class MainWindow extends JFrame { toolBar.addSeparator(); - // Informační label + // Info label JLabel infoLabel = new JLabel(" View Mode "); infoLabel.setFont(infoLabel.getFont().deriveFont(Font.PLAIN, 10f)); toolBar.add(infoLabel); @@ -493,7 +507,7 @@ public class MainWindow extends JFrame { private void setupKeyBindings() { JRootPane rootPane = getRootPane(); - // F3 - Prohlížeč + // F3 - Viewer rootPane.registerKeyboardAction(e -> viewFile(), KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); @@ -560,7 +574,7 @@ public class MainWindow extends JFrame { rootPane.registerKeyboardAction(e -> { if (activePanel != null) { // Always clear command line and return focus to panels - commandLine.setText(""); + commandLine.getEditor().setItem(""); activePanel.getFileTable().requestFocusInWindow(); } }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), @@ -616,6 +630,11 @@ public class MainWindow extends JFrame { rootPane.registerKeyboardAction(e -> closeCurrentTabInActivePanel(), KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW); + + // Ctrl+E - Command line history + rootPane.registerKeyboardAction(e -> showCommandLineHistory(), + KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_DOWN_MASK), + JComponent.WHEN_IN_FOCUSED_WINDOW); } /** @@ -687,7 +706,7 @@ public class MainWindow extends JFrame { * Attach TAB handling to switch panels */ private void addTabKeyHandler(JTable table) { - // Odstraníme standardní chování TAB ve Swing + // Remove standard Swing TAB behavior table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) .put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "switchPanel"); table.getActionMap().put("switchPanel", new AbstractAction() { @@ -709,7 +728,7 @@ public class MainWindow extends JFrame { } }); - // Přidáme F8 pro mazání s vyšší prioritou než defaultní Swing akce + // Add F8 for deleting with higher priority than default Swing actions table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) .put(KeyStroke.getKeyStroke(KeyEvent.VK_F8, 0), "deleteFiles"); table.getActionMap().put("deleteFiles", new AbstractAction() { @@ -757,7 +776,8 @@ public class MainWindow extends JFrame { // Printable characters only (exclude control keys like Enter, Backspace, Esc, Tab) if (c != KeyEvent.CHAR_UNDEFINED && c != '\b' && c != '\n' && c != '\t' && c != 27) { commandLine.requestFocusInWindow(); - commandLine.setText(commandLine.getText() + c); + String current = commandLine.getEditor().getItem().toString(); + commandLine.getEditor().setItem(current + c); e.consume(); } } @@ -767,7 +787,7 @@ public class MainWindow extends JFrame { private void copyFocusedToCommandLine(boolean fullPath) { FileItem focused = activePanel.getFocusedItem(); if (focused != null && !focused.getName().equals("..")) { - String current = commandLine.getText(); + String current = commandLine.getEditor().getItem().toString(); String toAdd = fullPath ? focused.getFile().getAbsolutePath() : focused.getName(); // If it contains spaces, wrap in quotes @@ -776,9 +796,9 @@ public class MainWindow extends JFrame { } if (!current.isEmpty() && !current.endsWith(" ")) { - commandLine.setText(current + " " + toAdd); + commandLine.getEditor().setItem(current + " " + toAdd); } else { - commandLine.setText(current + toAdd); + commandLine.getEditor().setItem(current + toAdd); } commandLine.requestFocusInWindow(); } @@ -808,7 +828,7 @@ public class MainWindow extends JFrame { if (result == JOptionPane.OK_OPTION) { performFileOperation((callback) -> { FileOperations.copy(selectedItems, targetDir, callback); - }, "Kopírování dokončeno", true, targetPanel); + }, "Copy completed", true, targetPanel); } } @@ -836,7 +856,7 @@ public class MainWindow extends JFrame { if (result == JOptionPane.OK_OPTION) { performFileOperation((callback) -> { FileOperations.move(selectedItems, targetDir, callback); - }, "Přesouvání dokončeno", false, activePanel, targetPanel); + }, "Move completed", false, activePanel, targetPanel); } } @@ -867,14 +887,14 @@ public class MainWindow extends JFrame { int result = JOptionPane.showConfirmDialog(this, message.toString(), - "Mazání", + "Delete", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if (result == JOptionPane.YES_OPTION) { performFileOperation((callback) -> { FileOperations.delete(selectedItems, callback); - }, "Mazání dokončeno", false, activePanel); + }, "Delete completed", false, activePanel); // After deletion and refresh, restore selection: stay on same row if possible, // otherwise move selection one row up. @@ -949,7 +969,7 @@ public class MainWindow extends JFrame { final File finalTargetZip = targetZip; performFileOperation((callback) -> { FileOperations.zip(selectedItems, finalTargetZip, callback); - }, "Zabaleno do " + zipName, false, targetPanel); + }, "Zipped into " + zipName, false, targetPanel); } /** @@ -985,7 +1005,7 @@ public class MainWindow extends JFrame { if (result == JOptionPane.OK_OPTION) { performFileOperation((callback) -> { FileOperations.unzip(zipFile, targetDir, callback); - }, "Rozbaleno do " + targetDir.getName(), false, targetPanel); + }, "Unzipped into " + targetDir.getName(), false, targetPanel); } } @@ -1014,7 +1034,7 @@ public class MainWindow extends JFrame { if (newName != null && !newName.trim().isEmpty() && !newName.equals(item.getName())) { performFileOperation((callback) -> { FileOperations.rename(item.getFile(), newName.trim()); - }, "Přejmenování dokončeno", false, activePanel); + }, "Rename completed", false, activePanel); } } } @@ -1139,8 +1159,8 @@ public class MainWindow extends JFrame { } catch (Exception ex) { // Fall back to internal editor if external fails JOptionPane.showMessageDialog(this, - "Nelze spustit externí editor: " + ex.getMessage() + "\nPoužije se interní editor.", - "Chyba", JOptionPane.ERROR_MESSAGE); + "Could not start external editor: " + ex.getMessage() + "\nUsing internal editor.", + "Error", JOptionPane.ERROR_MESSAGE); } } @@ -1153,8 +1173,8 @@ public class MainWindow extends JFrame { * Refresh both panels */ private void refreshPanels() { - // Refresh je nyní automatický při změnách - // Pokud je potřeba manuální refresh, můžeme zavolat loadDirectory + // Refresh is now automatic upon changes + // If manual refresh is needed, we can call loadDirectory if (leftPanel.getCurrentDirectory() != null) { leftPanel.loadDirectory(leftPanel.getCurrentDirectory()); } @@ -1171,6 +1191,16 @@ public class MainWindow extends JFrame { activePanel.setViewMode(mode); } } + + /** + * Show history of command line + */ + private void showCommandLineHistory() { + if (commandLine != null) { + commandLine.requestFocusInWindow(); + commandLine.showPopup(); + } + } /** * Add a new tab to the active panel @@ -1247,8 +1277,8 @@ public class MainWindow extends JFrame { } catch (Exception e) { JOptionPane.showMessageDialog(this, - "Chyba při otevírání terminálu: " + e.getMessage(), - "Chyba", + "Error opening terminal: " + e.getMessage(), + "Error", JOptionPane.ERROR_MESSAGE); } } @@ -1259,6 +1289,9 @@ public class MainWindow extends JFrame { return; } + // Add to history + addCommandToHistory(command.trim()); + File currentDir = activePanel.getCurrentDirectory(); if (currentDir == null) { currentDir = new File(System.getProperty("user.home")); @@ -1309,18 +1342,39 @@ public class MainWindow extends JFrame { if (pb != null) { pb.directory(currentDir); pb.start(); - commandLine.setText(""); // Clear after execution + + // Clear after execution + Component editorComp = commandLine.getEditor().getEditorComponent(); + if (editorComp instanceof JTextField) { + ((JTextField) editorComp).setText(""); + } else { + commandLine.setSelectedItem(""); + } activePanel.getFileTable().requestFocusInWindow(); } } catch (Exception e) { JOptionPane.showMessageDialog(this, - "Chyba při spouštění příkazu: " + e.getMessage(), - "Chyba", + "Error executing command: " + e.getMessage(), + "Error", JOptionPane.ERROR_MESSAGE); } } + private void addCommandToHistory(String command) { + if (command == null || command.isEmpty()) return; + + // Remove if already exists to move it to the top + for (int i = 0; i < commandLine.getItemCount(); i++) { + if (command.equals(commandLine.getItemAt(i))) { + commandLine.removeItemAt(i); + break; + } + } + commandLine.insertItemAt(command, 0); + // We don't necessarily want to select it here as it might interfere with the editor state + } + /** * Show About dialog */ @@ -1351,7 +1405,7 @@ public class MainWindow extends JFrame { * Execute file operation with error handling */ private void performFileOperation(FileOperation operation, String successMessage, boolean showBytes, FilePanel... panelsToRefresh) { - ProgressDialog progressDialog = new ProgressDialog(this, "Operační systém"); + ProgressDialog progressDialog = new ProgressDialog(this, "File Operation"); progressDialog.setDisplayAsBytes(showBytes); FileOperations.ProgressCallback callback = new FileOperations.ProgressCallback() { @@ -1379,15 +1433,15 @@ public class MainWindow extends JFrame { } } if (callback.isCancelled()) { - JOptionPane.showMessageDialog(MainWindow.this, "Operace byla přerušena uživatelem."); + JOptionPane.showMessageDialog(MainWindow.this, "Operation was cancelled by user."); } }); } catch (Exception e) { SwingUtilities.invokeLater(() -> { progressDialog.dispose(); JOptionPane.showMessageDialog(MainWindow.this, - "Chyba: " + e.getMessage(), - "Chyba", + "Error: " + e.getMessage(), + "Error", JOptionPane.ERROR_MESSAGE); }); } @@ -1445,8 +1499,15 @@ public class MainWindow extends JFrame { } catch (Exception ex) { // ignore } + + // Save command history + java.util.List cmdHistory = new java.util.ArrayList<>(); + for (int i = 0; i < commandLine.getItemCount(); i++) { + cmdHistory.add(commandLine.getItemAt(i)); + } + config.saveCommandLineHistory(cmdHistory); - // Uložit konfiguraci do souboru + // Save configuration to file config.saveConfig(); // Exit application