/* * This file is part of LaTeXDraw. * Copyright (c) 2005-2017 Arnaud BLOUIN * LaTeXDraw 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 2 of the License, or (at your option) any later version. * LaTeXDraw is distributed 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. */ package net.sf.latexdraw.instruments; import com.google.inject.Inject; import java.io.File; import java.io.FileOutputStream; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.stream.Collectors; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.geometry.Rectangle2D; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; import javafx.scene.control.Spinner; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; import javafx.scene.control.Tooltip; import javafx.stage.DirectoryChooser; import javafx.stage.Screen; import javafx.stage.Stage; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import net.sf.latexdraw.actions.GridProperties; import net.sf.latexdraw.actions.ModifyMagneticGrid; import net.sf.latexdraw.actions.SetUnit; import net.sf.latexdraw.badaboom.BadaboomCollector; import net.sf.latexdraw.ui.ScaleRuler; import net.sf.latexdraw.util.LNamespace; import net.sf.latexdraw.util.LPath; import net.sf.latexdraw.util.LangTool; import net.sf.latexdraw.util.Preference; import net.sf.latexdraw.util.Unit; import net.sf.latexdraw.util.VersionChecker; import net.sf.latexdraw.view.GridStyle; import net.sf.latexdraw.view.MagneticGrid; import org.malai.javafx.instrument.JfxInstrument; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * This instrument modifies the preferences. * @author Arnaud BLOUIN */ public class PreferencesSetter extends JfxInstrument implements Initializable { /** The recent files. */ private final List<String> recentFileNames; /** Sets if the grid is magnetic. */ @FXML private CheckBox magneticCB; /** Allows the set if the program must check new version on start up. */ @FXML private CheckBox checkNewVersion; /** This textField allows to set the default directories for open/save actions. */ @FXML private TextField pathOpenField; @FXML private CheckBox openGL; /** This textField allows to set the default directories for exporting actions. */ @FXML private TextField pathExportField; /** The text field used to defines the latex packages to use. */ @FXML private TextArea latexIncludes; /** Allows to set the unit of length by default. */ @FXML private ComboBox<String> unitChoice; /** The list that contains the supported languages. */ @FXML private ComboBox<String> langList; /** The field used to modifies the gap of the customised grid. */ @FXML private Spinner<Integer> persoGridGapField; /** The widget used to defines the number of recent file to keep in memory. */ @FXML private Spinner<Integer> nbRecentFilesField; /** Contains the different possible kind of grids. */ @FXML private ComboBox<GridStyle> styleList; @FXML private Button buttonOpen; @FXML private Button buttonExport; @Inject private Exporter exporter; @Inject private FileLoaderSaver saver; @Inject private MagneticGrid grid; /** The file chooser of paths selection. */ private DirectoryChooser fileChooser; /** * Creates the instrument. */ PreferencesSetter() { super(); recentFileNames = new ArrayList<>(); } @Override public void initialize(final URL location, final ResourceBundle resources) { latexIncludes.setTooltip(new Tooltip("<html>" + //$NON-NLS-1$ LangTool.INSTANCE.getBundle().getString("PreferencesSetter.1") + //$NON-NLS-1$ "<br>\\usepackage[frenchb]{babel}<br>\\usepackage[utf8]{inputenc}</html>"//$NON-NLS-1$ )); langList.getItems().addAll(LangTool.INSTANCE.getSupportedLocales().stream().map(Locale::getDisplayLanguage).collect(Collectors.toList())); unitChoice.getItems().addAll(Arrays.stream(Unit.values()).map(Unit::getLabel).collect(Collectors.toList())); styleList.getItems().addAll(GridStyle.values()); ShapePropertyCustomiser.scrollOnSpinner(nbRecentFilesField); ShapePropertyCustomiser.scrollOnSpinner(persoGridGapField); buttonOpen.setOnAction(evt -> { File file = getFileChooser().showDialog(null); if(file != null) { pathOpenField.setText(file.getPath()); } }); buttonExport.setOnAction(evt -> { File file = getFileChooser().showDialog(null); if(file != null) { pathExportField.setText(file.getPath()); exporter.setPathExport(file.getPath()); } }); } /** * Adds a recent file. * @param absolutePath The absolute path of the file to add. */ public void addRecentFile(final String absolutePath) { final int i = recentFileNames.indexOf(absolutePath); final int max = (int) Double.parseDouble(nbRecentFilesField.getValue().toString()); if(i != -1) { recentFileNames.remove(i); } while(recentFileNames.size() >= max) { recentFileNames.remove(max - 1); } recentFileNames.add(0, absolutePath); } public List<String> getRecentFileNames() { return recentFileNames; } @Override protected void configureBindings() throws IllegalAccessException, InstantiationException { bindComboBox(ModifyMagneticGrid.class, action -> { action.setValue(styleList.getSelectionModel().getSelectedItem()); action.setGrid(grid); action.setProperty(GridProperties.STYLE); }, styleList); bindCheckbox(ModifyMagneticGrid.class, action -> { action.setValue(magneticCB.isSelected()); action.setGrid(grid); action.setProperty(GridProperties.MAGNETIC); }, magneticCB); bindSpinner(ModifyMagneticGrid.class, action -> { action.setValue(persoGridGapField.getValue()); action.setGrid(grid); action.setProperty(GridProperties.GRID_SPACING); }, action -> action.setValue(persoGridGapField.getValue()), true, persoGridGapField); bindComboBox(SetUnit.class, action -> action.setUnit(Unit.getUnit(unitChoice.getSelectionModel().getSelectedItem())), unitChoice); } /** * @return The file chooser used to selected folders. * @since 3.0 */ private DirectoryChooser getFileChooser() { if(fileChooser == null) { fileChooser = new DirectoryChooser(); fileChooser.setTitle(LangTool.INSTANCE.getBundle().getString("PreferencesFrame.selectFolder")); //$NON-NLS-1$ } return fileChooser; } private void processXMLDataPreference(final File xml) { final Map<String, Node> prefMap = Preference.readXMLPreferencesFromFile(xml); final Stage frame = (Stage) pathExportField.getScene().getWindow(); Node n2; Node node; node = prefMap.get(LNamespace.XML_LATEX_INCLUDES); if(node != null) latexIncludes.setText(node.getTextContent()); node = prefMap.get(LNamespace.XML_OPENGL); if(node != null) openGL.setSelected(Boolean.parseBoolean(node.getTextContent())); node = prefMap.get(LNamespace.XML_CHECK_VERSION); if(node != null) checkNewVersion.setSelected(Boolean.parseBoolean(node.getTextContent())); node = prefMap.get(LNamespace.XML_CLASSIC_GRID); if(node != null) if(Boolean.parseBoolean(node.getTextContent())) styleList.getSelectionModel().select(GridStyle.STANDARD); else styleList.getSelectionModel().select(GridStyle.CUSTOMISED); node = prefMap.get(LNamespace.XML_DISPLAY_GRID); if(node != null) if(!Boolean.parseBoolean(node.getTextContent())) styleList.getSelectionModel().select(GridStyle.NONE); node = prefMap.get(LNamespace.XML_GRID_GAP); if(node != null) persoGridGapField.getValueFactory().setValue(Integer.valueOf(node.getTextContent())); node = prefMap.get(LNamespace.XML_LANG); if(node != null) langList.getSelectionModel().select(node.getTextContent()); node = prefMap.get(LNamespace.XML_MAGNETIC_GRID); if(node != null) magneticCB.setSelected(Boolean.parseBoolean(node.getTextContent())); node = prefMap.get(LNamespace.XML_PATH_EXPORT); if(node != null) pathExportField.setText(node.getTextContent()); node = prefMap.get(LNamespace.XML_PATH_OPEN); if(node != null) pathOpenField.setText(node.getTextContent()); node = prefMap.get(LNamespace.XML_UNIT); if(node != null) unitChoice.getSelectionModel().select(node.getTextContent()); node = prefMap.get(LNamespace.XML_RECENT_FILES); if(node != null) { final NodeList nl2 = node.getChildNodes(); final NamedNodeMap nnm = node.getAttributes(); recentFileNames.clear(); if(nnm != null && nnm.getNamedItem(LNamespace.XML_NB_RECENT_FILES) != null) { final Node attr = nnm.getNamedItem(LNamespace.XML_NB_RECENT_FILES); if(attr != null) { nbRecentFilesField.getValueFactory().setValue(Integer.valueOf(attr.getTextContent())); } } for(int j = 0, size2 = nl2.getLength(); j < size2; j++) { n2 = nl2.item(j); if(n2.getNodeName().equals(LNamespace.XML_RECENT_FILE) && n2.getTextContent() != null) { recentFileNames.add(n2.getTextContent()); } } } node = prefMap.get(LNamespace.XML_MAXIMISED); if(node != null) { frame.setFullScreen(Boolean.parseBoolean(node.getTextContent())); } node = prefMap.get(LNamespace.XML_SIZE); if(node != null) { final NodeList nl2 = node.getChildNodes(); for(int j = 0, size2 = nl2.getLength(); j < size2; j++) { n2 = nl2.item(j); if(n2.getNodeName().equals(LNamespace.XML_WIDTH)) { frame.setWidth(Double.valueOf(n2.getTextContent())); }else { if(n2.getNodeName().equals(LNamespace.XML_HEIGHT)) { frame.setHeight(Double.valueOf(n2.getTextContent())); } } } } node = prefMap.get(LNamespace.XML_POSITION); if(node != null) { final NodeList nl2 = node.getChildNodes(); for(int j = 0, size2 = nl2.getLength(); j < size2; j++) { n2 = nl2.item(j); if(n2.getNodeName().equals(LNamespace.XML_POSITION_X)) { frame.setX(Math.max(0, Double.valueOf(n2.getTextContent()))); }else { if(n2.getNodeName().equals(LNamespace.XML_POSITION_Y)) { frame.setY(Math.max(0, Double.valueOf(n2.getTextContent()))); } } } } } /** * @return True if a new version must be checked. * @since 3.0 */ public boolean isVersionCheckEnable() { return checkNewVersion != null && checkNewVersion.isSelected(); } /** * Applies the values of the preferences setter to the concerned elements. * @since 3.0 */ private void applyValues() { grid.setGridStyle(styleList.getSelectionModel().getSelectedItem()); grid.setMagnetic(magneticCB.isSelected()); grid.setGridSpacing(Integer.parseInt(persoGridGapField.getValue().toString())); grid.setGridSpacing(persoGridGapField.getValue()); exporter.setDefaultPackages(latexIncludes.getText()); exporter.setPathExport(pathExportField.getText()); saver.setPathSave(pathOpenField.getText()); saver.updateRecentMenuItems(recentFileNames); ScaleRuler.setUnit(Unit.getUnit(unitChoice.getSelectionModel().getSelectedItem())); } /** * Writes the preferences of latexdraw in an XML document. * @since 3.0 */ public void writeXMLPreferences() { try { try(final FileOutputStream fos = new FileOutputStream(LPath.PATH_PREFERENCES_XML_FILE)) { final Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); final Stage frame = (Stage) pathExportField.getScene().getWindow(); final Rectangle2D rec = Screen.getPrimary().getBounds(); final Element root = document.createElement(LNamespace.XML_ROOT_PREFERENCES); Element elt; Element elt2; document.setXmlVersion("1.0");//$NON-NLS-1$ document.setXmlStandalone(true); document.appendChild(root); final Attr attr = document.createAttribute(LNamespace.XML_VERSION); attr.setTextContent(VersionChecker.VERSION); root.setAttributeNode(attr); elt = document.createElement(LNamespace.XML_OPENGL); elt.setTextContent(String.valueOf(openGL.isSelected())); root.appendChild(elt); elt = document.createElement(LNamespace.XML_PATH_EXPORT); elt.setTextContent(pathExportField.getText()); root.appendChild(elt); elt = document.createElement(LNamespace.XML_PATH_OPEN); elt.setTextContent(pathOpenField.getText()); root.appendChild(elt); elt = document.createElement(LNamespace.XML_DISPLAY_GRID); elt.setTextContent(String.valueOf(styleList.getSelectionModel().getSelectedItem() != GridStyle.NONE)); root.appendChild(elt); elt = document.createElement(LNamespace.XML_UNIT); elt.setTextContent(unitChoice.getSelectionModel().getSelectedItem()); root.appendChild(elt); elt = document.createElement(LNamespace.XML_CHECK_VERSION); elt.setTextContent(String.valueOf(checkNewVersion.isSelected())); root.appendChild(elt); elt = document.createElement(LNamespace.XML_LANG); elt.setTextContent(langList.getSelectionModel().getSelectedItem()); root.appendChild(elt); elt = document.createElement(LNamespace.XML_MAGNETIC_GRID); elt.setTextContent(String.valueOf(magneticCB.isSelected())); root.appendChild(elt); elt = document.createElement(LNamespace.XML_CLASSIC_GRID); elt.setTextContent(Boolean.valueOf(styleList.getSelectionModel().getSelectedItem() == GridStyle.STANDARD).toString()); root.appendChild(elt); elt = document.createElement(LNamespace.XML_GRID_GAP); elt.setTextContent(persoGridGapField.getValue().toString()); root.appendChild(elt); elt = document.createElement(LNamespace.XML_LATEX_INCLUDES); elt.setTextContent(latexIncludes.getText()); root.appendChild(elt); elt = document.createElement(LNamespace.XML_RECENT_FILES); elt.setAttribute(LNamespace.XML_NB_RECENT_FILES, nbRecentFilesField.getValue().toString()); root.appendChild(elt); for(final String recentFile : recentFileNames) { elt2 = document.createElement(LNamespace.XML_RECENT_FILE); elt2.setTextContent(recentFile); elt.appendChild(elt2); } elt = document.createElement(LNamespace.XML_MAXIMISED); elt.setTextContent(String.valueOf(frame.isMaximized())); root.appendChild(elt); elt = document.createElement(LNamespace.XML_SIZE); root.appendChild(elt); elt2 = document.createElement(LNamespace.XML_WIDTH); elt2.setTextContent(String.valueOf((int) frame.getWidth())); elt.appendChild(elt2); elt2 = document.createElement(LNamespace.XML_HEIGHT); elt2.setTextContent(String.valueOf((int) frame.getHeight())); elt.appendChild(elt2); elt = document.createElement(LNamespace.XML_POSITION); root.appendChild(elt); elt2 = document.createElement(LNamespace.XML_POSITION_X); elt2.setTextContent(String.valueOf((int) (frame.getX() - rec.getMinX()))); elt.appendChild(elt2); elt2 = document.createElement(LNamespace.XML_POSITION_Y); elt2.setTextContent(String.valueOf((int) (frame.getY() - rec.getMinY()))); elt.appendChild(elt2); final Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); //$NON-NLS-1$ //$NON-NLS-2$ transformer.transform(new DOMSource(document), new StreamResult(fos)); } }catch(final Exception e) { BadaboomCollector.INSTANCE.add(e); } } /** * Reads the preferences of latexdraw defined in XML. * @throws IllegalArgumentException If a problem occurs. * @since 3.0 */ public void readXMLPreferences() { final File xml = new File(LPath.PATH_PREFERENCES_XML_FILE); if(xml.canRead()) { processXMLDataPreference(xml); } applyValues(); } }