diff --git a/build.gradle b/build.gradle index 066ff4ef4c..bb26cea58f 100644 --- a/build.gradle +++ b/build.gradle @@ -1525,6 +1525,7 @@ tasks.jacocoTestCoverageVerification { tasks.getByName("run") { jvmArgs(["--add-opens", "java.desktop/sun.awt.X11=ALL-UNNAMED"]) + dependsOn manualZips } tasks.register('debug', JavaExec) { @@ -1545,6 +1546,7 @@ tasks.register('runOnJava17', JavaExec) { mainClass.set application.mainClass classpath = sourceSets.main.runtimeClasspath jvmArgs(["--add-opens", "java.desktop/sun.awt.X11=ALL-UNNAMED"]) + dependsOn manualZips group = 'application' } @@ -1557,6 +1559,7 @@ tasks.register('runOnJava21', JavaExec) { mainClass.set application.mainClass classpath = sourceSets.main.runtimeClasspath jvmArgs(["--add-opens", "java.desktop/sun.awt.X11=ALL-UNNAMED"]) + dependsOn manualZips group = 'application' } diff --git a/src/org/omegat/Bundle.properties b/src/org/omegat/Bundle.properties index 7cf4afacd8..b9ccb43b94 100644 --- a/src/org/omegat/Bundle.properties +++ b/src/org/omegat/Bundle.properties @@ -1962,6 +1962,7 @@ SU_CONFIG_DIR_CREATE_ERROR=Your operating system refused to let OmegaT\n\ SU_SCRIPT_DIR_CREATE_ERROR=It was not possible to create the script folder\n\ inside the configuration folder. The configuration folder will be used\n\ instead. +SU_DATA_DIR_CREATE_ERROR=Your operating system refused to let OmegaT create the application data folder. # HttpConnectionUtils diff --git a/src/org/omegat/help/Help.java b/src/org/omegat/help/Help.java index 626116a297..b520b703f4 100644 --- a/src/org/omegat/help/Help.java +++ b/src/org/omegat/help/Help.java @@ -8,7 +8,7 @@ 2007 Didier Briel 2009 Alex Buloichik 2015 Aaron Madlon-Kay - 2023 Hiroshi Miura + 2023-2025 Hiroshi Miura Home page: https://www.omegat.org/ Support center: https://omegat.org/support @@ -40,10 +40,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; -import java.util.Comparator; import java.util.Properties; import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -89,6 +87,7 @@ public static void showJavadoc() throws IOException { * Shows help in the system browser. * * @throws IOException + * when URI creation failed. */ public static void showHelp() throws IOException { String lang = detectHelpLanguage(); @@ -125,7 +124,12 @@ private static URI getHelpZipFileURI(String lang) { return null; } try { - Path destinationDir = Files.createTempDirectory("omegat-" + OStrings.VERSION + "-help-" + lang); + Path destinationDir = Paths.get(StaticUtils.getApplicationDataDir(), "manual", OStrings.VERSION, lang); + Path indexPath = destinationDir.resolve("index.html"); + if (indexPath.toFile().exists()) { + // already have manual + return indexPath.toUri(); + } return extractZip(zipFile, destinationDir).toURI(); } catch (IOException ignored) { } @@ -144,29 +148,9 @@ private static File extractZip(File file, Path destinationDir) throws IOExceptio zipInputStream.closeEntry(); } } - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - try { - cleanUp(destinationDir); - } catch (IOException e) { - e.printStackTrace(); - } - })); return destinationDir.resolve(OConsts.HELP_HOME).toFile(); } - private static void cleanUp(Path destinationDir) throws IOException { - if (Files.exists(destinationDir)) { - try (Stream walk = Files.walk(destinationDir)) { - walk.sorted(Comparator.reverseOrder()).forEachOrdered(file -> { - try { - Files.delete(file); - } catch (IOException ignored) { - } - }); - } - } - } - public static URI getHelpFileURI(String filename) { return getHelpFileURI(null, filename); } @@ -223,7 +207,7 @@ public static String errorHaiku() { /** * Detects the documentation language to use. - * + *

* If the latest manual is not available in the system locale language, it * returns null, i.e. show a language selection screen. */ diff --git a/src/org/omegat/util/StaticUtils.java b/src/org/omegat/util/StaticUtils.java index f244fd11c6..d47ebd5a7a 100644 --- a/src/org/omegat/util/StaticUtils.java +++ b/src/org/omegat/util/StaticUtils.java @@ -72,20 +72,37 @@ private StaticUtils() { } /** - * Configuration directory on Windows platforms + * Configuration directory on Windows platforms. */ + private static final String WINDOWS_ROAMING_DATA_DIR = "AppData\\Roaming"; private static final String WINDOWS_CONFIG_DIR = "\\OmegaT\\"; /** - * Configuration directory on UNIX platforms + * Configuration directory on UNIX platforms. */ private static final String UNIX_CONFIG_DIR = "/.omegat/"; /** - * Configuration directory on Mac OS X + * Configuration directory on macOS. */ private static final String OSX_CONFIG_DIR = "/Library/Preferences/OmegaT/"; + /** + * Application data directory on Windows platforms. + */ + private static final String WINDOWS_LOCAL_DATA_DIR = "AppData\\Local"; + private static final String WINDOWS_DATA_DIR = "\\OmegaT\\"; + + /** + * Application data directory on UNIX platforms. + */ + private static final String UNIX_DATA_DIR = "/.local/share/OmegaT/"; + + /** + * Application data directory on macOS. + */ + private static final String OSX_DATA_DIR = "/Library/Application Support/OmegaT/"; + /** * Script directory */ @@ -258,7 +275,7 @@ public static String getConfigDir() { // Trying first Vista/7, because "Application Data" exists also as // virtual folder, // so we would not be able to differentiate with 2000/XP otherwise - File appDataFile = new File(home, "AppData\\Roaming"); + File appDataFile = new File(home, WINDOWS_ROAMING_DATA_DIR); if (appDataFile.exists()) { appData = appDataFile.getAbsolutePath(); } else { @@ -329,6 +346,56 @@ public static String getConfigDir() { return configDir; } + /** + * Get application data directory. + * @return directory path to store application data. + */ + public static String getApplicationDataDir() { + String dataDir = null; + String home = getHomeDir(); + // if os or user home is null or empty, we cannot reliably determine + // the data dir, so we use the current working dir (= empty string) + if (StringUtil.isEmpty(home)) { + dataDir = new File(".").getAbsolutePath() + File.separator; + return dataDir; + } + + if (Platform.isWindows) { + File appDataFile = new File(home, WINDOWS_LOCAL_DATA_DIR); + if (appDataFile.exists()) { + dataDir = appDataFile.getAbsolutePath() + WINDOWS_DATA_DIR; + } + } else if (Platform.isUnixLike()) { + dataDir = home + UNIX_DATA_DIR; + } else if (Platform.isMacOSX()) { + // "~/Library/Application Suppport/OmegaT/" + dataDir = home + OSX_DATA_DIR; + } else { + // use the user's home directory by default + dataDir = home + File.separator; + } + if (dataDir == null || dataDir.isEmpty()) { + return new File(".").getAbsolutePath() + File.separator; + } + try { + // check if the dir exists + File dir = new File(dataDir); + if (!dir.exists()) { + // create the dir + boolean created = dir.mkdirs(); + if (!created) { + Log.logErrorRB("SU_DATA_DIR_CREATE_ERROR"); + dataDir = new File(".").getAbsolutePath() + File.separator; + } + } + } catch (SecurityException e) { + // the system doesn't want us to write where we want to write + dataDir = new File(".").getAbsolutePath() + File.separator; + Log.log(e.toString()); + } + return dataDir; + } + public static String getHomeDir() { String home; // user home directory // get os and user home properties