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) { boolean isPrinter = item.mountpoint.equals(PRINTER_MARKER); chkIsPrinter.setSelected(isPrinter); cboNetshareMountPoint.setSelectedItem(isPrinter ? null : item.mountpoint.isEmpty() ? EMPTY_MARKER : Character.valueOf(item.mountpoint.charAt(0))); cboNetshareMountPoint.setEnabled(editable && !isPrinter); } if (editable) btnAdd.setText("Ändern"); } }); cboNetshareMountPoint.setModel(new DefaultComboBoxModel(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.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 newEntry = new Wrapper(input, false); Wrapper oldEntry = tblNetshare.getSelectedItem(); List> 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 selection = tblNetshare.getSelectedItem(); if (selection == null) { return; } List> 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 getState() { List> list = tblNetshare.getData(); if (list == null) return new ArrayList<>(0); List ret = new ArrayList<>(); for (Wrapper item : list) { if (item.isChecked() || item.item.shareId == 0) { ret.add(item.item); } } return ret; } public boolean setState(List data, List predefSelected) { if (data == null) return false; List shareList = new ArrayList<>(data); List predef = MetaDataCache.getPredefinedNetshares(); Set 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 = "Hier können Sie Netzlaufwerke angeben," + " die automatisch beim Start der Veranstaltung eingebunden werden sollen." + " Der Platzhalter %loginuser% wird im Pfad durch den Loginnamen des Nutzers ersetzt."; 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 cboNetshareAuth = new ComboBox<>( new ComboBoxRenderer() { @Override public String renderItem(NetShareAuth item) { if (item == null) return null; return FormatHelper.netShareAuthName(item); } }); protected final ComboBox cboNetshareMountPoint = new ComboBox<>( new ComboBoxRenderer() { @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); } }