package com.swingsane.gui.controller; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.concurrent.TimeUnit; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.text.BadLocationException; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import org.apache.log4j.Logger; import au.com.southsky.jfreesane.RateLimitingScanListeners; import au.com.southsky.jfreesane.SaneDevice; import au.com.southsky.jfreesane.SaneException; import au.com.southsky.jfreesane.ScanListener; import au.com.southsky.jfreesane.ScanListenerAdapter; import com.swingsane.business.discovery.DiscoveryEvent; import com.swingsane.business.discovery.DiscoveryJob; import com.swingsane.business.discovery.DiscoveryListener; import com.swingsane.business.notification.INotification; import com.swingsane.business.options.KnownSaneOptions; import com.swingsane.business.scanning.IScanService; import com.swingsane.business.scanning.ScanEvent; import com.swingsane.business.scanning.ScanEventListener; import com.swingsane.business.scanning.ScanJob; import com.swingsane.gui.dialog.CustomSettingsDialog; import com.swingsane.gui.dialog.GlobalSettingsDialog; import com.swingsane.gui.dialog.ScannerSettingsDialog; import com.swingsane.gui.list.ScannerListItem; import com.swingsane.gui.list.ScannerListItem.ScannerStatus; import com.swingsane.i18n.Localizer; import com.swingsane.preferences.IPreferredDefaults; import com.swingsane.preferences.ISwingSanePreferences; import com.swingsane.preferences.PreferencesUtils; import com.swingsane.preferences.model.ApplicationPreferences; import com.swingsane.preferences.model.Login; import com.swingsane.preferences.model.Scanner; import com.swingsane.util.Misc; import com.thoughtworks.xstream.XStream; public class ComponentController implements INotification { /** * Log4J logger. */ private static final Logger LOG = Logger.getLogger(ComponentController.class); private IComponents components; private IScanEventHandler scanEventHandler; private IScanService scanService; private IPreferredDefaults preferredDefaults; private ISwingSanePreferences preferences; private DiscoveryJob discoveryJob; private DiscoveryListener discoveryListener; private static final int PROGRESS_BAR_UPDATE_INTERVAL = 100; private DefaultListModel<ScannerListItem> scannerListModel = new DefaultListModel<ScannerListItem>(); private XStream xstream; public ComponentController() { } @Override public void addAbortListener() { } private void addMessage(String message) { StyledDocument doc = components.getMessagesTextPane().getStyledDocument(); SimpleAttributeSet keyWord = new SimpleAttributeSet(); StyleConstants.setForeground(keyWord, Color.GREEN); StyleConstants.setBackground(keyWord, Color.BLUE); StyleConstants.setBold(keyWord, true); try { if (message.toLowerCase().startsWith("found ")) { doc.insertString(0, message + "\n", keyWord); } else { doc.insertString(0, message + "\n", null); } } catch (BadLocationException e) { LOG.error(e, e); } } private void addScannerButtonActionPerformed(ActionEvent e) { ScannerSettingsDialog scannerSettingsDialog = new ScannerSettingsDialog( components.getRootComponent()); scannerSettingsDialog.setTitle(Localizer.localize("AddScannerDialogTitle")); scannerSettingsDialog.setModal(true); scannerSettingsDialog.setVisible(true); if (scannerSettingsDialog.getDialogResult() == JOptionPane.OK_OPTION) { try { detectScanners(scannerSettingsDialog.getRemoteAddress(), scannerSettingsDialog.getPortNumber(), scannerSettingsDialog.getDescription()); } catch (UnknownHostException ex) { LOG.error(ex, ex); } catch (IOException ex) { LOG.error(ex, ex); } catch (SaneException ex) { LOG.error(ex, ex); } } } private void adjustSettingsComponents(Scanner scanner) { boolean isUsingCustomOptions = scanner.isUsingCustomOptions(); components.getSaveSettingsButton().setEnabled(true); components.getUseCustomSettingsCheckBox().setEnabled(true); components.getUseCustomSettingsCheckBox().setSelected(isUsingCustomOptions); components.getCustomSettingsButton().setEnabled(isUsingCustomOptions); if (!isUsingCustomOptions) { updateResolutionModel(KnownSaneOptions.getResolutionModel(scanner), KnownSaneOptions.getResolution(scanner)); updatePageSizeModel(KnownSaneOptions.getPageSizeModel(scanner), KnownSaneOptions.getPageSize(scanner)); updateColorModeModel(KnownSaneOptions.getColorModeComponent(scanner), KnownSaneOptions.getColorMode(scanner)); updateDuplexCheckBox(KnownSaneOptions.isDuplexScanningAvailable(scanner), KnownSaneOptions.isDuplexScanningEnabled(scanner)); updateAutoCropCheckBox(KnownSaneOptions.isAutoCropAvailable(scanner), KnownSaneOptions.isAutoCropSelected(scanner)); updateBlackThresholdModel(KnownSaneOptions.getBlackThresholdModel(scanner)); updateUsingBlackThresholdCheckBox(KnownSaneOptions.isUsingDefaultBlackThreshold(scanner)); updateSourceModel(KnownSaneOptions.getSourceModel(scanner), KnownSaneOptions.getSource(scanner)); } updateBatchPrefix(scanner.getBatchPrefix()); updatePagesToScan(new Integer(scanner.getPagesToScan())); updateBatchScanCheckBox(KnownSaneOptions.isBatchScanAvailable(scanner), KnownSaneOptions.isBatchScanSelected(scanner)); } private void autoCropCheckBoxStateChanged(ActionEvent e) { if (getSelectedScannerListItem() == null) { return; } Scanner scanner = getSelectedScannerListItem().getScanner(); if (scanner == null) { return; } KnownSaneOptions.setAutoCrop(scanner, components.getAutoCropCheckBox().isSelected()); } private void batchNameCaretUpdateActionPerformed(CaretEvent e) { ScannerListItem currentScannerListItem = components.getScannerList().getSelectedValue(); if (currentScannerListItem == null) { return; } Scanner scanner = currentScannerListItem.getScanner(); if (scanner == null) { return; } scanner.setBatchPrefix(components.getBatchNameTextField().getText()); } private void blackThresholdSpinnerStateChanged(ChangeEvent e) { if (getSelectedScannerListItem() == null) { return; } Scanner scanner = getSelectedScannerListItem().getScanner(); if (scanner == null) { return; } KnownSaneOptions.setBlackThreshold(scanner, (Integer) components.getBlackThresholdSpinner() .getValue()); } private void cancelDetection(ActionEvent e) { if ((discoveryJob != null) && discoveryJob.isActive()) { discoveryJob.cancel(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { components.getDetectScannersButton().setEnabled(true); components.getCancelDetectScannersButton().setEnabled(false); components.getDetectScannersButton().requestFocus(); } }); } } private void cancelScan(ActionEvent e) { final ScannerListItem scannerListItem = components.getScannerList().getSelectedValue(); if (scannerListItem == null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { showMessageDialog(Localizer.localize("SelectAScannerMessage")); } }); return; } if (scannerListItem.isActive()) { scannerListItem.cancel(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateScannerListItem(scannerListItem, ScannerStatus.IDLE); } }); } } private void colorComboBoxActionPerformed(ItemEvent e) { if (getSelectedScannerListItem() == null) { return; } Scanner scanner = getSelectedScannerListItem().getScanner(); if (scanner == null) { return; } KnownSaneOptions .setColorMode(scanner, (String) components.getColorComboBox().getSelectedItem()); } private void customSettingsActionPerformed(ActionEvent e) { if (components.getScannerList().getSelectedIndex() < 0) { return; } ScannerListItem scannerListItem = components.getScannerList().getSelectedValue(); Scanner scanner = scannerListItem.getScanner(); CustomSettingsDialog customSettingsDialog = new CustomSettingsDialog( components.getRootComponent()); customSettingsDialog.setXstream(xstream); customSettingsDialog.setScanner(scanner); customSettingsDialog.setScanService(scanService); customSettingsDialog.initialize(); customSettingsDialog.setModal(true); customSettingsDialog.setVisible(true); if (customSettingsDialog.getDialogResult() == JOptionPane.OK_OPTION) { PreferencesUtils.update(scanner, customSettingsDialog.getScanner()); } } private void defaultThresholdCheckBoxStateChanged(ActionEvent e) { if (getSelectedScannerListItem() == null) { return; } Scanner scanner = getSelectedScannerListItem().getScanner(); if (scanner == null) { return; } boolean isUsingDefaultBlackThreshold = components.getDefaultThresholdCheckBox().isSelected(); KnownSaneOptions.setUsingDefaultBlackThreshold(scanner, isUsingDefaultBlackThreshold); components.getBlackThresholdSpinner().setEnabled(!isUsingDefaultBlackThreshold); } private void detectScanners() { discoveryJob = new DiscoveryJob(scanService); discoveryJob.setNotificaiton(this); discoveryListener = new DiscoveryListener() { @Override public void discoveryEventOccurred(final DiscoveryEvent devt) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { displayDevicesList(devt.getDiscoveredScanners()); discoveryJob.removeDiscoveryListener(discoveryListener); components.getDetectScannersButton().setEnabled(true); components.getCancelDetectScannersButton().setEnabled(false); components.getDetectScannersButton().requestFocus(); discoveryListener = null; discoveryJob = null; } }); } }; discoveryJob.addDiscoveryListener(discoveryListener); discoveryJob.discover(); } private void detectScanners(String hostAddress, int portNumber, String description) throws IOException, SaneException { discoveryJob = new DiscoveryJob(scanService); discoveryJob.setNotificaiton(this); discoveryListener = new DiscoveryListener() { @Override public void discoveryEventOccurred(final DiscoveryEvent devt) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { displayDevicesList(devt.getDiscoveredScanners()); discoveryJob.removeDiscoveryListener(discoveryListener); components.getDetectScannersButton().setEnabled(true); components.getCancelDetectScannersButton().setEnabled(false); components.getDetectScannersButton().requestFocus(); discoveryListener = null; discoveryJob = null; } }); } }; discoveryJob.addDiscoveryListener(discoveryListener); discoveryJob.discover(InetAddress.getByName(hostAddress), portNumber, description); } private void detectScannersActionPerformed(ActionEvent e) { if ((discoveryJob == null) || !(discoveryJob.isActive())) { detectScanners(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { components.getDetectScannersButton().setEnabled(false); components.getCancelDetectScannersButton().setEnabled(true); components.getCancelDetectScannersButton().requestFocus(); } }); } } private void disableScanButtons() { components.getScanProgressBar().setEnabled(false); components.getScanButton().setEnabled(false); components.getCancelScanButton().setEnabled(false); } private void disableSettingsComponents() { components.getSaveSettingsButton().setEnabled(false); components.getUseCustomSettingsCheckBox().setSelected(false); components.getUseCustomSettingsCheckBox().setEnabled(false); components.getCustomSettingsButton().setEnabled(false); updateResolutionModel(null, null); updatePageSizeModel(null, null); updateColorModeModel(null, null); updateDuplexCheckBox(false, false); updateAutoCropCheckBox(false, false); updateBatchScanCheckBox(false, false); updateBlackThresholdModel(null); updateUsingBlackThresholdCheckBox(false); updateSourceModel(null, null); updateBatchPrefix(null); updatePagesToScan(null); } /** * @param discoveredScanners * an {@link ArrayList} of {@link Scanner} */ private void displayDevicesList(final ArrayList<Scanner> discoveredScanners) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateScannerList(discoveredScanners); } }); } private void duplexScanningCheckBoxStateChanged(ActionEvent e) { if (getSelectedScannerListItem() == null) { return; } Scanner scanner = getSelectedScannerListItem().getScanner(); if (scanner == null) { return; } KnownSaneOptions.setDuplex(scanner, components.getDuplexScanningCheckBox().isSelected()); } private void editScannerActionPerformed(ActionEvent e) { if (components.getScannerList().getSelectedIndex() < 0) { return; } ScannerListItem scannerListItem = components.getScannerList().getSelectedValue(); Scanner scanner = scannerListItem.getScanner(); ScannerSettingsDialog scannerSettingsDialog = new ScannerSettingsDialog( components.getRootComponent()); scannerSettingsDialog.setTitle(Localizer.localize("EditScannerDialogTitle")); scannerSettingsDialog.setRemoteAddress(scanner.getRemoteAddress()); scannerSettingsDialog.setRemotePortNumber(new Integer(scanner.getRemotePortNumber())); scannerSettingsDialog.setDescription(scanner.getDescription()); scannerSettingsDialog.setModal(true); scannerSettingsDialog.setVisible(true); if (scannerSettingsDialog.getDialogResult() == JOptionPane.OK_OPTION) { scanner.setDescription(scannerSettingsDialog.getDescription()); scanner.setRemoteAddress(scannerSettingsDialog.getRemoteAddress()); scanner.setRemotePortNumber(scannerSettingsDialog.getPortNumber()); try { preferences.save(); } catch (IOException ex) { LOG.error(ex, ex); Misc.showSuccessMsg( components.getRootComponent(), String.format(Localizer.localize("ScannerSettingsNotSavedMessage"), ex.getLocalizedMessage())); } components.getScannerList().revalidate(); components.getScannerList().repaint(); } } private void enableScanButtons() { components.getScanButton().setEnabled(true); } public final IComponents getComponents() { return components; } @Override public final Exception getException() { return null; } public final ISwingSanePreferences getPreferences() { return preferences; } public final IPreferredDefaults getPreferredDefaults() { return preferredDefaults; } public final IScanEventHandler getScanEventHandler() { return scanEventHandler; } public final IScanService getScanService() { return scanService; } private ScannerListItem getSelectedScannerListItem() { final ScannerListItem scannerListItem = components.getScannerList().getSelectedValue(); if (scannerListItem == null) { return null; } return scannerListItem; } private String getTimeStamp() { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); String timeString = dateFormat.format(new Date().getTime()); return timeString; } public final XStream getXstream() { return xstream; } private void initComponentListeners() { JComboBox<String> sourceComboBox = components.getSourceComboBox(); sourceComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { sourceComboBoxActionPerformed(e); } }); JComboBox<Integer> resolutionComboBox = components.getResolutionComboBox(); resolutionComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { resolutionComboBoxActionPerformed(e); } }); JComboBox<String> colorComboBox = components.getColorComboBox(); colorComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { colorComboBoxActionPerformed(e); } }); JComboBox<String> pageSizeComboBox = components.getPageSizeComboBox(); pageSizeComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { pageSizeComboBoxActionPerformed(e); } }); JSpinner pagesToScanSpinner = components.getPagesToScanSpinner(); pagesToScanSpinner.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent evt) { pagesToScanSpinnerStateChanged(evt); } }); JSpinner blackThresholdSpinner = components.getBlackThresholdSpinner(); blackThresholdSpinner.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent evt) { blackThresholdSpinnerStateChanged(evt); } }); JCheckBox duplexScanningCheckBox = components.getDuplexScanningCheckBox(); duplexScanningCheckBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { duplexScanningCheckBoxStateChanged(e); } }); JCheckBox autoCropCheckBox = components.getAutoCropCheckBox(); autoCropCheckBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { autoCropCheckBoxStateChanged(e); } }); JCheckBox useADFCheckBox = components.getBatchScanCheckBox(); useADFCheckBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { useADFCheckBoxStateChanged(e); } }); JCheckBox defaultThresholdCheckBox = components.getDefaultThresholdCheckBox(); defaultThresholdCheckBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { defaultThresholdCheckBoxStateChanged(e); } }); JTextField batchNameTextField = components.getBatchNameTextField(); batchNameTextField.addCaretListener(new CaretListener() { @Override public void caretUpdate(CaretEvent e) { batchNameCaretUpdateActionPerformed(e); } }); JCheckBox useCustomSettingsCheckBox = components.getUseCustomSettingsCheckBox(); useCustomSettingsCheckBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { useCustomSettingsActionPerformed(e); } }); JButton customSettingsButton = components.getCustomSettingsButton(); customSettingsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { customSettingsActionPerformed(e); } }); JButton addScannerButton = components.getAddScannerButton(); addScannerButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { addScannerButtonActionPerformed(e); } }); JButton globalSettingsButton = components.getGlobalSettingsButton(); globalSettingsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { showGlobalSettingsDialog(); } }); JButton saveSettingsButton = components.getSaveSettingsButton(); saveSettingsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { saveSettingsButtonActionPerformed(e); } }); JButton editScannerButton = components.getEditScannerButton(); editScannerButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { editScannerActionPerformed(e); } }); JButton removeScannerButton = components.getRemoveScannerButton(); removeScannerButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { removeScannerButtonActionPerformed(e); } }); JButton scanButton = components.getScanButton(); scanButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { scanActionPerformed(e); } }); scanButton.setEnabled(false); JButton cancelScanButton = components.getCancelScanButton(); cancelScanButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { cancelScan(e); } }); cancelScanButton.setEnabled(false); JList<ScannerListItem> scannerList = components.getScannerList(); scannerList.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { scannerListSelectionChanged(e); } }); JButton detectScannersButton = components.getDetectScannersButton(); detectScannersButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { detectScannersActionPerformed(e); } }); detectScannersButton.setEnabled(true); JButton detectCancelButton = components.getCancelDetectScannersButton(); detectCancelButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { cancelDetection(e); } }); detectCancelButton.setEnabled(false); } public final boolean isAddScannerConfirmed(Scanner scanner) { return Misc.showConfirmDialog( components.getRootComponent(), Localizer.localize("ConfirmAddScannerTitle"), String.format(Localizer.localize("ConfirmAddScannerMessage"), scanner.getName(), scanner.getRemoteAddress() + ":" + scanner.getRemotePortNumber()), Localizer.localize("OK"), Localizer.localize("Cancel")); } public final boolean isBusy() { if (scannerListModel == null) { return false; } for (int i = 0; i < scannerListModel.getSize(); i++) { ScannerListItem scannerListItem = scannerListModel.getElementAt(i); ScanEventListener[] scanListeners = scannerListItem.getListeners(ScanEventListener.class); if ((scanListeners != null) && (scanListeners.length > 0)) { return true; } } return false; } @Override public final boolean isInterrupted() { return false; } private boolean isSameScanner(Scanner s1, Scanner s2) { if (s1.equals(s2)) { return true; } if (!(s1.getName().equals(s2.getName()))) { return false; } if (!(s1.getRemoteAddress().equals(s2.getRemoteAddress()))) { return false; } if (s1.getRemotePortNumber() != s2.getRemotePortNumber()) { return false; } return true; } @Override public final void message(final String message) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { addMessage(message); } }); } private void pageSizeComboBoxActionPerformed(ItemEvent e) { if (getSelectedScannerListItem() == null) { return; } Scanner scanner = getSelectedScannerListItem().getScanner(); if (scanner == null) { return; } KnownSaneOptions.setScanArea(scanner, (String) components.getPageSizeComboBox() .getSelectedItem()); } private void pagesToScanSpinnerStateChanged(ChangeEvent e) { if (getSelectedScannerListItem() == null) { return; } Scanner scanner = getSelectedScannerListItem().getScanner(); if (scanner == null) { return; } scanner.setPagesToScan((Integer) components.getPagesToScanSpinner().getValue()); } private String parseBatchPrefix(String batchPrefix) { return batchPrefix.replace(Localizer.localize("TimeStampToken"), getTimeStamp()); } private void removeScannerButtonActionPerformed(ActionEvent e) { ScannerListItem selectedScannerListItem = components.getScannerList().getSelectedValue(); if (selectedScannerListItem == null) { return; } ApplicationPreferences applicationPreferences = preferences.getApplicationPreferences(); ArrayList<Scanner> scannerList = applicationPreferences.getScannerList(); ArrayList<Scanner> removalList = new ArrayList<Scanner>(); if ((scannerList != null) && (scannerList.size() > 0)) { for (Scanner scanner : scannerList) { if (isSameScanner(scanner, selectedScannerListItem.getScanner())) { removalList.add(scanner); } } } for (Scanner scanner : removalList) { scannerList.remove(scanner); } scannerListModel.removeElement(selectedScannerListItem); disableSettingsComponents(); try { preferences.save(); } catch (IOException ex) { LOG.error(ex, ex); } } private void resolutionComboBoxActionPerformed(ItemEvent e) { if (getSelectedScannerListItem() == null) { return; } Scanner scanner = getSelectedScannerListItem().getScanner(); if (scanner == null) { return; } KnownSaneOptions.setResolution(scanner, (Integer) components.getResolutionComboBox() .getSelectedItem()); } private void restorePreferences() { ApplicationPreferences applicationPreferences = preferences.getApplicationPreferences(); ArrayList<Scanner> scannerList = applicationPreferences.getScannerList(); if ((scannerList != null) && (scannerList.size() > 0)) { for (Scanner scanner : scannerList) { restorePreferencesFromScanner(scanner); } } } private void restorePreferencesFromScanner(Scanner scanner) { final ScannerListItem scannerListItem = new ScannerListItem(scanner); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { scannerListModel.addElement(scannerListItem); components.getScannerList().revalidate(); components.getScannerList().repaint(); } }); } private void savePreferences(boolean showSaveNotification) { savePreferences(showSaveNotification, null); } private void savePreferences(boolean showSaveNotification, ScannerListItem currentScannerListItem) { ApplicationPreferences applicationPreferences = preferences.getApplicationPreferences(); ArrayList<Scanner> scannerList = applicationPreferences.getScannerList(); if (currentScannerListItem == null) { Enumeration<ScannerListItem> elements = scannerListModel.elements(); scannerList.clear(); while (elements.hasMoreElements()) { ScannerListItem currentItem = elements.nextElement(); scannerList.add(currentItem.getScanner()); } } else { boolean updated = false; for (int i = 0; i < scannerList.size(); i++) { if (scannerList.get(i).getGuid().equals(currentScannerListItem.getScanner().getGuid())) { scannerList.set(i, currentScannerListItem.getScanner()); updated = true; } } if (!updated) { scannerList.add(currentScannerListItem.getScanner()); } } try { preferences.save(); if (showSaveNotification) { Misc.showSuccessMsg(components.getRootComponent(), Localizer.localize("ScannerSettingsSavedSuccessfullyMessage")); } } catch (IOException ex) { LOG.error(ex, ex); Misc.showSuccessMsg( components.getRootComponent(), String.format(Localizer.localize("ScannerSettingsNotSavedMessage"), ex.getLocalizedMessage())); } } private void saveSettingsButtonActionPerformed(ActionEvent e) { ScannerListItem currentScannerListItem = components.getScannerList().getSelectedValue(); savePreferences(true, currentScannerListItem); } private void scanActionPerformed(ActionEvent e) { final ScannerListItem scannerListItem = getSelectedScannerListItem(); if (scannerListItem == null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { showMessageDialog(Localizer.localize("SelectAScannerMessage")); } }); return; } if (!(scannerListItem.isActive())) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateScannerListItem(scannerListItem, ScannerStatus.BUSY); } }); ScanEventListener scanEventListener = new ScanEventListener() { @Override public void eventOccurred(final ScanEvent sevt) { if (sevt.getBufferedImage() == null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateScannerListItem(scannerListItem, ScannerStatus.IDLE); } }); scannerListItem.removeListeners(); return; } scanEventHandler.scanPerformed(sevt); } }; int pagesToScan = Integer.MAX_VALUE; if (components.getPagesToScanSpinner().isEnabled()) { pagesToScan = (Integer) components.getPagesToScanSpinner().getValue(); if (components.getDuplexScanningCheckBox().isSelected()) { pagesToScan *= 2; } } ScanListenerAdapter progressBarUpdater = new ScanListenerAdapter() { @Override public void recordRead(SaneDevice device, final int totalBytesRead, final int imageSize) { final double fraction = (1.0d * totalBytesRead) / imageSize; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (components.getScannerList().getSelectedValue() == scannerListItem) { if (components.getScanProgressBar().isIndeterminate()) { components.getScanProgressBar().setIndeterminate(false); } components.getScanProgressBar().setEnabled(true); components.getScanProgressBar().setValue((int) (fraction * 100)); } } }); } @Override public void scanningFinished(SaneDevice device) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (components.getScannerList().getSelectedValue() == scannerListItem) { components.getScanProgressBar().setValue(0); } } }); } }; ScanListener rateLimitedScanListener = RateLimitingScanListeners.noMoreFrequentlyThan( progressBarUpdater, PROGRESS_BAR_UPDATE_INTERVAL, TimeUnit.MILLISECONDS); ScanJob scanJob = new ScanJob(scanService, scannerListItem.getScanner()); scannerListItem.setScanEventListener(scanEventListener); scannerListItem.setScanJob(scanJob); scanJob.setPagesToScan(pagesToScan); scanJob.setUseADF(components.getBatchScanCheckBox().isSelected()); scanJob.setBatchPrefix(parseBatchPrefix(scannerListItem.getScanner().getBatchPrefix())); scanJob.setNotificaiton(this); scanJob.addScanListener(scanEventListener); scanJob.acquire(rateLimitedScanListener); } } private void scannerListSelectionChanged(ListSelectionEvent e) { if (!(e.getValueIsAdjusting())) { return; } @SuppressWarnings("unchecked") JList<ScannerListItem> scannerList = (JList<ScannerListItem>) e.getSource(); if (scannerList.getSelectedIndex() < 0) { disableSettingsComponents(); disableScanButtons(); return; } disableSettingsComponents(); ScannerListItem scannerListItem = scannerList.getSelectedValue(); Scanner scanner = scannerListItem.getScanner(); adjustSettingsComponents(scanner); enableScanButtons(); updateComponents(scannerListItem); } private void selectPreferredDefaults(Scanner scanner) { preferredDefaults.update(scanner); } public final void setComponents(IComponents components) { this.components = components; this.components.getScannerList().setModel(scannerListModel); initComponentListeners(); restorePreferences(); } @Override public void setException(Exception exception) { } @Override public void setInterrupted(boolean interrupted) { } public final void setPreferences(ISwingSanePreferences preferences) { this.preferences = preferences; } public final void setPreferredDefaults(IPreferredDefaults preferredDefaults) { this.preferredDefaults = preferredDefaults; } public final void setScanEventHandler(IScanEventHandler scanEventHandler) { this.scanEventHandler = scanEventHandler; } private void setScannerBusy(boolean scannerBusy) { if (scannerBusy) { components.getScanProgressBar().setIndeterminate(true); components.getScanProgressBar().setEnabled(true); components.getScanButton().setEnabled(false); components.getCancelScanButton().setEnabled(true); components.getCancelScanButton().requestFocus(); } else { components.getScanProgressBar().setIndeterminate(false); components.getScanProgressBar().setValue(0); components.getScanProgressBar().setEnabled(false); components.getScanButton().setEnabled(true); components.getCancelScanButton().setEnabled(false); components.getScanButton().requestFocus(); } } public final void setScanService(IScanService scanServiceImpl) { scanService = scanServiceImpl; } public final void setXstream(XStream xstream) { this.xstream = xstream; } private void showGlobalSettingsDialog() { HashMap<String, Login> saneLogins = PreferencesUtils.copy(preferences .getApplicationPreferences().getSaneLogins()); String saneServiceName = preferences.getApplicationPreferences().getSaneServiceIdentity() .getServiceName(); GlobalSettingsDialog globalSettingsDialog = new GlobalSettingsDialog( components.getRootComponent()); globalSettingsDialog.setLogins(saneLogins); globalSettingsDialog.setSaneServiceName(saneServiceName); globalSettingsDialog.initialize(); globalSettingsDialog.setModal(true); globalSettingsDialog.setVisible(true); if (globalSettingsDialog.getDialogResult() == JOptionPane.OK_OPTION) { try { preferences.getApplicationPreferences().getSaneServiceIdentity() .setServiceName(globalSettingsDialog.getServiceName().trim()); PreferencesUtils.update(preferences.getApplicationPreferences().getSaneLogins(), globalSettingsDialog.getSaneLogins()); preferences.save(); } catch (IOException e) { LOG.error(e, e); } } } private void showMessageDialog(final String message) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JOptionPane.showMessageDialog(components.getRootComponent(), message); } }); } private void sourceComboBoxActionPerformed(ItemEvent e) { if (getSelectedScannerListItem() == null) { return; } Scanner scanner = getSelectedScannerListItem().getScanner(); if (scanner == null) { return; } KnownSaneOptions.setSource(scanner, (String) components.getSourceComboBox().getSelectedItem()); } private void updateAutoCropCheckBox(boolean enabled, boolean selected) { JCheckBox autoCropCheckBox = components.getAutoCropCheckBox(); autoCropCheckBox.setEnabled(enabled); autoCropCheckBox.setSelected(selected); } private void updateBatchPrefix(final String batchPrefix) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JTextField batchNameTextField = components.getBatchNameTextField(); if (batchPrefix == null) { batchNameTextField.setEnabled(false); } else { batchNameTextField.setEnabled(true); } batchNameTextField.setText(batchPrefix); } }); } private void updateBatchScanCheckBox(boolean enabled, boolean selected) { JCheckBox batchScanCheckBox = components.getBatchScanCheckBox(); batchScanCheckBox.setEnabled(enabled); batchScanCheckBox.setSelected(selected); if (enabled && selected) { components.getPagesToScanSpinner().setEnabled(false); } else { components.getPagesToScanSpinner().setEnabled(true); } } private void updateBlackThresholdModel(SpinnerModel blackThresholdSpinnerModel) { JSpinner blackThresholdSpinner = components.getBlackThresholdSpinner(); blackThresholdSpinner.setModel(blackThresholdSpinnerModel != null ? blackThresholdSpinnerModel : new SpinnerNumberModel(1, 1, null, 1)); blackThresholdSpinner.setEnabled(blackThresholdSpinnerModel != null ? !(components .getDefaultThresholdCheckBox().isSelected()) : false); } private void updateColorModeModel(ComboBoxModel<String> colorModeModel, String colorMode) { JComboBox<String> colorComboBox = components.getColorComboBox(); colorComboBox.setModel(colorModeModel != null ? colorModeModel : new DefaultComboBoxModel<String>()); colorComboBox.setEnabled(colorModeModel != null ? true : false); if (colorModeModel != null) { colorComboBox.setSelectedItem(colorMode); } } private void updateComponents(final ScannerListItem scannerListItem) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (components.getScannerList().getSelectedValue() == scannerListItem) { if (scannerListItem.getScannerStatus() == ScannerStatus.BUSY) { setScannerBusy(true); } else if (scannerListItem.getScannerStatus() == ScannerStatus.IDLE) { setScannerBusy(false); } } components.getScannerList().revalidate(); components.getScannerList().repaint(); } }); } private void updateDuplexCheckBox(boolean enabled, boolean selected) { JCheckBox duplexCheckBox = components.getDuplexScanningCheckBox(); duplexCheckBox.setEnabled(enabled); duplexCheckBox.setSelected(selected); } private void updatePageSizeModel(ComboBoxModel<String> pageSizeModel, String pageSize) { JComboBox<String> pageSizeComboBox = components.getPageSizeComboBox(); pageSizeComboBox.setModel(pageSizeModel != null ? pageSizeModel : new DefaultComboBoxModel<String>()); pageSizeComboBox.setEnabled(pageSizeModel != null ? true : false); if (pageSizeModel != null) { pageSizeComboBox.setSelectedItem(pageSize); } } private void updatePagesToScan(Integer pagesToScan) { JSpinner pagesToScanSpinner = components.getPagesToScanSpinner(); if (pagesToScan == null) { pagesToScanSpinner.setEnabled(false); } else { pagesToScanSpinner.setEnabled(!(components.getBatchScanCheckBox().isSelected())); pagesToScanSpinner.setValue(pagesToScan); } } private void updateResolutionModel(ComboBoxModel<Integer> resolutionModel, Integer resolution) { JComboBox<Integer> resolutionComboBox = components.getResolutionComboBox(); resolutionComboBox.setModel(resolutionModel != null ? resolutionModel : new DefaultComboBoxModel<Integer>()); resolutionComboBox.setEnabled(resolutionModel != null ? true : false); if (resolutionModel != null) { resolutionComboBox.setSelectedItem(resolution); } } private void updateScannerList(ArrayList<Scanner> discoveredScanners) { if (discoveredScanners == null) { return; } for (Scanner scanner : discoveredScanners) { if (isAddScannerConfirmed(scanner)) { selectPreferredDefaults(scanner); scannerListModel.addElement(new ScannerListItem(scanner)); } } components.getScannerList().setModel(scannerListModel); savePreferences(false); } private void updateScannerListItem(ScannerListItem scannerListItem, ScannerStatus scannerStatus) { scannerListItem.setScannerStatus(scannerStatus); updateComponents(scannerListItem); } private void updateSourceModel(ComboBoxModel<String> sourceModel, String source) { JComboBox<String> sourceComboBox = components.getSourceComboBox(); sourceComboBox.setModel(sourceModel != null ? sourceModel : new DefaultComboBoxModel<String>()); sourceComboBox.setEnabled(sourceModel != null ? true : false); if (source != null) { sourceComboBox.setSelectedItem(source); } } private void updateUsingBlackThresholdCheckBox(boolean usingDefaultBlackThreshold) { JCheckBox useDefaultBlackThreshold = components.getDefaultThresholdCheckBox(); useDefaultBlackThreshold.setSelected(usingDefaultBlackThreshold); } private void useADFCheckBoxStateChanged(ActionEvent e) { if (getSelectedScannerListItem() == null) { return; } Scanner scanner = getSelectedScannerListItem().getScanner(); if (scanner == null) { return; } boolean isBatchScanSelected = components.getBatchScanCheckBox().isSelected(); KnownSaneOptions.setBatchScan(scanner, isBatchScanSelected); components.getPagesToScanSpinner().setEnabled(!isBatchScanSelected); } private void useCustomSettingsActionPerformed(ActionEvent e) { if (components.getUseCustomSettingsCheckBox().isSelected()) { components.getCustomSettingsButton().setEnabled(true); updateResolutionModel(null, null); updatePageSizeModel(null, null); updateColorModeModel(null, null); updateDuplexCheckBox(false, false); updateAutoCropCheckBox(false, false); updateBlackThresholdModel(null); updateUsingBlackThresholdCheckBox(false); updateSourceModel(null, null); if (components.getScannerList().getSelectedIndex() >= 0) { ScannerListItem scannerListItem = components.getScannerList().getSelectedValue(); Scanner scanner = scannerListItem.getScanner(); scanner.setUsingCustomOptions(true); } } else { if (components.getScannerList().getSelectedIndex() < 0) { disableSettingsComponents(); return; } ScannerListItem scannerListItem = components.getScannerList().getSelectedValue(); Scanner scanner = scannerListItem.getScanner(); scanner.setUsingCustomOptions(false); adjustSettingsComponents(scanner); } } }