package de.uni_passau.fim.infosun.prophet.experimentEditor;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import de.uni_passau.fim.infosun.prophet.Constants;
import de.uni_passau.fim.infosun.prophet.experimentEditor.qTree.QTree;
import de.uni_passau.fim.infosun.prophet.experimentEditor.tabbedPane.ExperimentEditorTabbedPane;
import de.uni_passau.fim.infosun.prophet.util.language.UIElementNames;
/**
* An editor for experiments that can be viewed by experimentees using the <code>EViewer</code>.
*
* @author Georg Seibt
* @author Andreas Hasselberg
* @author Markus Köppen
*/
public class ExperimentEditor extends JFrame {
private static final String CONFIG_FILENAME = "config";
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
private Properties config;
/**
* Shows the GUI of the <code>ExperimentEditor</code>.
*
* @param args
* command line arguments, ignored by this application
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (UnsupportedLookAndFeelException | InstantiationException | IllegalAccessException | ClassNotFoundException e) {
System.err.println("Could not set the look and feel to the system look and feel.");
System.err.println(e.getMessage());
}
new ExperimentEditor().setVisible(true);
});
}
/**
* Constructs a new <code>ExperimentEditor</code>.
*/
public ExperimentEditor() {
loadConfig();
initLanguage();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setTitle(getClass().getSimpleName());
setPreferredSize(new Dimension(WIDTH, HEIGHT));
JSplitPane splitPane = new JSplitPane();
add(splitPane, BorderLayout.CENTER);
QTree tree = new QTree();
JScrollPane treeScrollPane = new JScrollPane(tree);
treeScrollPane.setBorder(BorderFactory.createEmptyBorder());
splitPane.setLeftComponent(treeScrollPane);
ExperimentEditorTabbedPane tabbedPane = new ExperimentEditorTabbedPane(tree);
splitPane.setRightComponent(tabbedPane);
splitPane.setBorder(null);
for (Component component : splitPane.getComponents()) {
if (component instanceof BasicSplitPaneDivider) {
((BasicSplitPaneDivider) component).setBorder(null);
}
}
ExperimentEditorMenuBar menuBar = new ExperimentEditorMenuBar(tree, tabbedPane);
setJMenuBar(menuBar);
pack();
splitPane.setDividerLocation(0.15);
setLocationRelativeTo(null);
}
/**
* Loads the 'config' file as a <code>Properties</code> object. If there is no such file an empty
* <code>Properties</code> object will be used. Also attaches a window listener that writes the config file to
* disk when the current <code>Window</code> is closing.
*/
private void loadConfig() {
File configFile = new File(CONFIG_FILENAME);
config = new Properties();
if (configFile.exists() && !configFile.isDirectory()) {
CharsetDecoder dec = StandardCharsets.UTF_8.newDecoder();
try (Reader reader = new InputStreamReader(new FileInputStream(configFile), dec) ){
config.load(reader);
} catch (IOException | IllegalArgumentException e) {
System.err.println("Could not load properties file " + configFile.getAbsolutePath());
}
}
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent event) {
CharsetEncoder enc = StandardCharsets.UTF_8.newEncoder();
try (Writer writer = new OutputStreamWriter(new FileOutputStream(configFile), enc)) {
config.store(writer, null);
} catch (IOException e) {
System.err.println("Could not store properties file " + configFile.getAbsolutePath());
System.err.println(e.getMessage());
}
super.windowClosing(event);
}
});
}
/**
* Initialises the <code>Locale</code> this <code>ExperimentEditor</code> is using. If no language is defined
* in the config file the user is asked to select one.
*/
private void initLanguage() {
String langKey = "language";
String language = config.getProperty(langKey);
Locale locale;
if (language == null) {
locale = getPreferredLanguage();
config.setProperty(langKey, locale.toLanguageTag());
} else {
locale = Locale.forLanguageTag(language);
}
UIElementNames.setLocale(locale);
}
/**
* Shows a dialog asking the user to select a language. If the user makes no selection <code>Locale.ENGLISH</code>
* is returned.
*
* @return the selected <code>Locale</code>
*/
private Locale getPreferredLanguage() {
Map<String, Locale> languages = new HashMap<>();
String message = "Select a language for PROPHET";
String title = "Input";
Object selectedLanguage;
Object[] values;
languages.put("German", Locale.GERMAN);
languages.put("English", Locale.ENGLISH);
languages.put("Portuguese (Brazil)", Constants.PORTUGUES_BR);
values = languages.keySet().toArray();
selectedLanguage = JOptionPane.showInputDialog(null, message, title, JOptionPane.INFORMATION_MESSAGE, null,
values, values[0]);
return languages.getOrDefault(selectedLanguage, Locale.ENGLISH);
}
}