OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 142 | Rev 156 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
18 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.erp.core.sales.pos.io;
15
 
16
import org.openconcerto.erp.core.sales.pos.ui.BarcodeListener;
83 ilm 17
import org.openconcerto.ui.DefaultGridBagConstraints;
18
import org.openconcerto.ui.component.ITextArea;
18 ilm 19
 
83 ilm 20
import java.awt.Dimension;
21
import java.awt.GridBagConstraints;
22
import java.awt.GridBagLayout;
18 ilm 23
import java.awt.KeyEventDispatcher;
24
import java.awt.KeyboardFocusManager;
25
import java.awt.event.KeyEvent;
26
import java.util.ArrayList;
27
import java.util.List;
28
import java.util.Timer;
29
import java.util.TimerTask;
30
 
83 ilm 31
import javax.swing.JFrame;
32
import javax.swing.JLabel;
33
import javax.swing.JPanel;
34
import javax.swing.JScrollPane;
18 ilm 35
import javax.swing.SwingUtilities;
83 ilm 36
import javax.swing.UIManager;
18 ilm 37
 
38
/**
39
 * Lecteur code barres, intercepte les événements clavier pour détecter un scan de code. Le code
40
 * barre doit terminer par un retour à la ligne.
142 ilm 41
 */
18 ilm 42
public class BarcodeReader implements KeyEventDispatcher {
43
 
83 ilm 44
    public int maxInterKeyDelay = 80;
18 ilm 45
    private static final int MIN_BARCODE_LENGTH = 2;
46
    private final List<BarcodeListener> listeners = new ArrayList<BarcodeListener>(1);
47
    private String value = "";
48
    private final List<KeyEvent> eve = new ArrayList<KeyEvent>();
49
    private long firstTime = -1;
50
    private Timer timer;
51
    // non final car un TimerTask n'est pas reutilisable
52
    private TimerTask task;
142 ilm 53
    private boolean enable = true;
18 ilm 54
 
83 ilm 55
    public BarcodeReader(int maxInterKeyDelay) {
18 ilm 56
        this.timer = null;
57
        this.task = null;
83 ilm 58
        this.maxInterKeyDelay = maxInterKeyDelay;
18 ilm 59
    }
60
 
61
    public synchronized void removeBarcodeListener(BarcodeListener l) {
62
        this.listeners.remove(l);
144 ilm 63
        if (this.listeners.isEmpty()) {
18 ilm 64
            stop();
65
        }
66
    }
67
 
68
    public synchronized void addBarcodeListener(final BarcodeListener l) {
144 ilm 69
        if (this.timer == null) {
70
            start();
71
        }
18 ilm 72
        this.listeners.add(l);
73
    }
74
 
75
    private void fire(String code) {
76
        for (int i = 0; i < this.listeners.size(); i++) {
77
            this.listeners.get(i).barcodeRead(code);
78
        }
79
    }
80
 
81
    /**
82
     * Commence à ecouter les évenements clavier pour intercepter les codes barres
142 ilm 83
     */
18 ilm 84
 
142 ilm 85
    public synchronized void start() {
86
        if (this.timer == null) {
87
            // init avant que les listeners s'en servent
88
            this.timer = new Timer(getClass().getName(), true);
89
            KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
144 ilm 90
            System.err.println("BarcodeReader start : scan delay " + maxInterKeyDelay + " ms");
142 ilm 91
        }
18 ilm 92
    }
93
 
94
    /**
95
     * Stoppe l'écoute sur les évenements clavier
142 ilm 96
     */
97
    public synchronized void stop() {
18 ilm 98
        if (this.timer != null) {
144 ilm 99
            System.err.println("BarcodeReader stop");
18 ilm 100
            this.timer.cancel();
93 ilm 101
            this.timer = null;
142 ilm 102
            KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
18 ilm 103
        }
104
    }
105
 
106
    @Override
107
    public boolean dispatchKeyEvent(KeyEvent e) {
142 ilm 108
        if (!enable)
109
            return false;
110
 
18 ilm 111
        if (this.task != null)
112
            this.task.cancel();
113
 
114
        final long t = e.getWhen();
115
        if (this.firstTime < 0) {
116
            this.firstTime = t;
117
        }
118
        int key = e.getKeyCode();
119
 
142 ilm 120
        final long delay = t - this.firstTime;
121
        if (key == KeyEvent.VK_BACK_SPACE || key == KeyEvent.VK_DELETE || (delay > maxInterKeyDelay && key != KeyEvent.VK_SHIFT)) {
18 ilm 122
            // touche normale
142 ilm 123
            this.eve.add(e);
18 ilm 124
            redispatch();
142 ilm 125
            return true;
18 ilm 126
        }
127
 
128
        final char key2 = e.getKeyChar();
129
        this.eve.add(e);
142 ilm 130
        if (e.getID() == KeyEvent.KEY_RELEASED) {
18 ilm 131
            if (key == KeyEvent.VK_SHIFT) {
132
                // rien
133
            } else if (key2 == '*' || key2 == '$' || key2 == '+' || key2 == '/' || key2 == '%' || key2 == '-' | key2 == ' ') {
134
                this.value += key2;
142 ilm 135
            } else if (Character.isLetter(key2) || Character.isDigit(key2)) {
136
                this.value += key2;
18 ilm 137
            } else if (key >= KeyEvent.VK_0 && key <= KeyEvent.VK_9 || key >= KeyEvent.VK_A && key <= KeyEvent.VK_Z) {
138
                // from KeyEvent : same as ASCII
139
                this.value += (char) key;
140
            } else if (key == KeyEvent.VK_ENTER && this.value.length() >= MIN_BARCODE_LENGTH) {
141
                // fin de code barre
142
                this.value = this.value.trim();
143
                fire(this.value);
144
                reset();
145
            } else {
146
                // Caractere non code barre
147
                redispatch();
148
            }
149
            // lance un timer s'il reste des evenements non dispatchés
144 ilm 150
            if (!this.eve.isEmpty()) {
18 ilm 151
                this.firstTime = t;
152
                this.task = new TimerTask() {
153
                    @Override
154
                    public void run() {
155
                        redispatchLater();
156
                    }
157
                };
83 ilm 158
                this.timer.schedule(this.task, maxInterKeyDelay);
18 ilm 159
            }
160
            // si pas d'evenement, pas de temps associé
144 ilm 161
            assert !this.eve.isEmpty() || this.firstTime == -1;
18 ilm 162
        }
163
        return true;
164
    }
165
 
166
    private void redispatchLater() {
167
        SwingUtilities.invokeLater(new Runnable() {
168
            @Override
169
            public void run() {
170
                redispatch();
171
            }
172
        });
173
    }
174
 
175
    private void redispatch() {
176
        for (int i = 0; i < this.eve.size(); i++) {
177
            final KeyEvent ee = this.eve.get(i);
178
            KeyboardFocusManager.getCurrentKeyboardFocusManager().redispatchEvent(ee.getComponent(), ee);
179
            for (int j = 0; j < this.listeners.size(); j++) {
180
                this.listeners.get(j).keyReceived(ee);
181
            }
182
        }
183
        reset();
184
    }
185
 
186
    private void reset() {
187
        this.value = "";
188
        this.eve.clear();
189
        this.firstTime = -1;
190
    }
191
 
83 ilm 192
    public static void main(String[] args) {
193
        String delay = "80";
194
        if (args.length > 0) {
195
            delay = args[0];
196
        }
197
        final int d = Integer.parseInt(delay);
198
        SwingUtilities.invokeLater(new Runnable() {
199
 
200
            @Override
201
            public void run() {
202
                try {
203
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
204
                } catch (Exception e) {
205
                    e.printStackTrace();
206
                }
207
                System.out.println("BarCode reader");
208
                System.out.println("Using inter key delay: " + d);
209
                JFrame f = new JFrame();
210
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
211
                JPanel panel = new JPanel();
212
                f.setTitle("Barcode reader test");
213
                f.setContentPane(panel);
214
                panel.setLayout(new GridBagLayout());
215
                GridBagConstraints c = new DefaultGridBagConstraints();
216
                final JLabel l = new JLabel("BarCode reader output :");
217
                panel.add(l, c);
218
                c.gridy++;
219
                c.weighty = 1;
220
                c.weightx = 1;
221
                c.fill = GridBagConstraints.BOTH;
222
                final ITextArea t1 = new ITextArea();
223
                panel.add(new JScrollPane(t1), c);
224
 
225
                BarcodeReader reader = new BarcodeReader(d);
226
                reader.addBarcodeListener(new BarcodeListener() {
227
 
228
                    @Override
229
                    public void keyReceived(KeyEvent ee) {
230
                        System.err.println("BarcodeReader keyReceived() : " + ee);
231
                    }
232
 
233
                    @Override
234
                    public void barcodeRead(String code) {
235
                        t1.append("Barcode OK : '" + code + "'\n");
236
                    }
237
                });
238
 
239
                f.setSize(new Dimension(640, 480));
240
                f.setLocationRelativeTo(null);
241
                f.setVisible(true);
242
 
243
            }
244
        });
245
 
246
    }
142 ilm 247
 
248
    public void setEnabled(boolean b) {
249
        this.enable = b;
250
    }
18 ilm 251
}