001package arcommon; 002 003import java.util.Locale; 004 005import arcommon.exception.ExceptionUtil; 006import arcommon.exception.ExceptionViewDialog; 007import arcommon.exception.MyLog; 008import arcommon.persistens.ISettings; 009import arcommon.persistens.SettingsUtil; 010import arcommon.ui.other.GUIUtil; 011/** 012 * A general application utilities class. 013 * <br> 014 * To use the some of the fields in this class, properties must be added to the module's <a href="http://yautar.dk/Java/ABT/ABT Download site.html">ABT</a> module property file. 015 * See each field for details. 016 */ 017public class ApplicationUtil { 018 public static boolean printStartMessage = true; 019 public static boolean printConfiguration = true; 020 private static boolean printUserHome = true; 021 private static boolean printUserHomeChanged = false; 022 public static boolean printUserDataPath = true; 023 public static boolean printApplicationStartPath = false; 024 public static boolean includeVersionInDefaultFrameTitle = true; 025 026 public static boolean fixLocale = true; 027 028 private static String applicationName; 029 private static String version; 030 private static int build; 031 032 public static final boolean DEVELOPMENT_MODE = Boolean.getBoolean("DevelopmentMode"); 033 034 /** 035 * Contains the users home directory / path (The root of all user specific data). 036 * <br> 037 * To use the {@link #USER_HOME} field the following must be added to the module's <a href="http://yautar.dk/Java/ABT/ABT Download site.html">ABT</a> module property file:<br> 038 * Package.Desktop.UserHomeSystemProperty=UserHome<br> 039 */ 040 public static final String USER_HOME = System.getProperty("UserHome", ""); 041 042 public static final String USER_DATA_PATH_SYSTEM_PROPERTY_NAME = "UserDataPath"; 043 044 /** 045 * Contains the path to this applications user specific data. 046 * <br> 047 * To use the {@link #USER_DATA_PATH} field the following must be added to the module's <a href="http://yautar.dk/Java/ABT/ABT Download site.html">ABT</a> Module Property file:<br> 048 * Package.Desktop.UserDataPathSystemProperty=UserDataPath<br> 049 */ 050 public static final String USER_DATA_PATH = System.getProperty(USER_DATA_PATH_SYSTEM_PROPERTY_NAME, ""); 051 052 /** 053 * Contains the path from where this application was started. This might be the same as current directory. 054 * <br> 055 * To use the {@link #APPLICATION_START_PATH} field the following must be added to the module's <a href="http://yautar.dk/Java/ABT/ABT Download site.html">ABT</a> Module Property file:<br> 056 * Package.Desktop.ApplicationStartPathSystemProperty=ApplicationStartPath<br> 057 */ 058 public static final String APPLICATION_START_PATH = System.getProperty("ApplicationStartPath", ""); 059 060 private static enum APPLICATION_TYPE {GUI, TUI, OTHER}; 061 062 public static void setPrintUserHome(boolean pprintUserHome) { 063 printUserHome = pprintUserHome; 064 printUserHomeChanged = true; 065 } 066 067 public static void initGuiApplication(String papplicationName) { 068 initGuiApplication(papplicationName, null, 0); 069 } 070 071 public static void initGuiApplication(String papplicationName, String pversion, int pbuild) { 072 initApplication(papplicationName, APPLICATION_TYPE.GUI, pversion, pbuild, true, null, null); 073 } 074 075 public static void initGuiApplicationDontSetCrashLog(String papplicationName, String pversion, int pbuild) { 076 initApplication(papplicationName, APPLICATION_TYPE.GUI, pversion, pbuild, false, null, null); 077 } 078 079 public static void initGuiApplication(String papplicationName, ISettings defaultSettings) { 080 initGuiApplication(papplicationName, null, 0, defaultSettings); 081 } 082 083 public static void initGuiApplication(String papplicationName, String pversion, int pbuild, ISettings defaultSettings) { 084 initApplication(papplicationName, APPLICATION_TYPE.GUI, pversion, pbuild, true, defaultSettings, null); 085 } 086 087 public static void initGuiApplication(String papplicationName, Class<? extends ISettings> defaultSettingsClass) { 088 initGuiApplication(papplicationName, null, 0, defaultSettingsClass); 089 } 090 091 public static void initGuiApplication(String papplicationName, String pversion, int pbuild, Class<? extends ISettings> defaultSettingsClass) { 092 initApplication(papplicationName, APPLICATION_TYPE.GUI, pversion, pbuild, true, null, defaultSettingsClass); 093 } 094 095 public static void initTuiApplication(String papplicationName) { 096 initTuiApplication(papplicationName, null, 0); 097 } 098 099 public static void initTuiApplication(String papplicationName, String pversion, int pbuild) { 100 initApplication(papplicationName, APPLICATION_TYPE.TUI, pversion, pbuild, true, null, null); 101 } 102 103 public static void initTuiApplication(String papplicationName, ISettings defaultSettings) { 104 initTuiApplication(papplicationName, null, 0, defaultSettings); 105 } 106 107 public static void initTuiApplication(String papplicationName, String pversion, int pbuild, ISettings defaultSettings) { 108 initApplication(papplicationName, APPLICATION_TYPE.TUI, pversion, pbuild, true, defaultSettings, null); 109 } 110 111 public static void initTuiApplication(String papplicationName, Class<? extends ISettings> defaultSettingsClass) { 112 initTuiApplication(papplicationName, null, 0, defaultSettingsClass); 113 } 114 115 public static void initTuiApplication(String papplicationName, String pversion, int pbuild, Class<? extends ISettings> defaultSettingsClass) { 116 initApplication(papplicationName, APPLICATION_TYPE.TUI, pversion, pbuild, true, null, defaultSettingsClass); 117 } 118 119 public static void initOtherApplication(String papplicationName, String pversion, int pbuild, Class<? extends ISettings> defaultSettingsClass) { 120 initApplication(papplicationName, APPLICATION_TYPE.OTHER, pversion, pbuild, true, null, defaultSettingsClass); 121 } 122 123 private static void initApplication(String papplicationName, APPLICATION_TYPE applicationType, String pversion, int pbuild, boolean setCrashLogFileName, ISettings defaultSettings, Class<? extends ISettings> defaultSettingsClass) { 124 applicationName = papplicationName; 125 version = pversion; 126 build = pbuild; 127 if (papplicationName == null) { 128 throw new RuntimeException("papplicationName == null"); 129 } 130 if (applicationName.length() == 0) { 131 throw new RuntimeException("applicationName.length() == 0"); 132 } 133 if (!applicationName.equals(applicationName.trim())) { 134 throw new RuntimeException("!applicationName.equals(applicationName.trim()) " + applicationName); 135 } 136 if (pbuild < 0) { 137 throw new RuntimeException("pbuild < 0"); 138 } 139 if (printStartMessage) { 140 if (version != null && version.length() > 0 && build > 0) { 141 System.out.println(applicationName + " version " + version + " (Build: " + build + ") is running" + (DEVELOPMENT_MODE ? " (Development mode active)" : "")); 142 } else { 143 if (version != null && version.length() > 0) { 144 System.out.println(applicationName + " version " + version + " is running" + (DEVELOPMENT_MODE ? " (Development mode active)" : "")); 145 } else { 146 System.out.println(applicationName + " is running" + (DEVELOPMENT_MODE ? " (Development mode active)" : "")); 147 } 148 } 149 } 150 151 switch (applicationType) { 152 case GUI : 153 ExceptionUtil.installStandardGuiExceptionHandler(); 154 ExceptionViewDialog.autoShowDetails = DEVELOPMENT_MODE; 155 break; 156 case TUI : 157 ExceptionUtil.installStandardTuiExceptionHandler(); 158 if (printConfiguration && !printUserHomeChanged) { 159 printUserHome = false; 160 } 161 break; 162 case OTHER : 163 ; 164 break; 165 default : 166 throw new RuntimeException("Unknown applicationType " + applicationType); 167 } 168 169 if (setCrashLogFileName) { 170 String crashLogFileName = USER_DATA_PATH + "Crash log for " + applicationName + ".txt"; 171 MyLog.logFileName = crashLogFileName; 172 if (printConfiguration) { 173 System.out.println("CRASH_LOG_FILE_NAME: " + crashLogFileName); 174 } 175 } 176 177 if (defaultSettings != null || defaultSettingsClass != null) { 178 String settingsFileName = calculateSettingsFileName(applicationName); 179 SettingsUtil.setSettingsFileName(settingsFileName); 180 if (printConfiguration) { 181 System.out.println("SETTINGS_FILE_NAME: " + settingsFileName); 182 } 183 } 184 if (defaultSettings != null) { 185 SettingsUtil.setDefaultSettings(defaultSettings); 186 } 187 if (defaultSettingsClass != null) { 188 SettingsUtil.setDefaultSettingsClass(defaultSettingsClass); 189 } 190 191 GUIUtil.defaultSelectAFileOrDirectoryPath = USER_HOME; 192 if (printConfiguration) { 193 if (printUserHome) { 194 System.out.println("USER_HOME: " + USER_HOME); 195 } 196 if (printUserDataPath) { 197 System.out.println("USER_DATA_PATH: " + USER_DATA_PATH); 198 } 199 if (printApplicationStartPath) { 200 System.out.println("APPLICATION_START_PATH: " + APPLICATION_START_PATH); 201 } 202 } 203 204 GUIUtil.setLinuxApplicationName(applicationName); 205 206 if (fixLocale) { 207 fixLocale(); 208 } 209 } 210 211 private static String calculateSettingsFileName(String papplicationName) { 212 String defaultSettingsFileName = papplicationName + " settings.xml"; 213 214 if (USER_DATA_PATH.length() > 0) { 215 return USER_DATA_PATH + defaultSettingsFileName; 216 } 217 218 String settingsFileNameProperty = System.getProperty("SettingsFileName"); 219 if (settingsFileNameProperty != null && settingsFileNameProperty.length() > 0) { 220 return settingsFileNameProperty; 221 } 222 223 return defaultSettingsFileName; 224 } 225 226 public static String getDefaultApplicationFrameTitle() { 227 if (includeVersionInDefaultFrameTitle && isApplicationVersionAndBuildSet()) { 228 return getApplicationName() + " (" + getApplicationVersion() + ")"; 229 } 230 231 return getApplicationName(); 232 } 233 234 public static String getApplicationName() { 235 if (applicationName == null) { 236 throw new RuntimeException("applicationName == null. Use initApplication...() to set it."); 237 } 238 239 return applicationName; 240 } 241 242 public static boolean isApplicationVersionAndBuildSet() { 243 return version != null; 244 } 245 246 public static String getApplicationVersion() { 247 if (version == null) { 248 throw new RuntimeException("version == null. Use initApplication...() to set it."); 249 } 250 251 return version; 252 } 253 254 public static int getApplicationBuild() { 255 if (version == null) { 256 throw new RuntimeException("version == null. Use initApplication...() to set version and build."); 257 } 258 259 return build; 260 } 261 262 public static boolean isApplicationInstalled() { 263 // This is a hacky way to detect if the application installed 264 if (USER_HOME != null && USER_HOME.length() > 0) { 265 return true; 266 } 267 268 if (USER_DATA_PATH != null && USER_DATA_PATH.length() > 0) { 269 return true; 270 } 271 272 return false; 273 } 274 275 /** 276 * This mighty no be the right fix, but it seems to fix the problem that decimal and grouping separators are wrong if "en_DK" is used as locale on Linux. 277 * <br> 278 * If "en_DK" is used as locale, the language is correctly set to English, but the decimal and grouping separators are not set to the Danish format.<br> 279 * This code seems to fix that problem, but might not be the right way to fix it.<br> 280 * The problem seems occur if the environment variable "LANG" is different from the environment variable "LC_NUMERIC". 281 */ 282 public static void fixLocale() { 283 if (!Util.isLinuxOS()) { 284 return ; 285 } 286 287 // Since 9 288// String fullCommandLine = ProcessHandle.current().info().commandLine().orElseThrow(); 289 // This requires --add-opens java.base/java.lang=ALL-UNNAMED 290/* if (Util.isJavaVersionAtLeast(9)) { 291 Class<?> processHandleClass = ReflectionUtil.loadClass("java.lang.ProcessHandle"); 292 Object currentReturn = ReflectionUtil.invokeStaticMethod(processHandleClass, "current"); 293 Object infoReturn = ReflectionUtil.invokeMethod(currentReturn, "info"); 294 Object commandLineReturn = ReflectionUtil.invokeMethod(infoReturn, "commandLine"); 295 String fullCommandLine = (String)ReflectionUtil.invokeMethod(commandLineReturn, "orElseThrow"); 296 if (fullCommandLine.contains(" -Duser.country=")) { 297 return ; 298 } 299 }*/ 300 301 String numericEnvironment = System.getenv("LC_NUMERIC"); 302 if (numericEnvironment == null || numericEnvironment.length() == 0) { 303 numericEnvironment = System.getenv("LC_ALL"); 304 } 305 306 String languageEnvironment = System.getenv("LANG"); 307 if (StringUtil.stringEquals(numericEnvironment, languageEnvironment)) { 308 return ; 309 } 310 311 if (numericEnvironment == null || numericEnvironment.length() == 0) { 312 return ; 313 } 314 315 String[] groups = StringUtil.getGroupsForRegExpAsFlatArray(numericEnvironment, "([a-zA-Z]+)_([a-zA-Z]+).UTF-8"); 316 if (groups == null || groups.length != 2) { 317 return ; 318 } 319 320 String language = groups[0]; 321 String country = groups[1]; 322 System.out.println("ApplicationUtil: Fixing locale numeric to language=\"" + language + "\" and country=\"" + country + "\""); 323 Locale.setDefault(new Locale(language, country)); 324 } 325}