Java tutorial
/** * 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.components; import java.awt.Window; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutionException; import javax.swing.JOptionPane; import javax.swing.ProgressMonitor; import javax.swing.SwingWorker; import org.apache.commons.lang.exception.ExceptionUtils; import richtercloud.reflection.form.builder.message.Message; import richtercloud.reflection.form.builder.message.MessageHandler; /** * * @author richter */ public class OCRResultPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private OCRResultPanelFetcher oCRResultPanelFetcher; private final Set<OCRResultPanelUpdateListener> updateListeners = new HashSet<>(); /** * Whether the OCR recognition process can be canceled with a dialog control * (modal dialog is displayed while the process is in progress) */ private boolean cancelable = true; private final MessageHandler messageHandler; private final String initialValue; private ProgressMonitor progressMonitor; private final Window oCRProgressMonitorParent; public OCRResultPanel(OCRResultPanelFetcher retriever, String initialValue, MessageHandler messageHandler, boolean autoSaveOCRData, Window oCRProgressMonitorParent) { this(retriever, initialValue, true, messageHandler, autoSaveOCRData, oCRProgressMonitorParent); } /** * Creates a new {@code OCRResultPanel}. * * @param retriever * @param initialValue * @param cancelable * @param messageHandler */ /* internal implementation notes: - It doesn't make sense to call start in constructor because a dialog needs to be displayed (at least if the OCR recognition is cancelable) which results in weird appearance if the OCRResultPanel isn't added to a parent. */ public OCRResultPanel(OCRResultPanelFetcher retriever, String initialValue, boolean cancelable, MessageHandler messageHandler, boolean autoSaveOCRData, Window oCRProgressMonitorParent) { this.initComponents(); this.oCRResultPanelFetcher = retriever; this.oCRResultTextArea.setText(initialValue); this.cancelable = cancelable; this.initialValue = initialValue; this.messageHandler = messageHandler; this.oCRProgressMonitorParent = oCRProgressMonitorParent; reset0(); if (autoSaveOCRData) { startOCR(); } } public String retrieveText() { return oCRResultTextArea.getText(); } public void addUpdateListener(OCRResultPanelUpdateListener updateListener) { this.updateListeners.add(updateListener); } public void removeUpdateListener(OCRResultPanelUpdateListener updateListener) { this.updateListeners.remove(updateListener); } public boolean isCancelable() { return cancelable; } private void reset0() { if (this.initialValue != null) { this.oCRResultTextArea.setText(initialValue); } else { this.oCRResultTextArea.setText(""); } } public void reset() { reset0(); } /** * 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() { oCRResultButton = new javax.swing.JButton(); oCRResultTextAreaScrollPane = new javax.swing.JScrollPane(); oCRResultTextArea = new javax.swing.JTextArea(); oCRResultButton.setText("OCR recognition"); oCRResultButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { oCRResultButtonActionPerformed(evt); } }); oCRResultTextArea.setColumns(20); oCRResultTextArea.setRows(5); oCRResultTextAreaScrollPane.setViewportView(oCRResultTextArea); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup( layout.createSequentialGroup().addContainerGap() .addGroup(layout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(oCRResultTextAreaScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 414, Short.MAX_VALUE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup().addGap(0, 0, Short.MAX_VALUE) .addComponent(oCRResultButton))) .addContainerGap())); layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup().addContainerGap() .addComponent(oCRResultTextAreaScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 282, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(oCRResultButton).addContainerGap())); }// </editor-fold>//GEN-END:initComponents /** * * @return the returning dialog @TODO: document need for it */ private void showProgressMonitor() { assert oCRProgressMonitorParent != null; progressMonitor = new ProgressMonitor(oCRProgressMonitorParent, //parent "OCR recognition in progress", //message null, //note 0, //min 100 //max ); progressMonitor.setMillisToPopup(0); progressMonitor.setMillisToDecideToPopup(0); } /* internal implementation notes: - There's no sense in checking whether OCR has been canceled with something different from the ProgressMonitor because it can only be canceled with the dialog, but a check for null has to be added. */ private void startOCR() { String oCRResult = null; if (!cancelable) { oCRResult = this.oCRResultPanelFetcher.fetch(); } else { showProgressMonitor(); final SwingWorker<String, String> oCRThread = new SwingWorker<String, String>() { private final OCRResultPanelFetcherProgressListener progressListener = new OCRResultPanelFetcherProgressListener() { @Override public void onProgressUpdate(OCRResultPanelFetcherProgressEvent progressEvent) { int progress = (int) (progressEvent.getProgress() * 100); if (progressMonitor != null) { //might be null if the panel isn't displayed yet progressMonitor.setProgress(progress); } } }; @Override public String doInBackground() { oCRResultPanelFetcher.addProgressListener(progressListener); try { Thread thread1 = new Thread() { @Override public void run() { while (!isDone()) { if (progressMonitor != null && progressMonitor.isCanceled()) { oCRResultPanelFetcher.cancelFetch(); break; } try { Thread.sleep(100); } catch (InterruptedException ex) { throw new RuntimeException(ex); } } } }; thread1.start(); String retValue = oCRResultPanelFetcher.fetch(); return retValue; } catch (Exception ex) { progressMonitor.setProgress(101); messageHandler.handle(new Message( String.format("An exception during fetching OCR result occured: %s", ExceptionUtils.getRootCauseMessage(ex)), JOptionPane.ERROR_MESSAGE, "Exception occured")); } return null; } @Override protected void done() { oCRResultPanelFetcher.removeProgressListener(progressListener); progressMonitor.setProgress(101); } }; oCRThread.execute(); try { oCRResult = oCRThread.get(); } catch (InterruptedException | ExecutionException ex) { throw new RuntimeException(ex); } } if (oCRResult != null) { //might be null if fetch has been canceled (this check is //unnecessary for non-cancelable processing, but don't care this.oCRResultTextArea.setText(oCRResult); } } private void oCRResultButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_oCRResultButtonActionPerformed startOCR(); }//GEN-LAST:event_oCRResultButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton oCRResultButton; private javax.swing.JTextArea oCRResultTextArea; private javax.swing.JScrollPane oCRResultTextAreaScrollPane; // End of variables declaration//GEN-END:variables }