Skip to content

Commit d4eca30

Browse files
ctruedenclaude
andcommitted
Implement magical MIME type handling
This implements addFileTypes(String mimePrefix, String... extensions) as described in the DesktopService interface method javadoc. And updates the LinuxPlatform to match the new reality. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent df9673e commit d4eca30

File tree

2 files changed

+59
-28
lines changed

2 files changed

+59
-28
lines changed

src/main/java/org/scijava/desktop/DefaultDesktopService.java

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,44 +28,89 @@
2828
*/
2929
package org.scijava.desktop;
3030

31+
import org.scijava.log.LogService;
32+
import org.scijava.plugin.Parameter;
3133
import org.scijava.plugin.Plugin;
3234
import org.scijava.service.AbstractService;
33-
import org.scijava.service.SciJavaService;
3435
import org.scijava.service.Service;
3536

37+
import java.io.BufferedReader;
38+
import java.io.IOException;
39+
import java.io.InputStream;
40+
import java.io.InputStreamReader;
41+
import java.nio.charset.StandardCharsets;
3642
import java.util.Collections;
3743
import java.util.HashMap;
3844
import java.util.Map;
3945

4046
/**
41-
* Service interface for an application's desktop-related concerns.
47+
* Default implementation of {@link DesktopService}.
4248
*
4349
* @author Curtis Rueden
4450
*/
4551
@Plugin(type = Service.class)
4652
public class DefaultDesktopService extends AbstractService implements DesktopService {
4753

54+
@Parameter(required = false)
55+
private LogService log;
56+
4857
private final Map<String, String> fileTypes = new HashMap<>();
4958

59+
/** Cached contents of {@code mime-types.txt}, keyed by extension (no leading dot). */
60+
private Map<String, String> mimeDB;
61+
5062
@Override
5163
public void addFileType(String ext, String mimeType) {
5264
fileTypes.put(ext, mimeType);
5365
}
5466

5567
@Override
5668
public void addFileTypes(String mimePrefix, String... extensions) {
57-
throw new UnsupportedOperationException("Not yet implemented");
69+
if (mimeDB == null) initMimeDB();
70+
for (final String ext : extensions) {
71+
final String mimeType = mimeDB.getOrDefault(ext, mimePrefix + "/x-" + ext);
72+
addFileType(ext, mimeType);
73+
}
5874
}
5975

6076
@Override
61-
public void addFileTypes(final Map<String, String> extToMimeType) {
77+
public void addFileTypes(Map<String, String> extToMimeType) {
6278
fileTypes.putAll(extToMimeType);
6379
}
6480

65-
/**
66-
* Gets the map of supported file types.
67-
*/
81+
@Override
6882
public Map<String, String> getFileTypes() {
6983
return Collections.unmodifiableMap(fileTypes);
7084
}
85+
86+
// -- Helper methods - lazy initialization --
87+
88+
/** Initializes {@link #mimeDB} from the built-in {@code mime-types.txt} resource. */
89+
private synchronized void initMimeDB() {
90+
if (mimeDB != null) return; // already initialized
91+
92+
final Map<String, String> db = new HashMap<>();
93+
final String resource = "mime-types.txt";
94+
try (final InputStream is = getClass().getResourceAsStream(resource);
95+
final BufferedReader reader = new BufferedReader(
96+
new InputStreamReader(is, StandardCharsets.UTF_8)))
97+
{
98+
String line;
99+
while ((line = reader.readLine()) != null) {
100+
if (line.startsWith("#") || line.isBlank()) continue;
101+
final int tab = line.indexOf('\t');
102+
if (tab < 0) {
103+
if (log != null) log.warn("Invalid MIME types DB line: " + line);
104+
continue;
105+
}
106+
final String ext = line.substring(0, tab).trim();
107+
final String mime = line.substring(tab + 1).trim();
108+
db.putIfAbsent(ext, mime);
109+
}
110+
}
111+
catch (final IOException e) {
112+
if (log != null) log.error("Failed to load MIME types database", e);
113+
}
114+
mimeDB = db;
115+
}
71116
}

src/main/java/org/scijava/desktop/platform/linux/LinuxPlatform.java

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,6 @@ public class LinuxPlatform extends AbstractPlatform
8282
@Parameter(required = false)
8383
private LogService log;
8484

85-
/** Cached MIME type mapping */
86-
private static Map<String, String> extensionToMime = null;
87-
8885
// -- Platform methods --
8986

9087
@Override
@@ -213,7 +210,7 @@ public void setDesktopIconPresent(final boolean install) throws IOException {
213210
public boolean isFileExtensionsEnabled() {
214211
try {
215212
final DesktopFile df = getOrCreateDesktopFile();
216-
final Map<String, String> mimeMapping = loadMimeTypeMapping();
213+
final Map<String, String> mimeMapping = fileTypes();
217214

218215
// Check if any file extension MIME types are in the .desktop file.
219216
for (final String mimeType : mimeMapping.values()) {
@@ -235,7 +232,7 @@ public boolean isFileExtensionsToggleable() {
235232

236233
@Override
237234
public void setFileExtensionsEnabled(final boolean enable) throws IOException {
238-
final Map<String, String> mimeMapping = loadMimeTypeMapping();
235+
final Map<String, String> mimeMapping = fileTypes();
239236
if (mimeMapping.isEmpty()) {
240237
if (log != null) {
241238
log.warn("No file extensions to register");
@@ -411,25 +408,14 @@ private Map<String, String> fileTypes() {
411408
Collections.emptyMap() : desktopService.getFileTypes();
412409
}
413410

414-
/**
415-
* Loads the file extension to MIME type mapping.
416-
*/
417-
private synchronized Map<String, String> loadMimeTypeMapping() throws IOException {
418-
if (extensionToMime != null) return extensionToMime;
419-
420-
extensionToMime = new LinkedHashMap<>();
421-
422-
final Map<String, String> fileTypes = fileTypes();
423-
// TODO: How do we know the MIME type of each extension?
424-
425-
return extensionToMime;
426-
}
427-
428411
/**
429412
* Registers custom MIME types for formats that don't have standard types.
430-
* Creates ~/.local/share/mime/packages/[appName].xml and runs update-mime-database.
413+
* Creates {@code ~/.local/share/mime/packages/[appName].xml} and runs
414+
* {@code update-mime-database}.
431415
*/
432-
private void registerCustomMimeTypes(final Map<String, String> mimeMapping) throws IOException {
416+
private void registerCustomMimeTypes(final Map<String, String> mimeMapping)
417+
throws IOException
418+
{
433419
// Separate standard from custom MIME types.
434420
final Map<String, String> customTypes = new LinkedHashMap<>();
435421
for (final Map.Entry<String, String> entry : mimeMapping.entrySet()) {

0 commit comments

Comments
 (0)