fixed open with
This commit is contained in:
parent
3b85234e55
commit
2114d2d453
@ -15,7 +15,7 @@ import java.io.InputStreamReader;
|
|||||||
*/
|
*/
|
||||||
public class MainApp {
|
public class MainApp {
|
||||||
|
|
||||||
public static final String APP_VERSION = "1.3.1";
|
public static final String APP_VERSION = "1.3.2";
|
||||||
|
|
||||||
public enum OS {
|
public enum OS {
|
||||||
WINDOWS, LINUX, MACOS, UNKNOWN
|
WINDOWS, LINUX, MACOS, UNKNOWN
|
||||||
|
|||||||
@ -21,6 +21,9 @@ import java.awt.datatransfer.Transferable;
|
|||||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.FileReader;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -1932,19 +1935,50 @@ public class FilePanelTab extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. If executable, start it directly
|
// 2. If it's a directory, navigate to it
|
||||||
if (file.canExecute() && !file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
new ProcessBuilder(file.getAbsolutePath())
|
loadDirectory(file);
|
||||||
.directory(file.getParentFile())
|
return;
|
||||||
.start();
|
|
||||||
} 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();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. Try to find and use system file association
|
||||||
|
String associatedProgram = findAssociatedProgram(file);
|
||||||
|
if (associatedProgram != null && !associatedProgram.isEmpty()) {
|
||||||
|
try {
|
||||||
|
java.util.List<String> cmdList = new java.util.ArrayList<>();
|
||||||
|
cmdList.add(associatedProgram);
|
||||||
|
cmdList.add(file.getAbsolutePath());
|
||||||
|
new ProcessBuilder(cmdList).directory(file.getParentFile()).start();
|
||||||
|
return;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// If association fails, continue to Desktop.open() below
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Try Desktop.open() - most reliable for non-executable files
|
||||||
|
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) {
|
||||||
|
try {
|
||||||
|
Desktop.getDesktop().open(file);
|
||||||
|
return;
|
||||||
|
} catch (Exception desktopEx) {
|
||||||
|
// Continue to next fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. If executable and other methods failed, try to run directly
|
||||||
|
if (file.canExecute()) {
|
||||||
|
try {
|
||||||
|
new ProcessBuilder(file.getAbsolutePath())
|
||||||
|
.directory(file.getParentFile())
|
||||||
|
.start();
|
||||||
|
return;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// Continue to error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. If nothing worked, show error
|
||||||
|
throw new IOException("Cannot open file: " + file.getName() + " (no associated application found)");
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
try {
|
try {
|
||||||
JOptionPane.showMessageDialog(this, "Error opening file: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(this, "Error opening file: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
@ -1996,6 +2030,352 @@ public class FilePanelTab extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the system file association for a given file.
|
||||||
|
* Returns the path to the associated program, or null if not found.
|
||||||
|
*/
|
||||||
|
private String findAssociatedProgram(File file) {
|
||||||
|
if (file == null || !file.isFile()) return null;
|
||||||
|
|
||||||
|
String fileName = file.getName().toLowerCase();
|
||||||
|
String ext = "";
|
||||||
|
int dot = fileName.lastIndexOf('.');
|
||||||
|
if (dot > 0 && dot < fileName.length() - 1) {
|
||||||
|
ext = fileName.substring(dot).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ext.isEmpty()) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (MainApp.CURRENT_OS == MainApp.OS.WINDOWS) {
|
||||||
|
return findWindowsAssociation(ext);
|
||||||
|
} else if (MainApp.CURRENT_OS == MainApp.OS.LINUX) {
|
||||||
|
return findLinuxAssociation(ext);
|
||||||
|
} else if (MainApp.CURRENT_OS == MainApp.OS.MACOS) {
|
||||||
|
return "open"; // macOS uses 'open' command with -a flag for associations
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get system file associations for a given extension.
|
||||||
|
* Returns a map of display names to application paths.
|
||||||
|
*/
|
||||||
|
private java.util.Map<String, String> getSystemAssociations(String ext) {
|
||||||
|
java.util.Map<String, String> result = new java.util.LinkedHashMap<>();
|
||||||
|
|
||||||
|
if (ext == null || ext.isEmpty()) return result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (MainApp.CURRENT_OS == MainApp.OS.WINDOWS) {
|
||||||
|
getWindowsSystemAssociations(ext, result);
|
||||||
|
} else if (MainApp.CURRENT_OS == MainApp.OS.LINUX) {
|
||||||
|
getLinuxSystemAssociations(ext, result);
|
||||||
|
} else if (MainApp.CURRENT_OS == MainApp.OS.MACOS) {
|
||||||
|
getMacSystemAssociations(ext, result);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Windows system associations by querying registry.
|
||||||
|
*/
|
||||||
|
private void getWindowsSystemAssociations(String ext, java.util.Map<String, String> result) {
|
||||||
|
try {
|
||||||
|
// Step 1: Get the file type
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "assoc " + ext);
|
||||||
|
Process p = pb.start();
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
String line = reader.readLine();
|
||||||
|
p.waitFor();
|
||||||
|
|
||||||
|
String fileType = null;
|
||||||
|
if (line != null && line.contains("=")) {
|
||||||
|
fileType = line.substring(line.indexOf("=") + 1).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileType == null || fileType.isEmpty()) return;
|
||||||
|
|
||||||
|
// Step 2: Query registry for shell commands (open, openas, etc.)
|
||||||
|
pb = new ProcessBuilder("reg", "query", "HKEY_CLASSES_ROOT\\" + fileType + "\\shell");
|
||||||
|
p = pb.start();
|
||||||
|
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
java.util.Set<String> verbs = new java.util.HashSet<>();
|
||||||
|
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
line = line.trim();
|
||||||
|
if (line.startsWith("HKEY_CLASSES_ROOT")) {
|
||||||
|
String verb = line.substring(line.lastIndexOf("\\") + 1);
|
||||||
|
if (!verb.isEmpty()) {
|
||||||
|
verbs.add(verb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.waitFor();
|
||||||
|
|
||||||
|
// Step 3: For each verb, get the command
|
||||||
|
for (String verb : verbs) {
|
||||||
|
try {
|
||||||
|
pb = new ProcessBuilder("reg", "query", "HKEY_CLASSES_ROOT\\" + fileType + "\\shell\\" + verb + "\\command");
|
||||||
|
p = pb.start();
|
||||||
|
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
if (line.contains("REG_SZ")) {
|
||||||
|
String command = line.replaceAll(".*REG_SZ", "").trim();
|
||||||
|
// Extract executable path
|
||||||
|
if (command.startsWith("\"")) {
|
||||||
|
command = command.substring(1);
|
||||||
|
int endIdx = command.indexOf("\"");
|
||||||
|
if (endIdx > 0) {
|
||||||
|
command = command.substring(0, endIdx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle case without quotes: path\to\app.exe "%1"
|
||||||
|
int spaceIdx = command.indexOf(" ");
|
||||||
|
if (spaceIdx > 0) {
|
||||||
|
command = command.substring(0, spaceIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File execFile = new File(command);
|
||||||
|
if (execFile.exists() && command.toLowerCase().endsWith(".exe")) {
|
||||||
|
// Get the executable name for display
|
||||||
|
String displayName = execFile.getName();
|
||||||
|
if (displayName.toLowerCase().endsWith(".exe")) {
|
||||||
|
displayName = displayName.substring(0, displayName.length() - 4);
|
||||||
|
}
|
||||||
|
// Capitalize first letter
|
||||||
|
if (!displayName.isEmpty()) {
|
||||||
|
displayName = displayName.substring(0, 1).toUpperCase() + displayName.substring(1);
|
||||||
|
}
|
||||||
|
result.put(displayName + " (" + verb + ")", command);
|
||||||
|
break; // Got command for this verb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.waitFor();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// Continue with next verb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Linux system associations using xdg-mime.
|
||||||
|
*/
|
||||||
|
private void getLinuxSystemAssociations(String ext, java.util.Map<String, String> result) {
|
||||||
|
try {
|
||||||
|
// Get mime type
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("xdg-mime", "query", "filetype", "dummy" + ext);
|
||||||
|
Process p = pb.start();
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
String mimeType = reader.readLine();
|
||||||
|
p.waitFor();
|
||||||
|
|
||||||
|
if (mimeType == null || mimeType.trim().isEmpty()) {
|
||||||
|
result.put("Default application", "xdg-open");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get list of possible applications for this mime type
|
||||||
|
pb = new ProcessBuilder("xdg-mime", "query", "default", mimeType.trim());
|
||||||
|
p = pb.start();
|
||||||
|
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
String defaultApp = reader.readLine();
|
||||||
|
p.waitFor();
|
||||||
|
|
||||||
|
if (defaultApp != null && !defaultApp.trim().isEmpty()) {
|
||||||
|
String[] searchPaths = {
|
||||||
|
System.getProperty("user.home") + "/.local/share/applications/" + defaultApp.trim(),
|
||||||
|
"/usr/share/applications/" + defaultApp.trim(),
|
||||||
|
"/usr/local/share/applications/" + defaultApp.trim()
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String path : searchPaths) {
|
||||||
|
File f = new File(path);
|
||||||
|
if (f.exists()) {
|
||||||
|
try (BufferedReader fr = new BufferedReader(new FileReader(f))) {
|
||||||
|
String line;
|
||||||
|
while ((line = fr.readLine()) != null) {
|
||||||
|
if (line.startsWith("Name=")) {
|
||||||
|
String appName = line.substring(5).trim();
|
||||||
|
String exec = parseDesktopFile(f);
|
||||||
|
if (exec != null && !exec.isEmpty()) {
|
||||||
|
result.put(appName, exec);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
result.put("Default application", "xdg-open");
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get macOS system associations using open command.
|
||||||
|
*/
|
||||||
|
private void getMacSystemAssociations(String ext, java.util.Map<String, String> result) {
|
||||||
|
// On macOS, we can use the 'open' command with -a flag to choose an application
|
||||||
|
// But getting all available apps is complex, so we'll just add the default
|
||||||
|
result.put("Default application", "open");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find Windows file association using assoc and ftype commands.
|
||||||
|
* More reliable than registry queries.
|
||||||
|
*/
|
||||||
|
private String findWindowsAssociation(String ext) {
|
||||||
|
try {
|
||||||
|
// Step 1: Use 'assoc .html' to get the file type (e.g., 'htmlfile')
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "assoc " + ext);
|
||||||
|
Process p = pb.start();
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
String line = reader.readLine();
|
||||||
|
p.waitFor();
|
||||||
|
|
||||||
|
String fileType = null;
|
||||||
|
if (line != null && line.contains("=")) {
|
||||||
|
// Format: '.html=htmlfile'
|
||||||
|
fileType = line.substring(line.indexOf("=") + 1).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileType == null || fileType.isEmpty()) return null;
|
||||||
|
|
||||||
|
// Step 2: Use 'ftype htmlfile' to get the command (e.g., '"C:\Program Files\...\iexplore.exe" "%1"')
|
||||||
|
pb = new ProcessBuilder("cmd", "/c", "ftype " + fileType);
|
||||||
|
p = pb.start();
|
||||||
|
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
line = reader.readLine();
|
||||||
|
p.waitFor();
|
||||||
|
|
||||||
|
if (line != null && line.contains("=")) {
|
||||||
|
// Format: 'htmlfile="C:\Program Files\Internet Explorer\iexplore.exe" "%1"'
|
||||||
|
String command = line.substring(line.indexOf("=") + 1).trim();
|
||||||
|
|
||||||
|
// Extract the executable path from the command
|
||||||
|
// Format: "C:\Program Files\...\app.exe" "%1" or similar
|
||||||
|
if (command.startsWith("\"")) {
|
||||||
|
command = command.substring(1); // Remove leading quote
|
||||||
|
int endIdx = command.indexOf("\"");
|
||||||
|
if (endIdx > 0) {
|
||||||
|
command = command.substring(0, endIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the executable exists
|
||||||
|
File execFile = new File(command);
|
||||||
|
if (execFile.exists() && command.toLowerCase().endsWith(".exe")) {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find Linux file association using xdg-mime and xdg-open.
|
||||||
|
*/
|
||||||
|
private String findLinuxAssociation(String ext) {
|
||||||
|
try {
|
||||||
|
// Use xdg-mime to find the mime type, then find the associated desktop application
|
||||||
|
String mimeType = null;
|
||||||
|
|
||||||
|
// Query mime type for extension
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("xdg-mime", "query", "filetype", "dummy" + ext);
|
||||||
|
Process p = pb.start();
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
String line = reader.readLine();
|
||||||
|
if (line != null) {
|
||||||
|
mimeType = line.trim();
|
||||||
|
}
|
||||||
|
p.waitFor();
|
||||||
|
|
||||||
|
if (mimeType == null || mimeType.isEmpty() || mimeType.equals("application/octet-stream")) {
|
||||||
|
// Try generic approach with xdg-open (it handles associations internally)
|
||||||
|
return "xdg-open";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find default application for mime type
|
||||||
|
pb = new ProcessBuilder("xdg-mime", "query", "default", mimeType);
|
||||||
|
p = pb.start();
|
||||||
|
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
String desktopFile = reader.readLine();
|
||||||
|
p.waitFor();
|
||||||
|
|
||||||
|
if (desktopFile != null && !desktopFile.trim().isEmpty()) {
|
||||||
|
desktopFile = desktopFile.trim();
|
||||||
|
|
||||||
|
// Search for the .desktop file in standard locations
|
||||||
|
String[] searchPaths = {
|
||||||
|
System.getProperty("user.home") + "/.local/share/applications/" + desktopFile,
|
||||||
|
"/usr/share/applications/" + desktopFile,
|
||||||
|
"/usr/local/share/applications/" + desktopFile
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String path : searchPaths) {
|
||||||
|
File f = new File(path);
|
||||||
|
if (f.exists()) {
|
||||||
|
// Parse .desktop file to find the Exec line
|
||||||
|
String exec = parseDesktopFile(f);
|
||||||
|
if (exec != null && !exec.isEmpty()) {
|
||||||
|
return exec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to xdg-open
|
||||||
|
return "xdg-open";
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return "xdg-open"; // Fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a .desktop file to extract the Exec command.
|
||||||
|
*/
|
||||||
|
private String parseDesktopFile(File desktopFile) {
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(desktopFile))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
if (line.startsWith("Exec=")) {
|
||||||
|
String exec = line.substring(5).trim();
|
||||||
|
// Remove any %f, %u, %F, %U placeholders
|
||||||
|
exec = exec.replaceAll("%[fuFU]", "").trim();
|
||||||
|
// Keep only the first word (command)
|
||||||
|
String[] parts = exec.split("\\s+");
|
||||||
|
if (parts.length > 0 && !parts[0].isEmpty()) {
|
||||||
|
return parts[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the item located at the given point (used for double-clicks while
|
* Open the item located at the given point (used for double-clicks while
|
||||||
* mouse-driven selection is blocked). This mirrors the behavior of
|
* mouse-driven selection is blocked). This mirrors the behavior of
|
||||||
@ -2119,12 +2499,14 @@ public class FilePanelTab extends JPanel {
|
|||||||
if (!isParentDir) {
|
if (!isParentDir) {
|
||||||
java.util.List<AppConfig.OpenWithEntry> owEntries = persistedConfig != null ? persistedConfig.getOpenWithEntries() : new java.util.ArrayList<>();
|
java.util.List<AppConfig.OpenWithEntry> owEntries = persistedConfig != null ? persistedConfig.getOpenWithEntries() : new java.util.ArrayList<>();
|
||||||
String itemType;
|
String itemType;
|
||||||
|
String ext = "";
|
||||||
if (isDir) {
|
if (isDir) {
|
||||||
itemType = "directory";
|
itemType = "directory";
|
||||||
} else {
|
} else {
|
||||||
String name = item.getFile().getName().toLowerCase();
|
String name = item.getFile().getName().toLowerCase();
|
||||||
int dot = name.lastIndexOf('.');
|
int dot = name.lastIndexOf('.');
|
||||||
itemType = (dot > 0 && dot < name.length() - 1) ? name.substring(dot + 1) : "";
|
itemType = (dot > 0 && dot < name.length() - 1) ? name.substring(dot + 1) : "";
|
||||||
|
ext = "." + itemType;
|
||||||
}
|
}
|
||||||
|
|
||||||
java.util.List<AppConfig.OpenWithEntry> filtered = new java.util.ArrayList<>();
|
java.util.List<AppConfig.OpenWithEntry> filtered = new java.util.ArrayList<>();
|
||||||
@ -2140,13 +2522,41 @@ public class FilePanelTab extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filtered.isEmpty()) {
|
// Get system file associations
|
||||||
|
java.util.Map<String, String> systemApps = !isDir && !ext.isEmpty() ? getSystemAssociations(ext) : new java.util.HashMap<>();
|
||||||
|
|
||||||
|
if (!filtered.isEmpty() || !systemApps.isEmpty()) {
|
||||||
JMenu openWithMenu = new JMenu("Open with");
|
JMenu openWithMenu = new JMenu("Open with");
|
||||||
|
|
||||||
|
// Add configured "Open with" entries
|
||||||
for (AppConfig.OpenWithEntry e : filtered) {
|
for (AppConfig.OpenWithEntry e : filtered) {
|
||||||
JMenuItem owItem = new JMenuItem(e.label);
|
JMenuItem owItem = new JMenuItem(e.label);
|
||||||
owItem.addActionListener(ae -> runExternalCommand(e.command, item.getFile()));
|
owItem.addActionListener(ae -> runExternalCommand(e.command, item.getFile()));
|
||||||
openWithMenu.add(owItem);
|
openWithMenu.add(owItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add separator if we have both custom and system entries
|
||||||
|
if (!filtered.isEmpty() && !systemApps.isEmpty()) {
|
||||||
|
openWithMenu.addSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add system associations
|
||||||
|
for (java.util.Map.Entry<String, String> entry : systemApps.entrySet()) {
|
||||||
|
JMenuItem appItem = new JMenuItem(entry.getKey());
|
||||||
|
String appPath = entry.getValue();
|
||||||
|
appItem.addActionListener(ae -> {
|
||||||
|
try {
|
||||||
|
java.util.List<String> cmd = new java.util.ArrayList<>();
|
||||||
|
cmd.add(appPath);
|
||||||
|
cmd.add(item.getFile().getAbsolutePath());
|
||||||
|
new ProcessBuilder(cmd).directory(item.getFile().getParentFile()).start();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
try { JOptionPane.showMessageDialog(FilePanelTab.this, "Cannot open file: " + ex.getMessage()); } catch (Exception ignore) {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
openWithMenu.add(appItem);
|
||||||
|
}
|
||||||
|
|
||||||
menu.add(openWithMenu);
|
menu.add(openWithMenu);
|
||||||
} else {
|
} else {
|
||||||
JMenuItem openWithMenuItem = new JMenuItem("Open with");
|
JMenuItem openWithMenuItem = new JMenuItem("Open with");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user