/*
* Copyright (c) 1998-2017 by Richard A. Wilkes. All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, version 2.0. If a copy of the MPL was not distributed with
* this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This Source Code Form is "Incompatible With Secondary Licenses", as
* defined by the Mozilla Public License, version 2.0.
*/
package com.trollworks.gcs.preferences;
import com.trollworks.gcs.app.GCS;
import com.trollworks.gcs.app.GCSImages;
import com.trollworks.toolkit.annotation.Localize;
import com.trollworks.toolkit.io.Log;
import com.trollworks.toolkit.io.xml.XMLNodeType;
import com.trollworks.toolkit.io.xml.XMLReader;
import com.trollworks.toolkit.io.xml.XMLWriter;
import com.trollworks.toolkit.ui.UIUtilities;
import com.trollworks.toolkit.ui.layout.FlexColumn;
import com.trollworks.toolkit.ui.layout.FlexGrid;
import com.trollworks.toolkit.ui.layout.FlexRow;
import com.trollworks.toolkit.ui.layout.FlexSpacer;
import com.trollworks.toolkit.ui.preferences.PreferencePanel;
import com.trollworks.toolkit.ui.preferences.PreferencesWindow;
import com.trollworks.toolkit.ui.print.PageOrientation;
import com.trollworks.toolkit.ui.print.PrintManager;
import com.trollworks.toolkit.ui.widget.StdFileDialog;
import com.trollworks.toolkit.ui.widget.WindowUtils;
import com.trollworks.toolkit.utility.Localization;
import com.trollworks.toolkit.utility.PathUtils;
import com.trollworks.toolkit.utility.Preferences;
import com.trollworks.toolkit.utility.text.Text;
import com.trollworks.toolkit.utility.units.LengthUnits;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
/** The sheet preferences panel. */
public class OutputPreferences extends PreferencePanel implements ActionListener, DocumentListener, ItemListener {
@Localize("Output")
private static String TITLE;
@Localize("when saving sheets to PNG")
@Localize(locale = "de", value = "beim Export als PNG-Datei")
@Localize(locale = "ru", value = "при сохранении листов в формате PNG")
@Localize(locale = "es", value = "cuando se salva la hoja de personaje en formato PNG")
private static String PNG_RESOLUTION_POST;
@Localize("The resolution, in dots-per-inch, to use when saving sheets as PNG files")
@Localize(locale = "de", value = "Die Auflösung in DPI, mit der die Charakterblätter als PNG-Datei gespeichert werden.")
@Localize(locale = "ru", value = "Разрешение в точках на дюйм, которое используется при сохранении листов в формате PNG-файла")
@Localize(locale = "es", value = "Resolución, en puntos por pulgada (ppp), cuando se salva la hoja de personaje en formato PNG")
private static String PNG_RESOLUTION_TOOLTIP;
@Localize("{0} dpi")
@Localize(locale = "de", value = "{0} DPI")
@Localize(locale = "es", value = "{0} ppp")
private static String DPI_FORMAT;
@Localize("Text Export Template")
private static String TEXT_TEMPLATE_OVERRIDE;
@Localize("Choose\u2026")
@Localize(locale = "de", value = "wählen\u2026")
@Localize(locale = "ru", value = "Выбрать\u2026")
@Localize(locale = "es", value = "Elegir\u2026")
private static String TEXT_TEMPLATE_PICKER;
@Localize("Specify a file to use as the template when exporting to a text format, such as HTML")
private static String TEXT_TEMPLATE_OVERRIDE_TOOLTIP;
@Localize("Select A Text Template")
private static String SELECT_TEXT_TEMPLATE;
@Localize("Use platform native print dialogs (settings cannot be saved)")
@Localize(locale = "de", value = "Verwende Druckdialoge des Betriebssystems (Einstellungen können nicht gespeichert werden)")
@Localize(locale = "ru", value = "Использовать диалоги печати родные для ОС (в этом случае не сохраняются настройки диалогов)")
@Localize(locale = "es", value = "Usar los diálogos de impresión del sistema operativo (No pueden guardarse las preferencias)")
private static String NATIVE_PRINTER;
@Localize("<html><body>Whether or not the native print dialogs should be used.<br>Choosing this option will prevent the program from saving<br>and restoring print settings with the document.</body></html>")
@Localize(locale = "de", value = "<html><body>Ob die Druckdialoge des Betriebssystems verwendet werden sollen.<br>Das Auswählen dieser Option wird das Programm daran hindern,<br>die Druckeinstellungen im Dokument zu speichern und werderherzustellen.</body></html>")
@Localize(locale = "ru", value = "<html><body>Использовать родные диалоги печати ОС.<br>При выборе этого параметра программа не будет сохранять<br>настройки печати документа.</body></html>")
@Localize(locale = "es", value = "<html><body>Indica si se usan o no los diálogos de impresión del sistema operativo.<br>Si se selecciona esta opción, el programa no podrá salvar<br>y restaurar configuración del documento.</body></html>")
private static String NATIVE_PRINTER_TOOLTIP;
@Localize("Use")
@Localize(locale = "de", value = "Verwende")
@Localize(locale = "ru", value = "Использовать")
@Localize(locale = "es", value = "usar")
private static String USE;
@Localize("and")
@Localize(locale = "de", value = "und")
@Localize(locale = "ru", value = "и")
@Localize(locale = "es", value = "y")
private static String AND;
@Localize("All Readable Image Files")
private static String ALL_READABLE_IMAGE_FILES;
@Localize("JPEG Files")
private static String JPEG_FILES;
@Localize("GIF Files")
private static String GIF_FILES;
@Localize("GURPS Calculator Key")
private static String GURPS_CALCULATOR_KEY;
@Localize("Find mine")
private static String WHERE_OBTAIN;
@Localize("Unable to open {0}")
private static String UNABLE_TO_OPEN_URL;
static {
Localization.initialize();
}
private static final String MODULE = "Output"; //$NON-NLS-1$
private static final int DEFAULT_PNG_RESOLUTION = 200;
private static final String PNG_RESOLUTION_KEY = "PNGResolution"; //$NON-NLS-1$
private static final int[] DPI = { 72, 96, 144, 150, 200, 300 };
private static final String USE_TEMPLATE_OVERRIDE_KEY = "UseTextTemplateOverride"; //$NON-NLS-1$
private static final String TEMPLATE_OVERRIDE_KEY = "TextTemplateOverride"; //$NON-NLS-1$
private static final String GURPS_CALCULATOR_KEY_KEY = "GurpsCalculatorKey"; //$NON-NLS-1$
public static final String BASE_GURPS_CALCULATOR_URL = "http://www.gurpscalculator.com"; //$NON-NLS-1$
public static final String GURPS_CALCULATOR_URL = BASE_GURPS_CALCULATOR_URL + "/Character/ImportGCS"; //$NON-NLS-1$
private static final String DEFAULT_PAGE_SETTINGS_KEY = "DefaultPageSettings"; //$NON-NLS-1$
private JComboBox<String> mPNGResolutionCombo;
private JCheckBox mUseTextTemplateOverride;
private JTextField mTextTemplatePath;
private JButton mTextTemplatePicker;
private JButton mGurpsCalculatorLink;
private JTextField mGurpsCalculatorKey;
private JCheckBox mUseNativePrinter;
/** Initializes the services controlled by these preferences. */
public static void initialize() {
// Converting preferences that used to live in SheetPreferences
Preferences prefs = Preferences.getInstance();
for (String key : prefs.getModuleKeys(SheetPreferences.MODULE)) {
if (PNG_RESOLUTION_KEY.equals(key)) {
prefs.setValue(MODULE, PNG_RESOLUTION_KEY, prefs.getIntValue(SheetPreferences.MODULE, PNG_RESOLUTION_KEY, DEFAULT_PNG_RESOLUTION));
prefs.removePreference(SheetPreferences.MODULE, PNG_RESOLUTION_KEY);
} else if (USE_TEMPLATE_OVERRIDE_KEY.equals(key)) {
prefs.setValue(MODULE, USE_TEMPLATE_OVERRIDE_KEY, prefs.getBooleanValue(SheetPreferences.MODULE, USE_TEMPLATE_OVERRIDE_KEY));
prefs.removePreference(SheetPreferences.MODULE, USE_TEMPLATE_OVERRIDE_KEY);
} else if (TEMPLATE_OVERRIDE_KEY.equals(key)) {
prefs.setValue(MODULE, TEMPLATE_OVERRIDE_KEY, prefs.getStringValue(SheetPreferences.MODULE, TEMPLATE_OVERRIDE_KEY));
prefs.removePreference(SheetPreferences.MODULE, TEMPLATE_OVERRIDE_KEY);
} else if (GURPS_CALCULATOR_KEY_KEY.equals(key)) {
prefs.setValue(MODULE, GURPS_CALCULATOR_KEY_KEY, prefs.getStringValue(SheetPreferences.MODULE, GURPS_CALCULATOR_KEY_KEY));
prefs.removePreference(SheetPreferences.MODULE, GURPS_CALCULATOR_KEY_KEY);
} else if (DEFAULT_PAGE_SETTINGS_KEY.equals(key)) {
prefs.setValue(MODULE, DEFAULT_PAGE_SETTINGS_KEY, prefs.getStringValue(SheetPreferences.MODULE, DEFAULT_PAGE_SETTINGS_KEY));
prefs.removePreference(SheetPreferences.MODULE, DEFAULT_PAGE_SETTINGS_KEY);
}
}
}
/** @return The resolution to use when saving the sheet as a PNG. */
public static int getPNGResolution() {
return Preferences.getInstance().getIntValue(MODULE, PNG_RESOLUTION_KEY, DEFAULT_PNG_RESOLUTION);
}
/** @return Whether the default text template has been overridden. */
public static boolean isTextTemplateOverridden() {
return Preferences.getInstance().getBooleanValue(MODULE, USE_TEMPLATE_OVERRIDE_KEY);
}
/** @return The text template to use when exporting to a text format. */
public static String getTextTemplate() {
return isTextTemplateOverridden() ? getTextTemplateOverride() : getDefaultTextTemplate();
}
private static String getTextTemplateOverride() {
return Preferences.getInstance().getStringValue(MODULE, TEMPLATE_OVERRIDE_KEY);
}
/** @return The default text template to use when exporting to a text format. */
public static String getDefaultTextTemplate() {
return GCS.getLibraryRootPath().resolve("Output Templates").resolve("html_template.html").toString(); //$NON-NLS-1$ //$NON-NLS-2$
}
public static String getGurpsCalculatorKey() {
return Preferences.getInstance().getStringValue(MODULE, GURPS_CALCULATOR_KEY_KEY);
}
/**
* @return The default page settings to use. May return <code>null</code> if no printer has been
* defined.
*/
public static PrintManager getDefaultPageSettings() {
String settings = Preferences.getInstance().getStringValue(MODULE, DEFAULT_PAGE_SETTINGS_KEY);
if (settings != null && !settings.isEmpty()) {
try (XMLReader in = new XMLReader(new StringReader(settings))) {
XMLNodeType type = in.next();
boolean found = false;
while (type != XMLNodeType.END_DOCUMENT) {
if (type == XMLNodeType.START_TAG) {
String name = in.getName();
if (PrintManager.TAG_ROOT.equals(name)) {
if (!found) {
found = true;
return new PrintManager(in);
}
throw new IOException();
}
in.skipTag(name);
type = in.getType();
} else {
type = in.next();
}
}
} catch (Exception exception) {
Log.error(exception);
}
}
try {
return new PrintManager(PageOrientation.PORTRAIT, 0.5, LengthUnits.IN);
} catch (Exception exception) {
return null;
}
}
/** @param mgr The {@Link PrintManager} to record the settings for. */
public static void setDefaultPageSettings(PrintManager mgr) {
String value = null;
if (mgr != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (XMLWriter out = new XMLWriter(baos)) {
out.writeHeader();
mgr.save(out, LengthUnits.IN);
} catch (Exception exception) {
Log.error(exception);
}
if (baos.size() > 0) {
value = new String(baos.toByteArray(), StandardCharsets.UTF_8);
}
}
Preferences.getInstance().setValue(MODULE, DEFAULT_PAGE_SETTINGS_KEY, value);
}
/**
* Creates a new {@link OutputPreferences}.
*
* @param owner The owning {@link PreferencesWindow}.
*/
public OutputPreferences(PreferencesWindow owner) {
super(TITLE, owner);
FlexColumn column = new FlexColumn();
FlexGrid grid = new FlexGrid();
column.add(grid);
FlexRow row = new FlexRow();
row.add(createLabel(GURPS_CALCULATOR_KEY, GURPS_CALCULATOR_KEY, GCSImages.getGCalcLogo()));
mGurpsCalculatorKey = createTextField(GURPS_CALCULATOR_KEY, getGurpsCalculatorKey());
row.add(mGurpsCalculatorKey);
mGurpsCalculatorLink = createHyperlinkButton(WHERE_OBTAIN, GURPS_CALCULATOR_URL);
if (Desktop.isDesktopSupported()) {
row.add(mGurpsCalculatorLink);
}
column.add(row);
mUseNativePrinter = createCheckBox(NATIVE_PRINTER, NATIVE_PRINTER_TOOLTIP, PrintManager.useNativeDialogs());
column.add(mUseNativePrinter);
row = new FlexRow();
mUseTextTemplateOverride = createCheckBox(TEXT_TEMPLATE_OVERRIDE, TEXT_TEMPLATE_OVERRIDE_TOOLTIP, isTextTemplateOverridden());
row.add(mUseTextTemplateOverride);
mTextTemplatePath = createTextTemplatePathField();
row.add(mTextTemplatePath);
mTextTemplatePicker = createButton(TEXT_TEMPLATE_PICKER, TEXT_TEMPLATE_OVERRIDE_TOOLTIP);
mTextTemplatePicker.setEnabled(isTextTemplateOverridden());
row.add(mTextTemplatePicker);
column.add(row);
row = new FlexRow();
row.add(createLabel(USE, PNG_RESOLUTION_TOOLTIP));
mPNGResolutionCombo = createPNGResolutionPopup();
row.add(mPNGResolutionCombo);
row.add(createLabel(PNG_RESOLUTION_POST, PNG_RESOLUTION_TOOLTIP, SwingConstants.LEFT));
column.add(row);
column.add(new FlexSpacer(0, 0, false, true));
column.apply(this);
}
private JButton createButton(String title, String tooltip) {
JButton button = new JButton(title);
button.setOpaque(false);
button.setToolTipText(Text.wrapPlainTextForToolTip(tooltip));
button.addActionListener(this);
add(button);
return button;
}
private JTextField createTextTemplatePathField() {
JTextField field = new JTextField(getTextTemplate());
field.setToolTipText(Text.wrapPlainTextForToolTip(TEXT_TEMPLATE_OVERRIDE_TOOLTIP));
field.setEnabled(isTextTemplateOverridden());
field.getDocument().addDocumentListener(this);
Dimension size = field.getPreferredSize();
Dimension maxSize = field.getMaximumSize();
maxSize.height = size.height;
field.setMaximumSize(maxSize);
add(field);
return field;
}
private JButton createHyperlinkButton(String linkText, String tooltip) {
JButton button = new JButton(String.format("<html><body><font color=\"#000099\"><u>%s</u></font></body></html>", linkText)); //$NON-NLS-1$
button.setFocusPainted(false);
button.setMargin(new Insets(0, 0, 0, 0));
button.setContentAreaFilled(false);
button.setBorderPainted(false);
button.setOpaque(false);
button.setToolTipText(Text.wrapPlainTextForToolTip(tooltip));
button.setBackground(Color.white);
button.addActionListener(this);
UIUtilities.setOnlySize(button, button.getPreferredSize());
add(button);
return button;
}
private JComboBox<String> createPNGResolutionPopup() {
int selection = 0;
int resolution = getPNGResolution();
JComboBox<String> combo = new JComboBox<>();
setupCombo(combo, PNG_RESOLUTION_TOOLTIP);
for (int i = 0; i < DPI.length; i++) {
combo.addItem(MessageFormat.format(DPI_FORMAT, new Integer(DPI[i])));
if (DPI[i] == resolution) {
selection = i;
}
}
combo.setSelectedIndex(selection);
combo.addActionListener(this);
combo.setMaximumRowCount(combo.getItemCount());
UIUtilities.setOnlySize(combo, combo.getPreferredSize());
return combo;
}
private JTextField createTextField(String tooltip, String value) {
JTextField field = new JTextField(value);
field.setToolTipText(Text.wrapPlainTextForToolTip(tooltip));
field.getDocument().addDocumentListener(this);
Dimension size = field.getPreferredSize();
Dimension maxSize = field.getMaximumSize();
maxSize.height = size.height;
field.setMaximumSize(maxSize);
add(field);
return field;
}
@Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == mPNGResolutionCombo) {
Preferences.getInstance().setValue(MODULE, PNG_RESOLUTION_KEY, DPI[mPNGResolutionCombo.getSelectedIndex()]);
} else if (source == mTextTemplatePicker) {
File file = StdFileDialog.showOpenDialog(this, SELECT_TEXT_TEMPLATE);
if (file != null) {
mTextTemplatePath.setText(PathUtils.getFullPath(file));
}
} else if (source == mGurpsCalculatorLink && Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(new URI(GURPS_CALCULATOR_URL));
} catch (Exception exception) {
WindowUtils.showError(this, MessageFormat.format(UNABLE_TO_OPEN_URL, GURPS_CALCULATOR_URL));
}
}
adjustResetButton();
}
@Override
public void reset() {
mGurpsCalculatorKey.setText(""); //$NON-NLS-1$
for (int i = 0; i < DPI.length; i++) {
if (DPI[i] == DEFAULT_PNG_RESOLUTION) {
mPNGResolutionCombo.setSelectedIndex(i);
break;
}
}
mUseTextTemplateOverride.setSelected(false);
mUseNativePrinter.setSelected(false);
}
@Override
public boolean isSetToDefaults() {
return getPNGResolution() == DEFAULT_PNG_RESOLUTION && isTextTemplateOverridden() == false && !PrintManager.useNativeDialogs() && mGurpsCalculatorKey.getText().equals(""); //$NON-NLS-1$
}
@Override
public void changedUpdate(DocumentEvent event) {
Document document = event.getDocument();
if (mTextTemplatePath.getDocument() == document) {
Preferences.getInstance().setValue(MODULE, TEMPLATE_OVERRIDE_KEY, mTextTemplatePath.getText());
} else if (mGurpsCalculatorKey.getDocument() == document) {
Preferences.getInstance().setValue(MODULE, GURPS_CALCULATOR_KEY_KEY, mGurpsCalculatorKey.getText());
}
adjustResetButton();
}
@Override
public void insertUpdate(DocumentEvent event) {
changedUpdate(event);
}
@Override
public void removeUpdate(DocumentEvent event) {
changedUpdate(event);
}
@Override
public void itemStateChanged(ItemEvent event) {
Object source = event.getSource();
if (source == mUseTextTemplateOverride) {
boolean checked = mUseTextTemplateOverride.isSelected();
Preferences.getInstance().setValue(MODULE, USE_TEMPLATE_OVERRIDE_KEY, checked);
mTextTemplatePath.setEnabled(checked);
mTextTemplatePicker.setEnabled(checked);
mTextTemplatePath.setText(getTextTemplate());
} else if (source == mUseNativePrinter) {
PrintManager.useNativeDialogs(mUseNativePrinter.isSelected());
}
adjustResetButton();
}
}