package org.openslx.dozmod.gui.configurator;
import java.awt.Color;
import java.awt.Insets;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import javax.swing.Box;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import org.openslx.dozmod.gui.changemonitor.DialogChangeMonitor;
import org.openslx.dozmod.gui.control.ComboBox;
import org.openslx.dozmod.gui.control.ComboBox.ComboBoxRenderer;
import org.openslx.dozmod.gui.control.QLabel;
import org.openslx.dozmod.gui.control.WordWrapLabel;
import org.openslx.dozmod.gui.helper.GridManager;
import org.openslx.util.Util;
/**
* Widget for advanced configuration options for lectures. This handles
* Runscript and sound (un)muting
*/
public class StartupConfigurator extends StartupConfiguratorLayout {
private static final long serialVersionUID = -3497629601818983994L;
private StartupSettings startupSettings = new StartupSettings(null);
public StartupConfigurator() {
super();
}
private void setError(final String msg) {
lblError.setText(msg);
}
/**
* Gets the runscript as String. The chosen interpreter and visibility flag
* will get encoded in the first line of the script.
*
* @return runscript as String. If no text was entered, returns a empty
* string.
*/
public String getState() {
setError(""); // fill remove any prior errors, we'll reset them if needed
// handle user input, this is tricky since
// * either an item has been selected -> editorContent will be of our enum type
// * user typed its own interpreter into the box -> editorContent will be a castable String
Object cboContent = cboRunscriptType.getEditor().getItem();
if (cboContent instanceof RunscriptType) {
startupSettings.put(Field.EXTENSION, ((RunscriptType) cboContent).extension);
} else if (cboContent instanceof String) {
startupSettings.put(Field.EXTENSION, (String) cboContent);
}
String taInputText = taRunScript.getText();
RunscriptVisibility visibility = (RunscriptVisibility) cboRunscriptVisibility.getSelectedItem();
startupSettings.put(Field.VISIBILITY, Integer.toString(visibility.value));
SoundState sound = (SoundState)cboSoundState.getSelectedItem();
startupSettings.put(Field.MUTED, Integer.toString(sound.value));
setError("");
return startupSettings.serialize() + "\n" + taInputText;
}
/**
* Sets the state of this widget to the given AdvancedConfiguration. Basicly
* this sets the content of the text areas to the corresponding network
* rules/runscript as given by the AdvancedConfiguration object
*
* @param config
* AdvancedConfiguration to set the state to
*/
public void setState(final String config) {
if (config == null || config.isEmpty()) {
cboRunscriptType.setSelectedItem(null);
taRunScript.setText("");
return;
}
String header = null;
try (BufferedReader reader = new BufferedReader(new StringReader(config))) {
header = reader.readLine();
} catch (IOException e) {
// swallow ...
}
if (header != null) {
// we should have following format: ext=<interpreter/extension>;visibility=<flag>;...
// e.g. ext=sh;visibility=0
startupSettings.deserialize(header);
String extension = startupSettings.get(Field.EXTENSION);
for (RunscriptType type : RunscriptType.values()) {
if (type.extension.equals(extension)) {
cboRunscriptType.setSelectedItem(type);
// mark that we found it by nulling the shebang...
extension = null;
break;
}
}
int visibility = Util.parseInt(startupSettings.get(Field.VISIBILITY), 1);
for (RunscriptVisibility windowFlag : RunscriptVisibility.values()) {
if (windowFlag.value == visibility) {
cboRunscriptVisibility.setSelectedItem(windowFlag);
break;
}
}
cboSoundState.setSelectedItem(SoundState.DEFAULT);
int mute = Util.parseInt(startupSettings.get(Field.MUTED), -1);
for (SoundState s : SoundState.values()) {
if (s.value == mute) {
cboSoundState.setSelectedItem(s);
break;
}
}
if (extension != null) {
// user specific shebang, so just write the text to the cbo
cboRunscriptType.getEditor().setItem(extension);
}
}
// finished with the interpreter, remove that line from the given config
// before setting that text
taRunScript.setText(config.replaceFirst(".*?\n", ""));
}
public void addToChangeMonitor(DialogChangeMonitor changeMonitor) {
changeMonitor.add(taRunScript);
changeMonitor.addEditableCombo(cboRunscriptType, null);
changeMonitor.addFixedCombo(cboRunscriptVisibility, null);
changeMonitor.addFixedCombo(cboSoundState, null);
}
private static enum Field {
EXTENSION("ext"),
VISIBILITY("visibility"),
MUTED("soundMuted");
public final String id;
Field(String id) {
this.id = id;
}
}
/**
* Map holding the inline settings from line 1 of the script
*/
private static class StartupSettings extends HashMap<String, String> {
private static final long serialVersionUID = -5893345450266600626L;
public StartupSettings(String data) {
super();
deserialize(data);
}
public String put(Field key, String value) {
value = value.replace(';', '_').replace('\r', '_').replace('\n', '_');
return super.put(key.id, value);
}
public String get(Field key)
{
String ret = super.get(key.id);
if (ret == null)
return "";
return ret;
}
public String serialize() {
StringBuilder sb = new StringBuilder();
for (Entry<String, String> e : this.entrySet()) {
if (sb.length() != 0) {
sb.append(';');
}
sb.append(e.getKey());
sb.append('=');
sb.append(e.getValue());
}
return sb.toString();
}
public void deserialize(String data) {
if (data == null)
return;
clear();
String[] parts = data.split(";");
for (String s : parts) {
String[] entry = s.split("=");
if (entry.length == 2) {
put(entry[0], entry[1]);
}
}
}
}
}
/**
* Internal layout class for the advanced configurator (to keep it clean even
* for widgets)
*/
class StartupConfiguratorLayout extends JPanel {
private static final long serialVersionUID = 648729071828404053L;
private final static String RUN_SCRIPT_HELP = "Ein hier eingetragenes Skript wird nach dem Start"
+ " der VM automatisch ausgeführt.";
protected final QLabel lblError;
protected final JTextArea taRunScript;
protected final ComboBox<RunscriptType> cboRunscriptType;
protected final ComboBox<RunscriptVisibility> cboRunscriptVisibility;
protected final ComboBox<SoundState> cboSoundState;
public StartupConfiguratorLayout() {
GridManager grid = new GridManager(this, 2, true, new Insets(5, 5, 5, 5));
grid.add(new QLabel("Audio"));
cboSoundState = new ComboBox<>(new ComboBoxRenderer<SoundState>() {
@Override
public String renderItem(SoundState item) {
return item.displayName;
}
});
cboSoundState.setModel(new DefaultComboBoxModel<SoundState>(SoundState.values()));
grid.add(cboSoundState).fill(true, false).expand(true, false);
grid.nextRow();
grid.add(Box.createVerticalStrut(4), 2);
grid.nextRow();
grid.add(new WordWrapLabel(RUN_SCRIPT_HELP, false, true), 2)
.fill(true, false).expand(true, false);
grid.nextRow();
cboRunscriptType = new ComboBox<RunscriptType>(
new ComboBoxRenderer<RunscriptType>() {
@Override
public String renderItem(RunscriptType item) {
if (item == null)
return null;
return item.toString();
}
});
cboRunscriptType.setModel(new DefaultComboBoxModel<RunscriptType>(
RunscriptType.values()));
cboRunscriptType.setEditable(true);
grid.add(new QLabel("Dateinamenserweiterung: ")).fill(false, false)
.expand(false, false);
grid.add(cboRunscriptType).fill(true, false)
.expand(true, false);
grid.nextRow();
cboRunscriptVisibility = new ComboBox<RunscriptVisibility>(new ComboBoxRenderer<RunscriptVisibility>() {
@Override
public String renderItem(RunscriptVisibility item) {
if (item == null)
return null;
return item.displayName;
}
});
cboRunscriptVisibility.setModel(new DefaultComboBoxModel<RunscriptVisibility>(RunscriptVisibility.values()));
grid.add(new QLabel("Sichtbarkeit: ")).fill(false, false)
.expand(false, false);
grid.add(cboRunscriptVisibility).fill(true, false)
.expand(true, false);
grid.nextRow();
taRunScript = new JTextArea("", 5, 20);
JScrollPane scpRunScript = new JScrollPane(taRunScript,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
taRunScript.setLineWrap(true);
taRunScript.setWrapStyleWord(true);
grid.add(scpRunScript, 2).fill(true, true).expand(true, true);
grid.nextRow();
lblError = new QLabel("");
lblError.setForeground(Color.RED);
JPanel pnlError = new JPanel();
pnlError.add(Box.createGlue());
pnlError.add(lblError);
pnlError.add(Box.createGlue());
grid.add(pnlError, 2).fill(true, false).expand(true, false);
grid.finish(false);
}
}
enum RunscriptType {
SHELL("Shellskript", "sh"), BATCH("Windows-Batch", "bat");
public final String displayName;
public final String extension;
private RunscriptType(String name, String extension) {
this.displayName = name;
this.extension = extension;
}
@Override
public String toString() {
return extension + " (" + displayName + ")";
}
}
enum RunscriptVisibility {
NORMAL("Normal", 1), MINIMIZED("Minimiert", 2), HIDDEN("Versteckt", 0);
public final String displayName;
public final int value;
private RunscriptVisibility(String name, int flag) {
this.displayName = name;
this.value = flag;
}
}
enum SoundState {
DEFAULT("Vorgabe des Pools", -1), MUTED("Stummschalten", 1), UNMUTED("Aktivieren", 0);
public final String displayName;
public final int value;
private SoundState(String name, int value) {
this.displayName = name;
this.value = value;
}
}