Java tutorial
/* Copyright 2014-2018 Will Winder This file is part of Universal Gcode Sender (UGS). UGS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. UGS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with UGS. If not, see <http://www.gnu.org/licenses/>. */ package com.willwinder.universalgcodesender.utils; import com.willwinder.universalgcodesender.connection.ConnectionDriver; import com.willwinder.universalgcodesender.model.Position; import com.willwinder.universalgcodesender.model.UnitUtils; import com.willwinder.universalgcodesender.model.UnitUtils.Units; import com.willwinder.universalgcodesender.pendantui.PendantConfigBean; import com.willwinder.universalgcodesender.types.Macro; import com.willwinder.universalgcodesender.types.WindowSettings; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import org.apache.commons.lang3.StringUtils; public class Settings { // Transient, don't serialize or deserialize. transient private SettingChangeListener listener = null; transient public static int HISTORY_SIZE = 20; private String firmwareVersion = "GRBL"; private String fileName = System.getProperty("user.home"); private Deque<String> fileHistory = new ArrayDeque<>(); private Deque<String> dirHistory = new ArrayDeque<>(); private String port = ""; private String portRate = "115200"; private boolean manualModeEnabled = false; private double manualModeStepSize = 1; private boolean useZStepSize = true; private double zJogStepSize = 1; private double jogFeedRate = 10; private boolean scrollWindowEnabled = true; private boolean verboseOutputEnabled = false; private boolean commandTableEnabled = false; // Sender Settings private WindowSettings mainWindowSettings = new WindowSettings(0, 0, 640, 520); private WindowSettings visualizerWindowSettings = new WindowSettings(0, 0, 640, 480); private boolean singleStepMode = false; private boolean statusUpdatesEnabled = true; private int statusUpdateRate = 200; private boolean displayStateColor = true; private Units preferredUnits = Units.MM; private boolean showNightlyWarning = true; private boolean showSerialPortWarning = true; private boolean autoConnect = false; private boolean autoReconnect = false; private AutoLevelSettings autoLevelSettings = new AutoLevelSettings(); private FileStats fileStats = new FileStats(); //vvv deprecated fields, still here to not break the old save files // Transient, don't serialize or deserialize. transient private String customGcode1 = null; transient private String customGcode2 = null; transient private String customGcode3 = null; transient private String customGcode4 = null; transient private String customGcode5 = null; //^^^ deprecated fields, still here to not break the old save files private Map<Integer, Macro> macros = new HashMap<>(); private String language = "en_US"; private PendantConfigBean pendantConfig = new PendantConfigBean(); private String connectionDriver; /** * The GSON deserialization doesn't do anything beyond initialize what's in the json document. Call finalizeInitialization() before using the Settings. */ public Settings() { System.out.println("Initializing..."); // Initialize macros with a default macro macros.put(1, new Macro(null, null, "G91 X0 Y0;")); } /** * Null legacy fields and move data to current data structures */ public void finalizeInitialization() { if (customGcode1 != null) { updateMacro(1, null, null, customGcode1); customGcode1 = null; } if (customGcode2 != null) { updateMacro(2, null, null, customGcode2); customGcode2 = null; } if (customGcode3 != null) { updateMacro(3, null, null, customGcode3); customGcode3 = null; } if (customGcode4 != null) { updateMacro(4, null, null, customGcode4); customGcode4 = null; } if (customGcode5 != null) { updateMacro(5, null, null, customGcode5); customGcode5 = null; } } /** * This method should only be called once during setup, a runtime exception * will be thrown if that contract is violated. */ public void setSettingChangeListener(SettingChangeListener listener) { this.listener = listener; } private void changed() { if (listener != null) { listener.settingChanged(); } } public String getFirmwareVersion() { return firmwareVersion; } public void setFirmwareVersion(String firmwareVersion) { if (StringUtils.equals(firmwareVersion, this.firmwareVersion)) return; this.firmwareVersion = firmwareVersion; changed(); } public String getLastOpenedFilename() { return fileName; } public void setLastOpenedFilename(String absolutePath) { Path p = Paths.get(absolutePath).toAbsolutePath(); this.fileName = p.toString(); updateRecentFiles(p.toString()); updateRecentDirectory(p.getParent().toString()); changed(); } public Collection<String> getRecentFiles() { return Collections.unmodifiableCollection(fileHistory); } public void updateRecentFiles(String absolutePath) { updateRecent(this.fileHistory, HISTORY_SIZE, absolutePath); } public Collection<String> getRecentDirectories() { return Collections.unmodifiableCollection(dirHistory); } public void updateRecentDirectory(String absolutePath) { updateRecent(this.dirHistory, HISTORY_SIZE, absolutePath); } private static void updateRecent(Deque<String> stack, int maxSize, String element) { stack.remove(element); stack.push(element); while (stack.size() > maxSize) stack.removeLast(); } public String getPort() { return port; } public void setPort(String port) { if (StringUtils.equals(port, this.port)) return; this.port = port; changed(); } public String getPortRate() { return portRate; } public void setPortRate(String portRate) { if (StringUtils.equals(portRate, this.portRate)) return; this.portRate = portRate; changed(); } public boolean isManualModeEnabled() { return manualModeEnabled; } public void setManualModeEnabled(boolean manualModeEnabled) { this.manualModeEnabled = manualModeEnabled; changed(); } public double getManualModeStepSize() { return manualModeStepSize; } public void setManualModeStepSize(double manualModeStepSize) { this.manualModeStepSize = manualModeStepSize; changed(); } public boolean useZStepSize() { return this.useZStepSize; } public void setUseZStepSize(boolean useZStepSize) { this.useZStepSize = useZStepSize; changed(); } public double getzJogStepSize() { return zJogStepSize; } public void setzJogStepSize(double zJogStepSize) { this.zJogStepSize = zJogStepSize; changed(); } public double getJogFeedRate() { return jogFeedRate; } public void setJogFeedRate(double jogFeedRate) { this.jogFeedRate = jogFeedRate; changed(); } public boolean isScrollWindowEnabled() { return scrollWindowEnabled; } public void setScrollWindowEnabled(boolean scrollWindowEnabled) { this.scrollWindowEnabled = scrollWindowEnabled; changed(); } public boolean isVerboseOutputEnabled() { return verboseOutputEnabled; } public void setVerboseOutputEnabled(boolean verboseOutputEnabled) { this.verboseOutputEnabled = verboseOutputEnabled; changed(); } public boolean isCommandTableEnabled() { return commandTableEnabled; } public void setCommandTableEnabled(boolean enabled) { commandTableEnabled = enabled; changed(); } public WindowSettings getMainWindowSettings() { return this.mainWindowSettings; } public void setMainWindowSettings(WindowSettings ws) { this.mainWindowSettings = ws; changed(); } public WindowSettings getVisualizerWindowSettings() { return this.visualizerWindowSettings; } public void setVisualizerWindowSettings(WindowSettings vw) { this.visualizerWindowSettings = vw; changed(); } public boolean isSingleStepMode() { return singleStepMode; } public void setSingleStepMode(boolean singleStepMode) { this.singleStepMode = singleStepMode; changed(); } public boolean isStatusUpdatesEnabled() { return statusUpdatesEnabled; } public void setStatusUpdatesEnabled(boolean statusUpdatesEnabled) { this.statusUpdatesEnabled = statusUpdatesEnabled; changed(); } public int getStatusUpdateRate() { return statusUpdateRate; } public void setStatusUpdateRate(int statusUpdateRate) { this.statusUpdateRate = statusUpdateRate; changed(); } public boolean isDisplayStateColor() { return displayStateColor; } public void setDisplayStateColor(boolean displayStateColor) { this.displayStateColor = displayStateColor; changed(); } public PendantConfigBean getPendantConfig() { return pendantConfig; } public void setPendantConfig(PendantConfigBean pendantConfig) { this.pendantConfig = pendantConfig; changed(); } public Units getPreferredUnits() { return (preferredUnits == null) ? Units.MM : preferredUnits; } public void setPreferredUnits(Units units) { if (units != null) { double scaleUnits = UnitUtils.scaleUnits(preferredUnits, units); preferredUnits = units; changed(); // Change setManualModeStepSize(manualModeStepSize * scaleUnits); setzJogStepSize(zJogStepSize * scaleUnits); setJogFeedRate(Math.round(jogFeedRate * scaleUnits)); } } public boolean isShowNightlyWarning() { return showNightlyWarning; } public void setShowNightlyWarning(boolean showNightlyWarning) { this.showNightlyWarning = showNightlyWarning; changed(); } public boolean isShowSerialPortWarning() { return showSerialPortWarning; } public void setShowSerialPortWarning(boolean showSerialPortWarning) { this.showSerialPortWarning = showSerialPortWarning; changed(); } public Macro getMacro(Integer index) { Macro macro = macros.get(index); if (macro == null) { macro = new Macro(index.toString(), null, null); } return macro; } public Integer getNumMacros() { return macros.size(); } public Integer getLastMacroIndex() { // Obviously it would be more efficient to just store the max index // value, but this is safer in that it's one less thing to keep in sync. int i = -1; for (Integer index : macros.keySet()) { i = Math.max(i, index); } return i; } public void clearMacros() { macros.clear(); changed(); } public void clearMacro(Integer index) { macros.remove(index); changed(); } public void updateMacro(Integer index, Macro macro) { updateMacro(index, macro.getName(), macro.getDescription(), macro.getGcode()); } public void updateMacro(Integer index, String name, String description, String gcode) { if (gcode == null || gcode.trim().isEmpty()) { macros.remove(index); } else { if (name == null) { name = index.toString(); } macros.put(index, new Macro(name, description, gcode)); } changed(); } public String getLanguage() { // "zh_CHS" is a legacy format that has been renamed. if ("zh_CHS".equals(this.language)) { this.language = "zh_CN"; } return this.language; } public void setLanguage(String language) { this.language = language; changed(); } public boolean isAutoConnectEnabled() { return autoConnect; } public boolean isAutoReconnect() { return autoReconnect; } public void setAutoLevelSettings(AutoLevelSettings settings) { if (!settings.equals(this.autoLevelSettings)) { this.autoLevelSettings = settings; changed(); } } public AutoLevelSettings getAutoLevelSettings() { return this.autoLevelSettings; } public void setFileStats(FileStats settings) { this.fileStats = settings; changed(); } public FileStats getFileStats() { return this.fileStats; } public ConnectionDriver getConnectionDriver() { ConnectionDriver connectionDriver = ConnectionDriver.JSSC; if (StringUtils.isNotEmpty(this.connectionDriver)) { try { connectionDriver = ConnectionDriver.valueOf(this.connectionDriver); } catch (IllegalArgumentException | NullPointerException ignored) { // Never mind, we'll use the default } } return connectionDriver; } public void setConnectionDriver(ConnectionDriver connectionDriver) { this.connectionDriver = connectionDriver.name(); } public static class AutoLevelSettings { // Setting window public double autoLevelProbeZeroHeight = 0; public Position autoLevelProbeOffset = new Position(0, 0, 0, Units.UNKNOWN); public double autoLevelArcSliceLength = 0.01; // Main window public double stepResolution = 10; public double probeSpeed = 10; public double zSurface = 0; public boolean equals(AutoLevelSettings obj) { return this.autoLevelProbeZeroHeight == obj.autoLevelProbeZeroHeight && Objects.equals(this.autoLevelProbeOffset, obj.autoLevelProbeOffset) && this.autoLevelArcSliceLength == obj.autoLevelArcSliceLength && this.stepResolution == obj.stepResolution && this.probeSpeed == obj.probeSpeed && this.zSurface == obj.zSurface; } } public static class FileStats { public Position minCoordinate; public Position maxCoordinate; public long numCommands; public FileStats() { this.minCoordinate = new Position(0, 0, 0, Units.MM); this.maxCoordinate = new Position(0, 0, 0, Units.MM); this.numCommands = 0; } public FileStats(Position min, Position max, long num) { this.minCoordinate = min; this.maxCoordinate = max; this.numCommands = num; } } }