richtercloud.document.scanner.gui.ScannerSelectionDialog.java Source code

Java tutorial

Introduction

Here is the source code for richtercloud.document.scanner.gui.ScannerSelectionDialog.java

Source

/**
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package richtercloud.document.scanner.gui;

import au.com.southsky.jfreesane.SaneDevice;
import au.com.southsky.jfreesane.SaneException;
import au.com.southsky.jfreesane.SaneOption;
import au.com.southsky.jfreesane.SaneSession;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetAddress;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.swing.JOptionPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import org.apache.commons.lang3.exception.ExceptionUtils;
import richtercloud.reflection.form.builder.message.Message;
import richtercloud.reflection.form.builder.message.MessageHandler;

/**
 * Allows displaying all SANE devices at an address and to view and edit its
 * setting as well select one for the application.
 *
 * The selected device and its address can be retrieved with
 * {@link #getSelectedDevice() } and {@link #getAddress() } after the dialog has
 * been closed.
 * @author richter
 */
public class ScannerSelectionDialog extends javax.swing.JDialog {
    private static final String SCANNER_ADDRESS_DEFAULT = "localhost";
    private static final long serialVersionUID = 1L;

    private class SelectionTableModel extends DefaultTableModel {
        private static final long serialVersionUID = 1L;
        private final List<SaneDevice> devices;

        SelectionTableModel(List<SaneDevice> devices) {
            super(new String[] { "Name", "Model", "Type", "Vendor" }, 0);
            this.devices = devices;
        }

        @Override
        public Object getValueAt(int row, int column) {
            if (column == 0) {
                return devices.get(row).getName();
            } else if (column == 1) {
                return devices.get(row).getModel();
            } else if (column == 2) {
                return devices.get(row).getType();
            } else if (column == 3) {
                return devices.get(row).getVendor();
            } else {
                throw new IllegalArgumentException();
            }
        }

        public void addDevices(List<SaneDevice> devices) {
            int lastRow = this.devices.size();
            this.devices.addAll(devices);
            fireTableRowsInserted(lastRow, this.devices.size());
        }

        public void addDevice(SaneDevice device) {
            this.devices.add(device);
            fireTableRowsInserted(devices.size(), devices.size());
        }

        public void clear() {
            int rowCount = this.devices.size();
            this.devices.clear();
            fireTableRowsDeleted(0, rowCount);
        }

        @Override
        public int getRowCount() {
            if (this.devices == null) {
                //during initialization (this is inefficient, but due to the bad design of DefaultTableModel
                return 0;
            }
            return this.devices.size();
        }

        @Override
        public int getColumnCount() {
            return 4;
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return String.class;
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return false;
        }

        public List<SaneDevice> getDevices() {
            return Collections.unmodifiableList(devices);
        }
    }

    private final SelectionTableModel tableModel = new SelectionTableModel(new LinkedList<SaneDevice>());
    private SaneSession scannerDialogSaneSession;
    private final TableModelListener scannerDialogTableModelListener = new TableModelListener() {
        @Override
        public void tableChanged(TableModelEvent e) {
            ScannerSelectionDialog.this.scannerDialogSelectButton
                    .setEnabled(ScannerSelectionDialog.this.scannerDialogSelectButtonEnabled());
            ScannerSelectionDialog.this.scannerDialogEditButton
                    .setEnabled(ScannerSelectionDialog.this.scannerDialogSelectButtonEnabled());
        }
    };
    private final ListSelectionListener scannerDialogTableSelectionListener = new ListSelectionListener() {
        @Override
        public void valueChanged(ListSelectionEvent e) {
            ScannerSelectionDialog.this.scannerDialogSelectButton
                    .setEnabled(ScannerSelectionDialog.this.scannerDialogSelectButtonEnabled());
            ScannerSelectionDialog.this.scannerDialogEditButton
                    .setEnabled(ScannerSelectionDialog.this.scannerDialogSelectButtonEnabled());
        }
    };
    private SaneDevice selectedDevice;
    /**
     * The address of the last search. Can't be retrieved reliably from the
     * address text field because its text might have changed after the last
     * search.
     */
    private String address;
    private final MessageHandler messageHandler;
    private final Map<String, SaneDevice> nameDeviceMap;
    private final Map<SaneDevice, Map<SaneOption, Object>> changedOptions;

    /**
     * Creates new form ScannerSelectionDialog
     * @param parent
     * @param messageHandler
     * @param nameDeviceMap
     * @param changedOptions
     * @param initialAddress
     */
    public ScannerSelectionDialog(java.awt.Frame parent, MessageHandler messageHandler,
            Map<String, SaneDevice> nameDeviceMap, Map<SaneDevice, Map<SaneOption, Object>> changedOptions,
            String initialAddress) {
        super(parent, true //modal
        );
        if (messageHandler == null) {
            throw new IllegalArgumentException("messageHandler mustn't be null");
        }
        this.messageHandler = messageHandler;
        if (nameDeviceMap == null) {
            throw new IllegalArgumentException("nameDeviceMap mustn't be null");
        }
        this.nameDeviceMap = nameDeviceMap;
        if (changedOptions == null) {
            throw new IllegalArgumentException("changedOptions mustn't be null");
        }
        this.changedOptions = changedOptions;
        initComponents();
        this.tableModel.addTableModelListener(this.scannerDialogTableModelListener);
        this.scannerDialogTable.getSelectionModel()
                .addListSelectionListener(this.scannerDialogTableSelectionListener);
        this.scannerDialogAddressTextField.setText(initialAddress);
    }

    public SaneDevice getSelectedDevice() {
        return selectedDevice;
    }

    public String getAddress() {
        return address;
    }

    private boolean scannerDialogSelectButtonEnabled() {
        return this.tableModel.getRowCount() > 0 && this.scannerDialogTable.getSelectedRowCount() > 0;
    }

    private void searchScanner() {
        String addressString = this.scannerDialogAddressTextField.getText();
        InetAddress address0;
        this.scannerDialogStatusLabel.setText("Searching...");
        try {
            address0 = InetAddress.getByName(addressString);
            this.scannerDialogSaneSession = SaneSession.withRemoteSane(address0);
            List<SaneDevice> availableDevices = this.scannerDialogSaneSession.listDevices();
            this.tableModel.addDevices(availableDevices);
            this.scannerDialogStatusLabel.setText(" ");
            this.address = addressString;
        } catch (ConnectException ex) {
            this.handleSearchScannerException(ex, DocumentScanner.SANED_BUG_INFO);
        } catch (IOException | SaneException ex) {
            this.handleSearchScannerException(ex, "");
        }
    }

    /**
     * for code reusage in {@link #searchScanner() }
     *
     * @param ex
     * @param additional
     */
    private void handleSearchScannerException(Exception ex, String additional) {
        String labelText = DocumentScanner.handleSearchScannerException(
                "The search at the specified address failed with the following error: ", ex, additional);
        this.scannerDialogStatusLabel.setText(labelText);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        scannerDialogAddressTextField = new javax.swing.JTextField();
        scannerDialogAddressLabel = new javax.swing.JLabel();
        scannerDialogSearchButton = new javax.swing.JButton();
        scannerDialogSeparator = new javax.swing.JSeparator();
        scannerDialogScrollPane = new javax.swing.JScrollPane();
        scannerDialogTable = new javax.swing.JTable();
        scannerDialogCancelButton = new javax.swing.JButton();
        scannerDialogSelectButton = new javax.swing.JButton();
        scannerDialogStatusLabel = new javax.swing.JLabel();
        scannerDialogEditButton = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);

        scannerDialogAddressTextField.setText(SCANNER_ADDRESS_DEFAULT);

        scannerDialogAddressLabel.setText("Address");

        scannerDialogSearchButton.setText("Search");
        scannerDialogSearchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                scannerDialogSearchButtonActionPerformed(evt);
            }
        });

        scannerDialogTable.setModel(tableModel);
        scannerDialogScrollPane.setViewportView(scannerDialogTable);

        scannerDialogCancelButton.setText("Cancel");
        scannerDialogCancelButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                scannerDialogCancelButtonActionPerformed(evt);
            }
        });

        scannerDialogSelectButton.setText("Select scanner");
        scannerDialogSelectButton.setEnabled(false);
        scannerDialogSelectButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                scannerDialogSelectButtonActionPerformed(evt);
            }
        });

        scannerDialogStatusLabel.setText(" ");

        scannerDialogEditButton.setText("Edit");
        scannerDialogEditButton.setEnabled(false);
        scannerDialogEditButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                scannerDialogEditButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup().addContainerGap()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
                                        layout.createSequentialGroup().addComponent(scannerDialogAddressLabel)
                                                .addGap(18, 18, 18).addComponent(scannerDialogAddressTextField))
                                .addComponent(scannerDialogSeparator)
                                .addComponent(scannerDialogScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 376,
                                        Short.MAX_VALUE)
                                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
                                        layout.createSequentialGroup().addGap(0, 0, Short.MAX_VALUE)
                                                .addComponent(scannerDialogEditButton)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                .addComponent(scannerDialogSelectButton)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                .addComponent(scannerDialogCancelButton))
                                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
                                        layout.createSequentialGroup().addComponent(scannerDialogStatusLabel)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED,
                                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                                .addComponent(scannerDialogSearchButton)))
                        .addContainerGap()));
        layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup().addContainerGap().addGroup(layout
                        .createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(scannerDialogAddressTextField, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(scannerDialogAddressLabel))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(scannerDialogSearchButton).addComponent(scannerDialogStatusLabel))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(scannerDialogSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 10,
                                javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(
                                scannerDialogScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 142, Short.MAX_VALUE)
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(scannerDialogCancelButton).addComponent(scannerDialogSelectButton)
                                .addComponent(scannerDialogEditButton))
                        .addContainerGap()));

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void scannerDialogSearchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scannerDialogSearchButtonActionPerformed
        this.searchScanner();
    }//GEN-LAST:event_scannerDialogSearchButtonActionPerformed

    private void scannerDialogCancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scannerDialogCancelButtonActionPerformed
        this.setVisible(false);
    }//GEN-LAST:event_scannerDialogCancelButtonActionPerformed

    private void scannerDialogSelectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scannerDialogSelectButtonActionPerformed
        assert this.scannerDialogTable.getSelectedRow() != -1;
        this.selectedDevice = this.tableModel.getDevices().get(this.scannerDialogTable.getSelectedRow());
        this.setVisible(false);
    }//GEN-LAST:event_scannerDialogSelectButtonActionPerformed

    private void scannerDialogEditButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scannerDialogEditButtonActionPerformed
        assert this.scannerDialogTable.getSelectedRow() != -1;
        SaneDevice device = this.tableModel.getDevices().get(this.scannerDialogTable.getSelectedRow());
        ScannerEditDialog scannerEditDialog;
        try {
            ScannerEditDialog.configureDefaultOptionValues(device, this.changedOptions, false);
            scannerEditDialog = new ScannerEditDialog(this, device, this.changedOptions, this.messageHandler);
            scannerEditDialog.setVisible(true);
        } catch (IOException | SaneException ex) {
            this.messageHandler.handle(new Message(
                    String.format("Exception during scanner configuration", ExceptionUtils.getRootCauseMessage(ex)),
                    JOptionPane.ERROR_MESSAGE, "Exception occured"));
        }
    }//GEN-LAST:event_scannerDialogEditButtonActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel scannerDialogAddressLabel;
    private javax.swing.JTextField scannerDialogAddressTextField;
    private javax.swing.JButton scannerDialogCancelButton;
    private javax.swing.JButton scannerDialogEditButton;
    private javax.swing.JScrollPane scannerDialogScrollPane;
    private javax.swing.JButton scannerDialogSearchButton;
    private javax.swing.JButton scannerDialogSelectButton;
    private javax.swing.JSeparator scannerDialogSeparator;
    private javax.swing.JLabel scannerDialogStatusLabel;
    private javax.swing.JTable scannerDialogTable;
    // End of variables declaration//GEN-END:variables
}