001package jmri.util;
002
003import java.awt.GraphicsConfiguration;
004import java.awt.GraphicsEnvironment;
005import java.awt.geom.AffineTransform;
006import java.io.*;
007import java.util.ArrayList;
008import java.util.List;
009import java.util.Properties;
010
011import jmri.InstanceManager;
012import jmri.ShutDownManager;
013
014/**
015 * Allow the user to configure properties that needs to be setup very early
016 * when JMRI starts, for example before Swing starts up.
017 * 
018 * @author Daniel Bergqvist Copyright (C) 2021
019 */
020public class EarlyInitializationPreferences {
021
022    private static final String FILENAME = jmri.util.FileUtil
023            .getExternalFilename("settings:JMRI_InitPreferences.properties");
024
025    private static final EarlyInitializationPreferences INSTANCE =
026            new EarlyInitializationPreferences();
027
028    private final Properties preferences = new Properties();
029
030    // The preferences might have been changed after startup, but we want to
031    // keep a list of the preferences used at startup for the JMRI Context.
032    private final List<String> startupPrefs = new ArrayList<>();
033
034
035    private EarlyInitializationPreferences() {
036        // Private constructor to protect singleton pattern.
037    }
038
039    public static EarlyInitializationPreferences getInstance() {
040        return INSTANCE;
041    }
042
043    public String getPreference(String pref) {
044        return preferences.getProperty(pref);
045    }
046
047    public void setPreference(String pref, String value) {
048        preferences.setProperty(pref, value);
049        store();
050    }
051
052    public boolean getGUIForce100percentScaling() {
053        String value = getPreference("sun.java2d.uiScale");
054        if (value == null) return false;
055        try {
056            return Integer.parseInt(value) == 1;
057        } catch (NumberFormatException e) {
058            return false;
059        }
060    }
061
062    public void setGUIForce100percentScaling(boolean value) {
063        setPreference("sun.java2d.uiScale", value ? "1" : "0");
064    }
065
066    /**
067     * Load the preferences at startup and set them.
068     */
069    public void loadAndSetPreferences() {
070        load();
071        for (String pref : preferences.stringPropertyNames()) {
072            System.setProperty(pref, preferences.getProperty(pref));
073            startupPrefs.add(pref + ": " + preferences.getProperty(pref));
074        }
075    }
076
077    /**
078     * Return the preferences set at startup.
079     * @return the preferences
080     */
081    public List<String> getStartupPreferences() {
082        return startupPrefs;
083    }
084
085    private boolean store() {
086        try (OutputStream output = new FileOutputStream(FILENAME)) {
087            preferences.store(output, null);
088            return true;
089        } catch (FileNotFoundException e){
090            System.err.println("Could not store to " + FILENAME
091                    + ", Normal if JMRI has not been started before.");
092        } catch (IOException ex) {
093            ex.printStackTrace(System.err);
094        }
095        return false;
096    }
097
098    private void load() {
099        try (InputStream input = new FileInputStream(FILENAME)) {
100            preferences.load(input);
101        } catch (IOException ex) {
102            setupNewPreferences();
103        }
104    }
105
106    private void setupNewPreferences() {
107        boolean restartIsNeeded = false;
108
109        if (SystemType.isWindows()) {
110            int uiScale = 1;
111
112            if (!GraphicsEnvironment.isHeadless()) {
113                try {
114                    // We must restart JMRI since we read the scale. Java
115                    // will not listen to sun.java2d.uiScale unless we set
116                    // it _before_ awt and Swing is started.
117                    restartIsNeeded = true;
118
119                    GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
120                    AffineTransform transform = gc.getDefaultTransform();
121
122                    double scaleX = transform.getScaleX();
123                    double scaleY = transform.getScaleY();
124                    System.err.format("ScaleX: %1.2f%n", scaleX);
125                    System.err.format("ScaleY: %1.2f%n", scaleY);
126
127                    // Don't set uiScale to 1 if Windows has a scaling above 125%
128                    if ((scaleX >= 1.3) || (scaleY >= 1.3)) uiScale = 0;
129                } catch (NullPointerException e) {
130                    e.printStackTrace(System.err);
131                }
132            }
133
134            preferences.setProperty("sun.java2d.uiScale", Integer.toString(uiScale));
135        }
136
137        if (store() && restartIsNeeded) {
138            InstanceManager.getDefault(ShutDownManager.class).restart();
139        }
140    }
141
142//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(EarlyInitializationPreferences.class);
143}