OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 144 | Rev 180 | 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;
156 ilm 27
import java.util.HashMap;
18 ilm 28
import java.util.List;
156 ilm 29
import java.util.Map;
30
import java.util.Map.Entry;
18 ilm 31
import java.util.Timer;
32
import java.util.TimerTask;
33
 
83 ilm 34
import javax.swing.JFrame;
35
import javax.swing.JLabel;
36
import javax.swing.JPanel;
37
import javax.swing.JScrollPane;
18 ilm 38
import javax.swing.SwingUtilities;
83 ilm 39
import javax.swing.UIManager;
18 ilm 40
 
41
/**
42
 * Lecteur code barres, intercepte les événements clavier pour détecter un scan de code. Le code
43
 * barre doit terminer par un retour à la ligne.
142 ilm 44
 */
18 ilm 45
public class BarcodeReader implements KeyEventDispatcher {
46
 
83 ilm 47
    public int maxInterKeyDelay = 80;
18 ilm 48
    private static final int MIN_BARCODE_LENGTH = 2;
49
    private final List<BarcodeListener> listeners = new ArrayList<BarcodeListener>(1);
50
    private String value = "";
51
    private final List<KeyEvent> eve = new ArrayList<KeyEvent>();
52
    private long firstTime = -1;
53
    private Timer timer;
54
    // non final car un TimerTask n'est pas reutilisable
55
    private TimerTask task;
142 ilm 56
    private boolean enable = true;
156 ilm 57
    private boolean debug = false;
58
    Map<Integer, String> mapCharacterFR = new HashMap<>();
18 ilm 59
 
83 ilm 60
    public BarcodeReader(int maxInterKeyDelay) {
18 ilm 61
        this.timer = null;
62
        this.task = null;
83 ilm 63
        this.maxInterKeyDelay = maxInterKeyDelay;
156 ilm 64
        mapCharacterFR.put((int) '&', "1");
65
        mapCharacterFR.put((int) 'é', "2");
66
        mapCharacterFR.put((int) '"', "3");
67
        mapCharacterFR.put((int) '\'', "4");
68
        mapCharacterFR.put((int) '(', "5");
69
        mapCharacterFR.put((int) '-', "6");
70
        mapCharacterFR.put((int) 'è', "7");
71
        mapCharacterFR.put((int) '_', "8");
72
        mapCharacterFR.put((int) 'ç', "9");
73
        mapCharacterFR.put((int) 'à', "0");
18 ilm 74
    }
75
 
76
    public synchronized void removeBarcodeListener(BarcodeListener l) {
77
        this.listeners.remove(l);
144 ilm 78
        if (this.listeners.isEmpty()) {
18 ilm 79
            stop();
80
        }
81
    }
82
 
83
    public synchronized void addBarcodeListener(final BarcodeListener l) {
144 ilm 84
        if (this.timer == null) {
85
            start();
86
        }
18 ilm 87
        this.listeners.add(l);
88
    }
89
 
90
    private void fire(String code) {
91
        for (int i = 0; i < this.listeners.size(); i++) {
92
            this.listeners.get(i).barcodeRead(code);
93
        }
94
    }
95
 
96
    /**
97
     * Commence à ecouter les évenements clavier pour intercepter les codes barres
142 ilm 98
     */
18 ilm 99
 
142 ilm 100
    public synchronized void start() {
101
        if (this.timer == null) {
102
            // init avant que les listeners s'en servent
103
            this.timer = new Timer(getClass().getName(), true);
104
            KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
144 ilm 105
            System.err.println("BarcodeReader start : scan delay " + maxInterKeyDelay + " ms");
142 ilm 106
        }
18 ilm 107
    }
108
 
109
    /**
110
     * Stoppe l'écoute sur les évenements clavier
142 ilm 111
     */
112
    public synchronized void stop() {
18 ilm 113
        if (this.timer != null) {
144 ilm 114
            System.err.println("BarcodeReader stop");
18 ilm 115
            this.timer.cancel();
93 ilm 116
            this.timer = null;
142 ilm 117
            KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
18 ilm 118
        }
119
    }
120
 
121
    @Override
122
    public boolean dispatchKeyEvent(KeyEvent e) {
142 ilm 123
        if (!enable)
124
            return false;
125
 
18 ilm 126
        if (this.task != null)
127
            this.task.cancel();
128
 
129
        final long t = e.getWhen();
130
        if (this.firstTime < 0) {
131
            this.firstTime = t;
132
        }
156 ilm 133
        int keyCode = e.getKeyCode();
18 ilm 134
 
142 ilm 135
        final long delay = t - this.firstTime;
156 ilm 136
        if (keyCode == KeyEvent.VK_BACK_SPACE || keyCode == KeyEvent.VK_DELETE || (delay > maxInterKeyDelay && keyCode != KeyEvent.VK_SHIFT)) {
18 ilm 137
            // touche normale
156 ilm 138
            if (this.debug) {
139
                System.err.println("TOuche normale " + keyCode);
140
            }
142 ilm 141
            this.eve.add(e);
18 ilm 142
            redispatch();
142 ilm 143
            return true;
18 ilm 144
        }
145
 
156 ilm 146
        final char keyChar = e.getKeyChar();
18 ilm 147
        this.eve.add(e);
142 ilm 148
        if (e.getID() == KeyEvent.KEY_RELEASED) {
156 ilm 149
            if (keyCode == KeyEvent.VK_SHIFT) {
18 ilm 150
                // rien
156 ilm 151
                if (this.debug) {
152
                    System.err.println("SHIFT " + keyCode);
153
                }
154
            } else if (keyChar == '*' || keyChar == '$' || keyChar == '+' || keyChar == '/' || keyChar == '%' || keyChar == ' ') {
155
                this.value += keyChar;
156
                if (this.debug) {
157
                    System.err.println("KEY " + keyCode + " - " + keyChar);
158
                }
159
            } else if (keyCode >= KeyEvent.VK_0 && keyCode <= KeyEvent.VK_9 || keyCode >= KeyEvent.VK_A && keyCode <= KeyEvent.VK_Z) {
18 ilm 160
                // from KeyEvent : same as ASCII
156 ilm 161
                if (this.debug) {
162
                    System.err.println("[0-9] [A-Z] " + keyCode);
163
                }
164
                this.value += (char) keyCode;
165
            } else if (keyCode == KeyEvent.VK_ENTER && this.value.length() >= MIN_BARCODE_LENGTH) {
18 ilm 166
                // fin de code barre
156 ilm 167
                if (this.debug) {
168
                    System.err.println("BARCODE OK ENTER OR LENGHT " + keyCode + " length = " + this.value.length() + " min length =" + MIN_BARCODE_LENGTH);
169
                }
18 ilm 170
                this.value = this.value.trim();
171
                fire(this.value);
172
                reset();
156 ilm 173
            } else if (mapCharacterFR.containsKey((int) keyChar)) {
174
                if (this.debug) {
175
                    System.err.println("MAP DEFAULT FR CHAR " + keyChar + " WITH " + mapCharacterFR.get((int) keyChar));
176
                }
177
                this.value += mapCharacterFR.get((int) keyChar);
178
            } else if (Character.isLetter(keyChar) || Character.isDigit(keyChar)) {
179
                this.value += keyChar;
180
                if (this.debug) {
181
                    System.err.println("LETTER OR DIGIT " + keyChar);
182
                }
18 ilm 183
            } else {
184
                // Caractere non code barre
156 ilm 185
                if (this.debug) {
186
                    System.err.println("CHAR NON CODE BARRE " + e);
187
                }
18 ilm 188
                redispatch();
189
            }
190
            // lance un timer s'il reste des evenements non dispatchés
144 ilm 191
            if (!this.eve.isEmpty()) {
18 ilm 192
                this.firstTime = t;
193
                this.task = new TimerTask() {
194
                    @Override
195
                    public void run() {
196
                        redispatchLater();
197
                    }
198
                };
83 ilm 199
                this.timer.schedule(this.task, maxInterKeyDelay);
18 ilm 200
            }
201
            // si pas d'evenement, pas de temps associé
144 ilm 202
            assert !this.eve.isEmpty() || this.firstTime == -1;
18 ilm 203
        }
204
        return true;
205
    }
206
 
207
    private void redispatchLater() {
208
        SwingUtilities.invokeLater(new Runnable() {
209
            @Override
210
            public void run() {
211
                redispatch();
212
            }
213
        });
214
    }
215
 
216
    private void redispatch() {
217
        for (int i = 0; i < this.eve.size(); i++) {
218
            final KeyEvent ee = this.eve.get(i);
219
            KeyboardFocusManager.getCurrentKeyboardFocusManager().redispatchEvent(ee.getComponent(), ee);
220
            for (int j = 0; j < this.listeners.size(); j++) {
221
                this.listeners.get(j).keyReceived(ee);
222
            }
223
        }
224
        reset();
225
    }
226
 
227
    private void reset() {
228
        this.value = "";
229
        this.eve.clear();
230
        this.firstTime = -1;
231
    }
232
 
156 ilm 233
    public Map<Integer, String> getMapCharacterFR() {
234
        return mapCharacterFR;
235
    }
236
 
237
    public void setDebug(boolean debug) {
238
        this.debug = debug;
239
    }
240
 
83 ilm 241
    public static void main(String[] args) {
242
        String delay = "80";
243
        if (args.length > 0) {
244
            delay = args[0];
245
        }
246
        final int d = Integer.parseInt(delay);
247
        SwingUtilities.invokeLater(new Runnable() {
248
 
249
            @Override
250
            public void run() {
251
                try {
252
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
253
                } catch (Exception e) {
254
                    e.printStackTrace();
255
                }
256
                System.out.println("BarCode reader");
257
                System.out.println("Using inter key delay: " + d);
258
                JFrame f = new JFrame();
259
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
260
                JPanel panel = new JPanel();
261
                f.setTitle("Barcode reader test");
262
                f.setContentPane(panel);
263
                panel.setLayout(new GridBagLayout());
264
                GridBagConstraints c = new DefaultGridBagConstraints();
265
                final JLabel l = new JLabel("BarCode reader output :");
266
                panel.add(l, c);
267
                c.gridy++;
268
                c.weighty = 1;
269
                c.weightx = 1;
270
                c.fill = GridBagConstraints.BOTH;
271
                final ITextArea t1 = new ITextArea();
272
                panel.add(new JScrollPane(t1), c);
273
 
274
                BarcodeReader reader = new BarcodeReader(d);
156 ilm 275
                reader.setDebug(true);
276
 
277
                System.err.println("FR MAP");
278
                for (Entry<Integer, String> string : reader.getMapCharacterFR().entrySet()) {
279
                    System.err.println(string.getKey() + " --> " + string.getValue());
280
                }
281
 
83 ilm 282
                reader.addBarcodeListener(new BarcodeListener() {
283
 
284
                    @Override
285
                    public void keyReceived(KeyEvent ee) {
286
                        System.err.println("BarcodeReader keyReceived() : " + ee);
287
                    }
288
 
289
                    @Override
290
                    public void barcodeRead(String code) {
291
                        t1.append("Barcode OK : '" + code + "'\n");
292
                    }
293
                });
294
 
295
                f.setSize(new Dimension(640, 480));
296
                f.setLocationRelativeTo(null);
297
                f.setVisible(true);
298
 
299
            }
300
        });
301
 
302
    }
142 ilm 303
 
304
    public void setEnabled(boolean b) {
305
        this.enable = b;
306
    }
18 ilm 307
}