/*
* This file is part of the Illarion project.
*
* Copyright © 2015 - Illarion e.V.
*
* Illarion is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Illarion 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.
*/
package illarion.mapedit.gui;
import illarion.common.config.Config;
import illarion.common.config.ConfigChangedEvent;
import illarion.common.config.ConfigDialog;
import illarion.common.config.ConfigDialog.Entry;
import illarion.common.config.ConfigDialog.Page;
import illarion.common.config.ConfigSystem;
import illarion.common.config.entries.CheckEntry;
import illarion.common.config.entries.DirectoryEntry;
import illarion.common.config.entries.SelectEntry;
import illarion.common.util.DirectoryManager;
import illarion.common.util.DirectoryManager.Directory;
import illarion.mapedit.Lang;
import javolution.util.FastTable;
import org.bushe.swing.event.annotation.AnnotationProcessor;
import org.bushe.swing.event.annotation.EventTopicSubscriber;
import org.pushingpixels.substance.api.SubstanceLookAndFeel;
import org.pushingpixels.substance.api.skin.SkinInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.swing.*;
import java.awt.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;
/**
* @author Fredrik K
*/
public final class MapEditorConfig {
@Nonnull
private static final Logger LOGGER = LoggerFactory.getLogger(MapEditorConfig.class);
@Nonnull
private static final String DEFAULT_LOOK_AND_FEEL = "org.pushingpixels.substance.api.skin.OfficeSilver2007Skin";
@Nonnull
private static final String[] LANGUAGES = {"English", "German", ""};
@Nonnull
private static final MapEditorConfig INSTANCE = new MapEditorConfig();
private static final int ENGLISH = 0;
private static final int GERMAN = 1;
@Nonnull
public static final String MAPEDIT_FOLDER = "mapeditFolder";
@Nonnull
public static final String USE_WINDOW_DECO = "useWindowDeco";
@Nonnull
private static final String USED_LOOK_AND_FEEL = "usedLookAndFeel";
@Nonnull
public static final String USED_LANGUAGE = "usedLanguage";
@Nonnull
public static final String SHOW_MAP_POSITION = "showMapPosition";
@Nonnull
public static final String WINDOW_HEIGHT = "windowSizeH";
@Nonnull
public static final String WINDOW_WIDTH = "windowSizeW";
@Nullable
private ConfigSystem configSystem;
/**
* Private constructor to ensure that no instance but the singleton instance
* is created.
*/
private MapEditorConfig() {
AnnotationProcessor.process(this);
}
/**
* Get the singleton instance of this class.
*
* @return the singleton instance
*/
@Nonnull
public static MapEditorConfig getInstance() {
return INSTANCE;
}
/**
* Create a ConfigDialog
*
* @return the dialog
*/
@Nonnull
public ConfigDialog createDialog() {
if (configSystem == null) {
throw new IllegalStateException("Configuration system not initialized yet.");
}
ConfigDialog dialog = new ConfigDialog();
dialog.setConfig(configSystem);
dialog.setMessageSource(Lang.getInstance());
Page generalPage = new Page("gui.config.generalTab");
generalPage.addEntry(
new Entry("gui.config.MapeditFolderLabel", new DirectoryEntry(MAPEDIT_FOLDER, null)));
generalPage.addEntry(new Entry("gui.config.language",
new SelectEntry(USED_LANGUAGE, SelectEntry.STORE_VALUE,
(Object[]) LANGUAGES)
));
generalPage.addEntry(new Entry("gui.config.showMapPostion", new CheckEntry(SHOW_MAP_POSITION)));
dialog.addPage(generalPage);
Page lookAndFeelPage = new Page("gui.config.lookAndFeelTab");
lookAndFeelPage
.addEntry(new Entry("gui.config.useWindowDecoLabel", new CheckEntry(USE_WINDOW_DECO)));
Collection<String> themeObject = new FastTable<>();
Collection<String> themeLabel = new FastTable<>();
for (Map.Entry<String, SkinInfo> skin : SubstanceLookAndFeel.getAllSkins().entrySet()) {
themeObject.add(skin.getValue().getClassName());
themeLabel.add(skin.getValue().getDisplayName());
}
lookAndFeelPage.addEntry(new Entry("gui.config.usedThemeLabel",
new SelectEntry(USED_LOOK_AND_FEEL, SelectEntry.STORE_VALUE,
themeObject.toArray(), themeLabel
.toArray(new String[themeLabel.size()])
)
));
dialog.addPage(lookAndFeelPage);
return dialog;
}
/**
* Get the the language for the editor
*
* @return Locale
*/
public Locale getLanguage() {
if (configSystem == null) {
LOGGER.error("Configuration system not initialized yet.");
return getDefaultLanguage();
}
String language = configSystem.getString(USED_LANGUAGE);
if ((language != null) && language.equals(LANGUAGES[ENGLISH])) {
return Locale.ENGLISH;
}
if ((language != null) && language.equals(LANGUAGES[GERMAN])) {
return Locale.GERMAN;
}
return getDefaultLanguage();
}
private static Locale getDefaultLanguage() {
Locale locale = Locale.getDefault();
if (locale.getLanguage().equalsIgnoreCase(Locale.GERMAN.getLanguage())) {
locale = Locale.GERMAN;
} else {
locale = Locale.ENGLISH;
}
return locale;
}
private static String getDefaultLanguageString() {
Locale locale = Locale.getDefault();
if (locale.getLanguage().equalsIgnoreCase(Locale.GERMAN.getLanguage())) {
return LANGUAGES[GERMAN];
}
if (locale.getLanguage().equalsIgnoreCase(Locale.ENGLISH.getLanguage())) {
return LANGUAGES[ENGLISH];
}
return "";
}
public boolean isShowPosition() {
if (configSystem == null) {
LOGGER.error("Configuration system not initialized yet.");
return true;
}
return configSystem.getBoolean(SHOW_MAP_POSITION);
}
@EventTopicSubscriber(topic = USED_LOOK_AND_FEEL)
public void onConfigChanged(@Nonnull String topic, ConfigChangedEvent event) {
if (topic.equals(USED_LOOK_AND_FEEL)) {
if (MainFrame.getInstance() != null) {
SubstanceLookAndFeel.setSkin(getLookAndFeel());
SwingUtilities.updateComponentTreeUI(MainFrame.getInstance());
}
}
}
/**
* Get the look and feel that shall be used.
*
* @return the class path of the look and feel that shall be used
*/
@Nonnull
public String getLookAndFeel() {
if (configSystem == null) {
LOGGER.error("Configuration system not initialized yet.");
return DEFAULT_LOOK_AND_FEEL;
}
String lookAndFeel = configSystem.getString(USED_LOOK_AND_FEEL);
if (lookAndFeel == null) {
return DEFAULT_LOOK_AND_FEEL;
}
return lookAndFeel;
}
/**
* Init the config system
*/
public void init() {
Path userDir = checkFolder();
configSystem = new ConfigSystem(userDir.resolve("MapEdit.xcfgz"));
configSystem.setDefault(MAPEDIT_FOLDER, Paths.get(System.getProperty("user.home")));
configSystem.setDefault(USE_WINDOW_DECO, true);
configSystem.setDefault(USED_LOOK_AND_FEEL, DEFAULT_LOOK_AND_FEEL);
configSystem.setDefault(USED_LANGUAGE, getDefaultLanguageString());
configSystem.setDefault(SHOW_MAP_POSITION, false);
configSystem.setDefault(WINDOW_HEIGHT, 700);
configSystem.setDefault(WINDOW_WIDTH, 1000);
}
/**
* This function determines the user data directory and requests the folder
* to store the client data in case it is needed. It also performs checks to
* see if the folder is valid.
*
* @return a string with the path to the folder or null in case no folder is
* set
*/
@Nonnull
private static Path checkFolder() {
Path userDir = DirectoryManager.getInstance().getDirectory(Directory.User);
assert userDir != null;
return userDir;
}
/**
* Set the size of the window
*
* @param windowSize size of the window
*/
public void setWindowSize(@Nonnull Dimension windowSize) {
if (configSystem == null) {
LOGGER.error("Configuration system not initialized yet.");
return;
}
configSystem.set(WINDOW_WIDTH, windowSize.width);
configSystem.set(WINDOW_HEIGHT, windowSize.height);
}
/**
* Get the last saved size of the window
*
* @return last saved size of the window
*/
@Nonnull
public Dimension getWindowSize() {
if (configSystem == null) {
LOGGER.error("Configuration system not initialized yet.");
return new Dimension(0, 0);
}
return new Dimension(configSystem.getInteger("windowSizeW"), configSystem.getInteger("windowSizeH"));
}
/**
* Save the configuration file to the filesystem of the local system.
*/
public void save() {
if (configSystem == null) {
LOGGER.error("Configuration system not initialized yet.");
return;
}
configSystem.save();
}
/**
* Get the internal used config object.
*
* @return the internal used config object
*/
@Nullable
public Config getInternalCfg() {
return configSystem;
}
/**
* Get the folder where to store the maps.
*
* @return the folder to store the maps
*/
@Nullable
public Path getMapFolder() {
if (configSystem == null) {
LOGGER.error("Configuration system not initialized yet.");
return Paths.get(System.getProperty("user.home"));
}
Path mapFolder = configSystem.getPath(MAPEDIT_FOLDER);
if (mapFolder == null) {
return Paths.get(System.getProperty("user.home"));
}
return mapFolder;
}
/**
* Set the folder where to store the maps.
*
* @param newFolder the folder where to store the maps
*/
public void setMapFolder(@Nonnull Path newFolder) {
if (configSystem == null) {
LOGGER.error("Configuration system not initialized yet.");
return;
}
configSystem.set(MAPEDIT_FOLDER, newFolder);
}
/**
* Get the flag if the editor is supposed to decorate the windows.
*
* @return {@code true} in case the editor is expected to decorate the
* windows
*/
public boolean isUseWindowDecoration() {
if (configSystem == null) {
LOGGER.error("Configuration system not initialized yet.");
return true;
}
return configSystem.getBoolean(USE_WINDOW_DECO);
}
}