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     * &nbsp;&nbsp;&nbsp;&nbsp;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     * &nbsp;&nbsp;&nbsp;&nbsp;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     * &nbsp;&nbsp;&nbsp;&nbsp;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}