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=;visibility=;... // 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 { 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 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 cboRunscriptType; protected final ComboBox cboRunscriptVisibility; protected final ComboBox 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() { @Override public String renderItem(SoundState item) { return item.displayName; } }); cboSoundState.setModel(new DefaultComboBoxModel(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( new ComboBoxRenderer() { @Override public String renderItem(RunscriptType item) { if (item == null) return null; return item.toString(); } }); cboRunscriptType.setModel(new DefaultComboBoxModel( 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(new ComboBoxRenderer() { @Override public String renderItem(RunscriptVisibility item) { if (item == null) return null; return item.displayName; } }); cboRunscriptVisibility.setModel(new DefaultComboBoxModel(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; } }