package org.openslx.dozmod.gui.configurator;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelListener;
import org.apache.log4j.Logger;
import org.openslx.bwlp.thrift.iface.NetShare;
import org.openslx.bwlp.thrift.iface.NetShareAuth;
import org.openslx.dozmod.gui.Gui;
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.table.CheckListTable.Wrapper;
import org.openslx.dozmod.gui.control.table.NetshareTable;
import org.openslx.dozmod.gui.control.table.QScrollPane;
import org.openslx.dozmod.gui.helper.GridManager;
import org.openslx.dozmod.gui.helper.MessageType;
import org.openslx.dozmod.thrift.cache.MetaDataCache;
import org.openslx.dozmod.util.FormatHelper;
/**
* Widget for network share configuration of lectures
*/
public class NetshareConfigurator extends NetshareConfiguratorLayout {
private static final long serialVersionUID = -3336605759245603655L;
private final static Logger LOGGER = Logger.getLogger(NetshareConfigurator.class);
public static final Character EMPTY_MARKER = '-';
public static final String PRINTER_MARKER = "PRINTER";
// mount points / win drive letters - ideally, we would check whether the image is linux or windows based
// and either show a drive selection list like this one, or a textfield for a user-defined mount point...
private Character[] mountPoints = { EMPTY_MARKER, 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
public NetshareConfigurator() {
super();
tblNetshare.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
NetShare item = tblNetshare.getSelectedItem2();
// only activate form fields if netshare is not predefined
boolean editable = (item == null || item.shareId == 0);
// now disable as needed
btnDel.setEnabled(editable);
btnAdd.setEnabled(editable);
tfSharePath.setEnabled(editable);
tfShareName.setEnabled(editable);
tfUsername.setEnabled(editable);
tfPassword.setEnabled(editable);
cboNetshareAuth.setEnabled(editable);
cboNetshareMountPoint.setEnabled(editable);
chkIsPrinter.setEnabled(editable);
chkShowPass.setEnabled(editable);
if (item == null) {
clearInputFields();
return;
}
// first set the fields to let any listener trigger
tfSharePath.setText(item.path);
if (item.displayname != null)
tfShareName.setText(
String.valueOf(EMPTY_MARKER).equals(item.displayname) ? "" : item.displayname);
tfUsername.setText(item.username);
tfPassword.setText(item.password);
cboNetshareAuth.setSelectedItem(item.auth);
if (item.mountpoint != null) {
chkIsPrinter.setSelected(item.mountpoint.equals(PRINTER_MARKER));
cboNetshareMountPoint
.setSelectedItem(item.mountpoint.equals(PRINTER_MARKER) ? null
: Character.valueOf(item.mountpoint.charAt(0)));
cboNetshareMountPoint.setEnabled(editable && !item.mountpoint.equals(PRINTER_MARKER));
}
if (editable)
btnAdd.setText("Ändern");
}
});
cboNetshareMountPoint.setModel(new DefaultComboBoxModel<Character>(mountPoints));
cboNetshareMountPoint.setSelectedItem(null);
chkIsPrinter.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
cboNetshareMountPoint.setEnabled(e.getStateChange() != ItemEvent.SELECTED);
}
});
chkIsPrinter.setSelected(false);
// combobox for share authentication types
cboNetshareAuth.setModel(new DefaultComboBoxModel<NetShareAuth>(NetShareAuth.values()));
cboNetshareAuth.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
NetShareAuth selectedAuth = cboNetshareAuth.getItemAt(cboNetshareAuth.getSelectedIndex());
boolean activate = selectedAuth != null && selectedAuth == NetShareAuth.OTHER_USER;
// username field is needed to either special or guest user
tfUsername.setEnabled(activate);
tfPassword.setEnabled(activate);
chkShowPass.setEnabled(activate);
}
});
cboNetshareAuth.setSelectedItem(null);
btnAdd.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// check if we are editing an existing share entry or
// creating a new one, check for input either way
NetShare input = new NetShare();
input.path = tfSharePath.getText();
if (input.path == null || input.path.isEmpty()) {
lblError.setText("Kein Pfad angegeben!");
return;
}
String inputShareName = tfShareName.getText();
if (inputShareName.isEmpty())
inputShareName = String.valueOf(EMPTY_MARKER);
input.displayname = inputShareName;
NetShareAuth inputNetShareAuth = cboNetshareAuth
.getItemAt(cboNetshareAuth.getSelectedIndex());
if (inputNetShareAuth == null) {
lblError.setText("Kein Authentifizierungstyp angegeben!");
return;
}
input.auth = inputNetShareAuth;
switch (inputNetShareAuth) {
case LOGIN_USER:
// this uses the service client's logged in user
// we don't need to have anything
break;
case OTHER_USER:
// save given username/password
input.username = tfUsername.getText();
input.password = new String(tfPassword.getPassword());
if (input.username.isEmpty()) {
lblError.setText("Kein Nutzername angegeben!");
return;
}
break;
default:
input = null;
break;
}
if (input == null) {
lblError.setText("Fehlerhafte Eingabe");
LOGGER.debug("Bad input, aborting.");
return;
}
// process mount point and printer check box
Character inputMountPoint = cboNetshareMountPoint
.getItemAt(cboNetshareMountPoint.getSelectedIndex());
if (!chkIsPrinter.isSelected()) {
if (inputMountPoint == null) {
lblError.setText("Kein Laufwerk angegeben!");
return;
}
input.mountpoint = String.valueOf(inputMountPoint);
} else {
input.mountpoint = PRINTER_MARKER;
}
// if a password is set, warn the user about its unsafe storage
// which we might want to implement one day...
if (input.password != null && !input.password.isEmpty()) {
if (!Gui.showMessageBox(
"Das eingebene Passwort wird im Klartext gespeichert "
+ "und ist in der VM für jeden Nutzer sichtbar.\n"
+ "Verwenden Sie auf keinen Fall sicherheitskritische Passwörter!"
+ "\n\nMöchten Sie diesen Netzlaufwerk trotzdem hinzufügen?",
MessageType.QUESTION_YESNO, LOGGER, null)) {
return;
}
}
Wrapper<NetShare> newEntry = new Wrapper<NetShare>(input, false);
Wrapper<NetShare> oldEntry = tblNetshare.getSelectedItem();
List<Wrapper<NetShare>> oldList = new ArrayList<>(tblNetshare.getData());
// now decide whether to create a new entry or update existing one
if (oldEntry != null && oldList.contains(oldEntry)) {
// editing existing one, delete it from the internal data
if (!oldList.remove(oldEntry)) {
lblError.setText("Änderung fehlgeschlagen!");
LOGGER.error("Failed to remove selected share for replacement: " + oldEntry);
return;
}
}
// either we deleted the existing share from the data or we are
// creating a new one, either way add it to the list and update
// the table, if its not present already
if (oldList.contains(newEntry)) {
lblError.setText("Existiert bereits!");
LOGGER.error("Network share already in the list, aborting.");
return;
}
lblError.setText(null);
oldList.add(newEntry);
tblNetshare.setData(oldList, false);
clearInputFields();
}
});
btnDel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// try to delete the selected share
Wrapper<NetShare> selection = tblNetshare.getSelectedItem();
if (selection == null) {
return;
}
List<Wrapper<NetShare>> oldList = new ArrayList<>(tblNetshare.getData());
try {
if (!oldList.remove(selection)) {
// false if it was not found
LOGGER.error("Could not remove non-existant network share '" + selection.toString()
+ "' from the table data: " + oldList.toString());
return;
}
// refresh table data
tblNetshare.setData(oldList, true);
} catch (Exception ex) {
LOGGER.debug("Failed to remove " + selection.toString() + " from the table data.", ex);
return;
}
}
});
chkShowPass.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() != ItemEvent.SELECTED) {
tfPassword.setEchoChar('*');
} else {
tfPassword.setEchoChar((char) 0);
}
}
});
clearInputFields();
}
private void clearInputFields() {
btnDel.setEnabled(false);
tfSharePath.setText(null);
tfShareName.setText(null);
tfUsername.setText(null);
tfPassword.setText(null);
cboNetshareAuth.setSelectedItem(null);
cboNetshareMountPoint.setSelectedItem(null);
chkIsPrinter.setSelected(false);
chkShowPass.setSelected(false);
btnAdd.setText("Hinzufügen");
}
public List<NetShare> getState() {
List<Wrapper<NetShare>> list = tblNetshare.getData();
if (list == null)
return new ArrayList<>(0);
List<NetShare> ret = new ArrayList<>();
for (Wrapper<NetShare> item : list) {
if (item.isChecked() || item.item.shareId == 0) {
ret.add(item.item);
}
}
return ret;
}
public boolean setState(List<NetShare> data, List<Integer> predefSelected) {
if (data == null)
return false;
List<NetShare> shareList = new ArrayList<>(data);
List<NetShare> predef = MetaDataCache.getPredefinedNetshares();
Set<NetShare> checked = new HashSet<>();
for (NetShare share : predef) {
shareList.add(share);
if (predefSelected != null && predefSelected.contains(share.shareId)) {
checked.add(share);
}
}
tblNetshare.setData(shareList, checked, false);
return true;
}
public void addTableModelListener(TableModelListener listener) {
tblNetshare.getModel().addTableModelListener(listener);
}
public void addToChangeMonitor(DialogChangeMonitor changeMonitor) {
changeMonitor.add(tblNetshare);
}
}
/**
* Internal layout class for this widget
*/
class NetshareConfiguratorLayout extends JPanel {
private static final long serialVersionUID = 6479525981542743622L;
private final static String txtNetshareDesc = "<html>Hier können Sie Netzlaufwerke angeben,"
+ " die automatisch beim Start der Veranstaltung eingebunden werden sollen."
+ " Der Platzhalter <em>%loginuser%</em> wird im Pfad durch den Loginnamen des Nutzers ersetzt.</html>";
protected final JLabel lblError;
protected final NetshareTable tblNetshare = new NetshareTable();
protected final JTextField tfSharePath, tfShareName, tfUsername;
protected final JPasswordField tfPassword;
protected final JButton btnAdd, btnDel;
protected final JCheckBox chkIsPrinter;
protected final JCheckBox chkShowPass;
protected final ComboBox<NetShareAuth> cboNetshareAuth = new ComboBox<>(
new ComboBoxRenderer<NetShareAuth>() {
@Override
public String renderItem(NetShareAuth item) {
if (item == null)
return null;
return FormatHelper.netShareAuthName(item);
}
});
protected final ComboBox<Character> cboNetshareMountPoint = new ComboBox<>(
new ComboBoxRenderer<Character>() {
@Override
public String renderItem(Character letter) {
if (letter == null)
return null;
return letter.equals(NetshareConfigurator.EMPTY_MARKER) ? letter.toString()
: letter.toString() + ":";
}
});
public NetshareConfiguratorLayout() {
GridManager grid = new GridManager(this, 3, true, new Insets(3, 3, 3, 3));
// top info panel
grid.add(new JLabel(txtNetshareDesc), 3).fill(true, false).expand(true, false);
grid.nextRow();
// middle netshare list
grid.add(new QScrollPane(tblNetshare), 3).fill(true, true).expand(true, true);
grid.nextRow();
JPanel pnlNewShare = new JPanel();
GridManager gridNewShare = new GridManager(pnlNewShare, 6, true, new Insets(0, 3, 0, 3));
pnlNewShare.setBorder(BorderFactory.createTitledBorder("Eigenes Netzlaufwerk definieren"));
JPanel pnlSharePath = new JPanel();
pnlSharePath.setLayout(new BoxLayout(pnlSharePath, BoxLayout.LINE_AXIS));
gridNewShare.add(new QLabel("Pfad"));
tfSharePath = new JTextField();
pnlSharePath.add(tfSharePath);
pnlSharePath.add(Box.createGlue());
pnlSharePath.add(Box.createHorizontalStrut(5));
chkIsPrinter = new JCheckBox("Drucker");
pnlSharePath.add(chkIsPrinter);
pnlSharePath.add(Box.createHorizontalStrut(5));
gridNewShare.add(pnlSharePath, 5).fill(true, false).expand(true, false);
gridNewShare.nextRow();
// bottom form to add a new share
tfShareName = new JTextField();
// extra panel for fancy layout purposes...
JPanel pnlShareName = new JPanel();
pnlShareName.setLayout(new BoxLayout(pnlShareName, BoxLayout.LINE_AXIS));
pnlShareName.add(tfShareName);
pnlShareName.add(Box.createHorizontalStrut(3));
pnlShareName.add(new QLabel("Laufwerk"));
pnlShareName.add(Box.createHorizontalStrut(3));
pnlShareName.add(cboNetshareMountPoint);
gridNewShare.add(new QLabel("Anzeigename"));
gridNewShare.add(pnlShareName, 5).fill(true, false).expand(true, false);
gridNewShare.nextRow();
gridNewShare.add(new QLabel("Authentifizierung"));
gridNewShare.add(cboNetshareAuth, 5).fill(true, false).expand(true, false);
gridNewShare.nextRow();
gridNewShare.add(new QLabel("Username"));
tfUsername = new JTextField(20);
gridNewShare.add(tfUsername, 2).fill(true, false).expand(true, false);
gridNewShare.add(new QLabel("Passwort"));
tfPassword = new JPasswordField(20);
gridNewShare.add(tfPassword, 2).fill(true, false).expand(true, false);
gridNewShare.nextRow();
chkShowPass = new JCheckBox("Passwort anzeigen");
gridNewShare.add(Box.createGlue(), 5);
gridNewShare.add(chkShowPass).anchor(GridBagConstraints.EAST);
gridNewShare.nextRow();
grid.add(pnlNewShare, 3).fill(true, false).expand(true, false);
grid.nextRow();
btnAdd = new JButton("Hinzufügen");
btnDel = new JButton("Entfernen");
lblError = new QLabel("");
lblError.setForeground(Color.RED);
grid.add(lblError).fill(true, false).expand(true, false);
grid.add(btnAdd).anchor(GridBagConstraints.EAST);
grid.add(btnDel).anchor(GridBagConstraints.EAST);
grid.finish(false);
}
}