package org.openslx.dozmod.gui.control;
import java.awt.Color;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.EventListener;
import java.util.EventObject;
import javax.swing.Box;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.event.EventListenerList;
import org.openslx.dozmod.gui.changemonitor.DialogChangeMonitor;
import org.openslx.dozmod.gui.control.ComboBox.ComboBoxRenderer;
import org.openslx.dozmod.gui.control.RunscriptConfigurator.RunscriptType;
import org.openslx.dozmod.gui.helper.GridManager;
import org.openslx.dozmod.gui.helper.TextChangeListener;
/**
* Widget for advanced configuration options for lectures. This handles
* following options - Network rules - Runscript - USB
*/
public class RunscriptConfigurator extends RunscriptConfiguratorLayout {
private static final long serialVersionUID = -3497629601818983994L;
public static enum RunscriptType {
SHELL("Shellskript", "sh"), BATCH("Windows-Batch", "bat");
private final String displayName;
private final String extension;
private RunscriptType(String name, String extension) {
this.displayName = name;
this.extension = extension;
}
@Override
public String toString() {
return extension + " (" + displayName + ")";
}
}
public RunscriptConfigurator() {
super();
final TextChangeListener docListener = new TextChangeListener() {
@Override
public void changed() {
fireRunscriptConfigurationChangeEvent(new RunscriptConfigurationChangeEvent(
new Object()));
}
};
taRunScript.getDocument().addDocumentListener(docListener);
cboRunscriptType.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireRunscriptConfigurationChangeEvent(new RunscriptConfigurationChangeEvent(
new Object()));
}
});
cboRunscriptType.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
fireRunscriptConfigurationChangeEvent(new RunscriptConfigurationChangeEvent(
new Object()));
}
});
}
private void setError(final String msg) {
lblError.setText(msg);
}
/**
* Gets the runscript as String. The chosen interpreter will get encoded as
* 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
String extension = null;
Object cboContent = cboRunscriptType.getEditor().getItem();
if (cboContent instanceof RunscriptType) {
extension = ((RunscriptType) cboContent).extension;
} else if (cboContent instanceof String) {
extension = (String) cboContent;
}
String taInputText = taRunScript.getText();
if (taInputText.isEmpty())
return "";
if (extension == null || extension.isEmpty()) {
// this should never happen, so return null to report this invalid state
setError("Fehlende Dateinamenerweiterung!");
return null;
}
setError("");
return "ext=" + extension + "\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 extensionHeader = null;
try {
BufferedReader reader = new BufferedReader(new StringReader(config));
extensionHeader = reader.readLine();
reader.close();
} catch (IOException e) {
// swallow ...
}
if (extensionHeader != null) {
// we should have following format: ext=<interpreter>
// e.g. ext=sh
extensionHeader = extensionHeader.replace("ext=", "");
for (RunscriptType type : RunscriptType.values()) {
if (type.extension.equals(extensionHeader)) {
cboRunscriptType.setSelectedItem(type);
// mark that we found it by nulling the shebang...
extensionHeader = null;
continue;
}
}
if (extensionHeader != null) {
// user specific shebang, so just write the text to the cbo
cboRunscriptType.getEditor().setItem(extensionHeader);
}
}
// finished with the interpreter, remove that line from the given config
// before setting that text
taRunScript.setText(config.replaceFirst("^ext=.*\n", ""));
}
/**
* Custom event mechanism to detect changes to the user list (Mostly needed
* for the reactToChange() stuff in LectureDetailsWindow)
*/
protected EventListenerList listenerList = new EventListenerList();
public class RunscriptConfigurationChangeEvent extends EventObject {
private static final long serialVersionUID = -8779550754760035845L;
public RunscriptConfigurationChangeEvent(Object source) {
super(source);
}
}
public interface RunscriptConfigurationChangeEventListener extends
EventListener {
public void stateChanged(RunscriptConfigurationChangeEvent event);
}
public void addRunscriptConfigurationChangeEventListener(
RunscriptConfigurationChangeEventListener listener) {
listenerList.add(RunscriptConfigurationChangeEventListener.class,
listener);
}
public void removeRunscriptConfigurationChangeEventListener(
RunscriptConfigurationChangeEventListener listener) {
listenerList.remove(RunscriptConfigurationChangeEventListener.class,
listener);
}
void fireRunscriptConfigurationChangeEvent(
RunscriptConfigurationChangeEvent evt) {
Object[] listeners = listenerList.getListenerList();
for (int i = 0; i < listeners.length; i++) {
if (listeners[i] == RunscriptConfigurationChangeEventListener.class) {
((RunscriptConfigurationChangeEventListener) listeners[i + 1])
.stateChanged(evt);
}
}
}
public void addToChangeMonitor(DialogChangeMonitor changeMonitor) {
changeMonitor.add(taRunScript);
changeMonitor.addEditableCombo(cboRunscriptType, null, null, null);
}
}
/**
* Internal layout class for the advanced configurator (to keep it clean even
* for widgets)
*/
class RunscriptConfiguratorLayout extends JPanel {
private static final long serialVersionUID = 648729071828404053L;
private final static String txtRunScriptDesc = "Ein hier eingetragenes Skript wird nach dem Start dieser VM automatisch ausgeführt.";
protected final QLabel lblError;
protected final JTextArea taRunScript;
protected final ComboBox<RunscriptType> cboRunscriptType;
public RunscriptConfiguratorLayout() {
GridManager grid = new GridManager(this, 2, true, new Insets(5, 5, 5, 5));
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(new WordWrapLabel(txtRunScriptDesc, 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();
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);
}
}