windows support added

This commit is contained in:
rdavidek 2026-01-25 21:48:37 +01:00
parent 5762e24df6
commit 3418313aeb
5 changed files with 152 additions and 15 deletions

10
pom.xml
View File

@ -97,5 +97,15 @@
<artifactId>junrar</artifactId> <artifactId>junrar</artifactId>
<version>7.4.1</version> <version>7.4.1</version>
</dependency> </dependency>
<dependency>
<groupId>com.formdev</groupId>
<artifactId>flatlaf</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.formdev</groupId>
<artifactId>flatlaf-extras</artifactId>
<version>3.5.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,10 +1,14 @@
package cz.kamma.kfmanager; package cz.kamma.kfmanager;
import cz.kamma.kfmanager.ui.MainWindow; import cz.kamma.kfmanager.ui.MainWindow;
import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatLightLaf;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/** /**
* Main application class for KF File Manager * Main application class for KF File Manager
@ -17,11 +21,26 @@ public class MainApp {
// Set application name for X11/Wayland WM_CLASS // Set application name for X11/Wayland WM_CLASS
System.setProperty("awt.app.name", "cz-kamma-kfmanager-MainApp"); System.setProperty("awt.app.name", "cz-kamma-kfmanager-MainApp");
// Set look and feel to system default // Use FlatLaf for modern look and better system theme support
try { try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); if (System.getProperty("os.name").toLowerCase().contains("win")) {
// On Windows, use FlatLaf and detect system theme (light/dark)
if (isWindowsDarkMode()) {
FlatDarkLaf.setup();
} else {
FlatLightLaf.setup();
}
} else {
// On Linux and macOS, use FlatLaf as a better-looking alternative
// to the default system L&F
FlatLightLaf.setup();
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
} }
// Enable arrow key navigation in JOptionPane dialogs // Enable arrow key navigation in JOptionPane dialogs
@ -34,6 +53,22 @@ public class MainApp {
}); });
} }
private static boolean isWindowsDarkMode() {
try {
Process process = Runtime.getRuntime().exec("reg query \"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize\" /v AppsUseLightTheme");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("AppsUseLightTheme")) {
return line.contains("0x0");
}
}
} catch (Exception e) {
// ignore and fallback to light
}
return false;
}
private static void setupGlobalKeyNavigation() { private static void setupGlobalKeyNavigation() {
Toolkit.getDefaultToolkit().addAWTEventListener(event -> { Toolkit.getDefaultToolkit().addAWTEventListener(event -> {
if (event instanceof KeyEvent) { if (event instanceof KeyEvent) {

View File

@ -774,6 +774,13 @@ public class FilePanel extends JPanel {
} }
} }
public void navigateUp() {
FilePanelTab tab = getCurrentTab();
if (tab != null) {
tab.navigateUp();
}
}
public void showArchiveFile(File archive, String entryName) { public void showArchiveFile(File archive, String entryName) {
FilePanelTab tab = getCurrentTab(); FilePanelTab tab = getCurrentTab();
if (tab != null) { if (tab != null) {

View File

@ -63,7 +63,7 @@ public class FilePanelTab extends JPanel {
private Runnable onDirectoryChanged; private Runnable onDirectoryChanged;
private Runnable onSwitchPanelRequested; private Runnable onSwitchPanelRequested;
// Appearance customization // Appearance customization
private Color selectionColor = new Color(184, 207, 229); private Color selectionColor = null;
private Color markedColor = new Color(204, 153, 0); private Color markedColor = new Color(204, 153, 0);
// Sorting state for FULL mode header clicks // Sorting state for FULL mode header clicks
private int sortColumn = -1; // 0=name,1=size,2=date private int sortColumn = -1; // 0=name,1=size,2=date
@ -1462,7 +1462,21 @@ public class FilePanelTab extends JPanel {
cmdList.add(fullPath); cmdList.add(fullPath);
} }
new ProcessBuilder(cmdList).directory(file.getParentFile()).start(); try {
new ProcessBuilder(cmdList).directory(file.getParentFile()).start();
} catch (IOException ex) {
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("win")) {
// Try via cmd.exe for Windows shell commands/scripts
new ProcessBuilder("cmd", "/c", trimmedCmd + (hasPlaceholder ? "" : " \"" + fullPath + "\""))
.directory(file.getParentFile()).start();
} else if (osName.contains("linux") || osName.contains("mac")) {
new ProcessBuilder("sh", "-c", trimmedCmd + (hasPlaceholder ? "" : " '" + fullPath + "'"))
.directory(file.getParentFile()).start();
} else {
throw ex;
}
}
} catch (Exception ex) { } catch (Exception ex) {
try { JOptionPane.showMessageDialog(this, "Cannot execute command: " + ex.getMessage()); } catch (Exception ignore) {} try { JOptionPane.showMessageDialog(this, "Cannot execute command: " + ex.getMessage()); } catch (Exception ignore) {}
} }
@ -2368,6 +2382,15 @@ public class FilePanelTab extends JPanel {
// Hide table header in BRIEF mode to save vertical space and match requirements // Hide table header in BRIEF mode to save vertical space and match requirements
if (fileTable.getTableHeader() != null) { if (fileTable.getTableHeader() != null) {
fileTable.getTableHeader().setVisible(mode != ViewMode.BRIEF); fileTable.getTableHeader().setVisible(mode != ViewMode.BRIEF);
// In JScrollPane, manually managing columnHeader might be necessary to reclaim space
Component parent = fileTable.getParent();
if (parent instanceof JViewport) {
Component scroll = parent.getParent();
if (scroll instanceof JScrollPane) {
JScrollPane sp = (JScrollPane) scroll;
sp.setColumnHeaderView(mode == ViewMode.BRIEF ? null : fileTable.getTableHeader());
}
}
} }
briefCurrentColumn = 0; briefCurrentColumn = 0;
updateColumnRenderers(); updateColumnRenderers();
@ -2557,7 +2580,7 @@ public class FilePanelTab extends JPanel {
// Show selection highlight even when the table doesn't have focus, but only // Show selection highlight even when the table doesn't have focus, but only
// if this panel/tab is the active one. // if this panel/tab is the active one.
if (isCurrentCell && FilePanelTab.this.active) { if (isCurrentCell && FilePanelTab.this.active) {
setBackground(selectionColor); setBackground(selectionColor != null ? selectionColor : table.getSelectionBackground());
} else { } else {
setBackground(FilePanelTab.this.getBackground()); setBackground(FilePanelTab.this.getBackground());
} }
@ -2581,7 +2604,11 @@ public class FilePanelTab extends JPanel {
setFont(baseFont.deriveFont(baseStyle)); setFont(baseFont.deriveFont(baseStyle));
// Automatically adjust foreground contrast // Automatically adjust foreground contrast
if (isCurrentCell && FilePanelTab.this.active) { if (isCurrentCell && FilePanelTab.this.active) {
setForeground(isDark(selectionColor) ? Color.WHITE : Color.BLACK); if (selectionColor != null) {
setForeground(isDark(selectionColor) ? Color.WHITE : Color.BLACK);
} else {
setForeground(table.getSelectionForeground());
}
} else { } else {
setForeground(isDark(FilePanelTab.this.getBackground()) ? Color.WHITE : Color.BLACK); setForeground(isDark(FilePanelTab.this.getBackground()) ? Color.WHITE : Color.BLACK);
} }

View File

@ -2138,8 +2138,21 @@ public class MainWindow extends JFrame {
ProcessBuilder pb = null; ProcessBuilder pb = null;
if (osName.contains("win")) { if (osName.contains("win")) {
// Windows // Windows - try Windows Terminal first, then PowerShell, then cmd
pb = new ProcessBuilder("cmd.exe", "/c", "start", "cmd.exe"); try {
// Try to use Windows Terminal if available
new ProcessBuilder("wt.exe", "-d", currentDir.getAbsolutePath()).start();
return;
} catch (Exception e1) {
try {
// Fallback to PowerShell
new ProcessBuilder("powershell.exe").directory(currentDir).start();
return;
} catch (Exception e2) {
// Final fallback to cmd
pb = new ProcessBuilder("cmd.exe", "/c", "start", "cmd.exe");
}
}
} else if (osName.contains("mac")) { } else if (osName.contains("mac")) {
// macOS // macOS
pb = new ProcessBuilder("open", "-a", "Terminal", currentDir.getAbsolutePath()); pb = new ProcessBuilder("open", "-a", "Terminal", currentDir.getAbsolutePath());
@ -2191,15 +2204,46 @@ public class MainWindow extends JFrame {
return; return;
} }
String trimmed = command.trim();
// Add to history // Add to history
addCommandToHistory(command.trim()); addCommandToHistory(trimmed);
// Handle internal commands like 'cd'
if (trimmed.toLowerCase().startsWith("cd ") || trimmed.toLowerCase().equals("cd..") || trimmed.equals("..")) {
String targetPath = null;
if (trimmed.equals("..") || trimmed.toLowerCase().equals("cd..")) {
targetPath = "..";
} else {
targetPath = trimmed.substring(3).trim();
if (targetPath.startsWith("\"") && targetPath.endsWith("\"")) {
targetPath = targetPath.substring(1, targetPath.length() - 1);
}
}
if (activePanel != null) {
if ("..".equals(targetPath)) {
activePanel.navigateUp();
} else {
File targetDir = new File(activePanel.getCurrentDirectory(), targetPath);
if (targetDir.exists() && targetDir.isDirectory()) {
activePanel.loadDirectory(targetDir);
} else {
// try absolute path
targetDir = new File(targetPath);
if (targetDir.exists() && targetDir.isDirectory()) {
activePanel.loadDirectory(targetDir);
}
}
}
}
} else {
// Execute natively for other commands
executeNative(trimmed, null);
}
// Final prompt update after command execution (path might have changed) // Final prompt update after command execution (path might have changed)
updateCommandLinePrompt(); updateCommandLinePrompt();
// Execute natively, not via bash wrapper
executeNative(command.trim(), null);
// Clear after execution and return focus // Clear after execution and return focus
Component editorComp = commandLine.getEditor().getEditorComponent(); Component editorComp = commandLine.getEditor().getEditorComponent();
if (editorComp instanceof JTextField) { if (editorComp instanceof JTextField) {
@ -2224,7 +2268,20 @@ public class MainWindow extends JFrame {
currentDir = new File(System.getProperty("user.home")); currentDir = new File(System.getProperty("user.home"));
} }
String osName = System.getProperty("os.name").toLowerCase();
try { try {
String trimmedCmd = command.trim();
// Special case for Windows terminal commands - launch in a new window
if (osName.contains("win")) {
String cmdLower = trimmedCmd.toLowerCase();
if (cmdLower.equals("cmd") || cmdLower.equals("powershell") ||
cmdLower.equals("pwsh") || cmdLower.equals("wt")) {
new ProcessBuilder("cmd", "/c", "start", cmdLower).directory(currentDir).start();
return;
}
}
// Check if it's a file path that exists (and not a complex command) // Check if it's a file path that exists (and not a complex command)
if (!command.contains(" ") || (command.startsWith("\"") && command.endsWith("\"") && !command.substring(1, command.length()-1).contains("\""))) { if (!command.contains(" ") || (command.startsWith("\"") && command.endsWith("\"") && !command.substring(1, command.length()-1).contains("\""))) {
String path = command.startsWith("\"") ? command.substring(1, command.length()-1) : command; String path = command.startsWith("\"") ? command.substring(1, command.length()-1) : command;
@ -2247,10 +2304,11 @@ public class MainWindow extends JFrame {
try { try {
new ProcessBuilder(cmdList).directory(currentDir).start(); new ProcessBuilder(cmdList).directory(currentDir).start();
} catch (IOException ex) { } catch (IOException ex) {
// Fallback for Linux/macOS: try via shell // Fallback for different OS: try via shell
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("linux") || osName.contains("mac")) { if (osName.contains("linux") || osName.contains("mac")) {
new ProcessBuilder("sh", "-c", command).directory(currentDir).start(); new ProcessBuilder("sh", "-c", command).directory(currentDir).start();
} else if (osName.contains("win")) {
new ProcessBuilder("cmd", "/c", command).directory(currentDir).start();
} else { } else {
throw ex; throw ex;
} }