OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 182 | 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
 *
182 ilm 4
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
18 ilm 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
 
182 ilm 16
import org.openconcerto.erp.gs1.GS1Util;
18 ilm 17
 
185 ilm 18
import java.awt.Color;
19
import java.awt.Component;
20
import java.awt.Desktop;
83 ilm 21
import java.awt.Dimension;
185 ilm 22
import java.awt.FlowLayout;
83 ilm 23
import java.awt.GridBagConstraints;
24
import java.awt.GridBagLayout;
18 ilm 25
import java.awt.KeyEventDispatcher;
26
import java.awt.KeyboardFocusManager;
185 ilm 27
import java.awt.event.ActionEvent;
28
import java.awt.event.ActionListener;
18 ilm 29
import java.awt.event.KeyEvent;
185 ilm 30
import java.io.File;
31
import java.io.FileOutputStream;
32
import java.io.IOException;
33
import java.io.OutputStreamWriter;
34
import java.text.SimpleDateFormat;
18 ilm 35
import java.util.ArrayList;
185 ilm 36
import java.util.Date;
18 ilm 37
import java.util.List;
38
import java.util.Timer;
39
import java.util.TimerTask;
40
 
185 ilm 41
import javax.swing.JButton;
42
import javax.swing.JFileChooser;
83 ilm 43
import javax.swing.JFrame;
44
import javax.swing.JLabel;
45
import javax.swing.JPanel;
46
import javax.swing.JScrollPane;
185 ilm 47
import javax.swing.JSpinner;
48
import javax.swing.JTable;
49
import javax.swing.JTextArea;
50
import javax.swing.SpinnerNumberModel;
18 ilm 51
import javax.swing.SwingUtilities;
83 ilm 52
import javax.swing.UIManager;
185 ilm 53
import javax.swing.event.ChangeEvent;
54
import javax.swing.event.ChangeListener;
55
import javax.swing.event.TableModelEvent;
56
import javax.swing.event.TableModelListener;
57
import javax.swing.table.DefaultTableCellRenderer;
58
import javax.swing.table.TableModel;
18 ilm 59
 
60
/**
61
 * Lecteur code barres, intercepte les événements clavier pour détecter un scan de code. Le code
182 ilm 62
 * barre doit terminer par un retour à la ligne. Pour les GS1 : Aim Code ID Character AIM ID doit
63
 * être activé, ]D2 pour databar / ]C1 pour GS1
142 ilm 64
 */
18 ilm 65
public class BarcodeReader implements KeyEventDispatcher {
66
 
185 ilm 67
    public class KeyEventTableModel implements TableModel {
68
        public static final String CHAR_UNDEFINED = "CHAR_UNDEFINED";
69
        public static final String KEY_TYPED = "Key Typed";
70
        List<TableModelListener> listeners = new ArrayList<>();
71
        List<KeyEvent> list = new ArrayList<>();
72
 
73
        private KeyEventTableModel() {
74
            //
75
        }
76
 
77
        @Override
78
        public int getRowCount() {
79
            return list.size();
80
        }
81
 
82
        @Override
83
        public int getColumnCount() {
84
            return 4;
85
        }
86
 
87
        @Override
88
        public String getColumnName(int columnIndex) {
89
            switch (columnIndex) {
90
            case 0:
91
                return "Date";
92
            case 1:
93
                return "ID";
94
            case 2:
95
                return "Code";
96
            case 3:
97
                return "Character";
98
            default:
99
                break;
100
            }
101
            return "?";
102
        }
103
 
104
        @Override
105
        public Class<?> getColumnClass(int columnIndex) {
106
            if (columnIndex == 0) {
107
                return Date.class;
108
            }
109
            return String.class;
110
        }
111
 
112
        @Override
113
        public boolean isCellEditable(int rowIndex, int columnIndex) {
114
            return false;
115
        }
116
 
117
        @Override
118
        public Object getValueAt(int rowIndex, int columnIndex) {
119
            KeyEvent e = list.get(rowIndex);
120
            switch (columnIndex) {
121
            case 0:
122
                return new Date(e.getWhen());
123
            case 1:
124
                int id = e.getID();
125
                if (id == KeyEvent.KEY_TYPED) {
126
                    return KEY_TYPED;
127
                }
128
                if (id == KeyEvent.KEY_PRESSED) {
129
                    return "Key Pressed";
130
                }
131
                if (id == KeyEvent.KEY_RELEASED) {
132
                    return "Key Released";
133
                }
134
                return String.valueOf(id);
135
            case 2:
136
                int code = e.getKeyCode();
137
                String name = "";
138
                if (code == KeyEvent.VK_ENTER) {
139
                    name = "ENTER";
140
                } else if (code == KeyEvent.VK_BACK_SPACE) {
141
                    name = "BACK SPACE";
142
                } else if (code == KeyEvent.VK_SHIFT) {
143
                    name = "SHIFT";
144
                } else if (code >= KeyEvent.VK_0 && code <= KeyEvent.VK_9) {
145
                    name = "DIGIT";
146
                } else if (code >= KeyEvent.VK_A && code <= KeyEvent.VK_Z) {
147
                    name = "CHAR";
148
                } else if (code == KeyEvent.VK_F8) {
149
                    name = "F8";
150
                }
151
                return (name + " " + String.valueOf(code) + "  0x" + charToHex((char) code)).trim();
152
            case 3:
153
                char kc = e.getKeyChar();
154
                if (kc == KeyEvent.CHAR_UNDEFINED) {
155
                    return CHAR_UNDEFINED;
156
                } else if (kc == 29) {
157
                    return "<GS>";
158
                }
159
                return String.valueOf(kc);
160
            default:
161
                break;
162
            }
163
 
164
            return null;
165
        }
166
 
167
        @Override
168
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
169
            // nothing
170
 
171
        }
172
 
173
        @Override
174
        public void addTableModelListener(TableModelListener l) {
175
            this.listeners.add(l);
176
 
177
        }
178
 
179
        @Override
180
        public void removeTableModelListener(TableModelListener l) {
181
            this.listeners.remove(l);
182
        }
183
 
184
        Timer t = new Timer();
185
 
186
        public void fire() {
187
            t.cancel();
188
            t = new Timer();
189
            t.schedule(new TimerTask() {
190
 
191
                @Override
192
                public void run() {
193
                    for (TableModelListener l : listeners) {
194
                        l.tableChanged(new TableModelEvent(KeyEventTableModel.this));
195
                    }
196
 
197
                }
198
            }, 400);
199
 
200
        }
201
 
202
        public void clear() {
203
            this.list.clear();
204
            fire();
205
        }
206
 
207
        public void add(KeyEvent e) {
208
            this.list.add(e);
209
            fire();
210
 
211
        }
212
 
213
    }
214
 
215
    private int maxInterKeyDelay = 200;
18 ilm 216
    private static final int MIN_BARCODE_LENGTH = 2;
185 ilm 217
    private final List<BarcodeListener> listeners = new ArrayList<>(1);
218
    private List<KeyEventDispatcher> dispatchers = null;
18 ilm 219
    private String value = "";
185 ilm 220
    private final List<KeyEvent> eve = new ArrayList<>();
18 ilm 221
    private long firstTime = -1;
222
    private Timer timer;
223
    // non final car un TimerTask n'est pas reutilisable
224
    private TimerTask task;
142 ilm 225
    private boolean enable = true;
185 ilm 226
    private boolean debug = true;
227
    private List<Integer> valueCode = new ArrayList<>();
18 ilm 228
 
83 ilm 229
    public BarcodeReader(int maxInterKeyDelay) {
18 ilm 230
        this.timer = null;
231
        this.task = null;
83 ilm 232
        this.maxInterKeyDelay = maxInterKeyDelay;
185 ilm 233
 
18 ilm 234
    }
235
 
185 ilm 236
    public void setMaxInterKeyDelay(int maxInterKeyDelay) {
237
        this.maxInterKeyDelay = maxInterKeyDelay;
238
    }
239
 
240
    public void addKeyEventDispatcher(KeyEventDispatcher d) {
241
        if (this.dispatchers == null) {
242
            this.dispatchers = new ArrayList<>();
243
        }
244
        this.dispatchers.add(d);
245
    }
246
 
18 ilm 247
    public synchronized void removeBarcodeListener(BarcodeListener l) {
248
        this.listeners.remove(l);
144 ilm 249
        if (this.listeners.isEmpty()) {
18 ilm 250
            stop();
251
        }
252
    }
253
 
254
    public synchronized void addBarcodeListener(final BarcodeListener l) {
144 ilm 255
        if (this.timer == null) {
256
            start();
257
        }
18 ilm 258
        this.listeners.add(l);
259
    }
260
 
185 ilm 261
    private void fire(Barcode code) {
18 ilm 262
        for (int i = 0; i < this.listeners.size(); i++) {
263
            this.listeners.get(i).barcodeRead(code);
264
        }
265
    }
266
 
267
    /**
268
     * Commence à ecouter les évenements clavier pour intercepter les codes barres
142 ilm 269
     */
18 ilm 270
 
142 ilm 271
    public synchronized void start() {
272
        if (this.timer == null) {
273
            // init avant que les listeners s'en servent
274
            this.timer = new Timer(getClass().getName(), true);
275
            KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
185 ilm 276
            System.err.println("BarcodeReader start : scan delay between keys" + this.maxInterKeyDelay + " ms");
142 ilm 277
        }
18 ilm 278
    }
279
 
280
    /**
281
     * Stoppe l'écoute sur les évenements clavier
142 ilm 282
     */
283
    public synchronized void stop() {
18 ilm 284
        if (this.timer != null) {
144 ilm 285
            System.err.println("BarcodeReader stop");
18 ilm 286
            this.timer.cancel();
93 ilm 287
            this.timer = null;
142 ilm 288
            KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
18 ilm 289
        }
290
    }
291
 
185 ilm 292
    int lastPressedkeyCode = 0;
293
 
18 ilm 294
    @Override
295
    public boolean dispatchKeyEvent(KeyEvent e) {
180 ilm 296
        if (!this.enable) {
142 ilm 297
            return false;
180 ilm 298
        }
18 ilm 299
        if (this.task != null)
300
            this.task.cancel();
185 ilm 301
        if (this.dispatchers != null) {
302
            for (KeyEventDispatcher d : this.dispatchers) {
303
                d.dispatchKeyEvent(e);
304
            }
305
        }
18 ilm 306
 
307
        final long t = e.getWhen();
308
        if (this.firstTime < 0) {
309
            this.firstTime = t;
310
        }
185 ilm 311
 
156 ilm 312
        int keyCode = e.getKeyCode();
18 ilm 313
 
142 ilm 314
        final long delay = t - this.firstTime;
180 ilm 315
        if (keyCode == KeyEvent.VK_BACK_SPACE || keyCode == KeyEvent.VK_DELETE || (delay > this.maxInterKeyDelay && keyCode != KeyEvent.VK_SHIFT)) {
18 ilm 316
            // touche normale
156 ilm 317
            if (this.debug) {
185 ilm 318
                System.err.println("Touche normale " + keyCode + " delai:" + delay);
156 ilm 319
            }
142 ilm 320
            this.eve.add(e);
18 ilm 321
            redispatch();
142 ilm 322
            return true;
18 ilm 323
        }
324
 
156 ilm 325
        final char keyChar = e.getKeyChar();
18 ilm 326
        this.eve.add(e);
185 ilm 327
        if (e.getID() == KeyEvent.KEY_PRESSED) {
328
            lastPressedkeyCode = e.getKeyCode();
329
        }
330
        if (e.getID() == KeyEvent.KEY_RELEASED && keyCode == KeyEvent.VK_F8) {
331
            this.value += '\u001D';
332
            this.valueCode.add(lastPressedkeyCode);
333
        } else {
334
            if (e.getID() == KeyEvent.KEY_RELEASED && keyCode == KeyEvent.VK_ENTER && this.value.length() >= MIN_BARCODE_LENGTH) {
18 ilm 335
                // fin de code barre
156 ilm 336
                if (this.debug) {
337
                    System.err.println("BARCODE OK ENTER OR LENGHT " + keyCode + " length = " + this.value.length() + " min length =" + MIN_BARCODE_LENGTH);
338
                }
18 ilm 339
                this.value = this.value.trim();
185 ilm 340
                if (this.value.startsWith("$")) {
341
                    // Barcode not configured for FR
342
                    StringBuilder b = new StringBuilder(this.value.length());
343
                    for (int i = 0; i < this.value.length(); i++) {
344
                        char c = this.value.charAt(i);
345
                        int kCode = this.valueCode.get(i);
346
                        if (c == '&') {
347
                            b.append('1');
348
                        } else if (c == 'é') {
349
                            b.append('2');
350
                        } else if (c == '"') {
351
                            b.append('3');
352
                        } else if (c == '\'') {
353
                            b.append('4');
354
                        } else if (c == '(') {
355
                            b.append('5');
356
                        } else if (c == '-') {
357
                            if (kCode == 109) {
358
                                b.append('-');
359
                            } else {
360
                                b.append('6');
361
                            }
362
                        } else if (c == 'è') {
363
 
364
                            b.append('7');
365
 
366
                        } else if (c == '_') {
367
                            b.append('8');
368
                        } else if (c == 'ç') {
369
                            b.append('9');
370
                        } else if (c == 'à') {
371
                            b.append('0');
372
                        } else if (c == '$') {
373
                            b.append(']');
374
                        } else if (c == 'M') {
375
                            b.append(':');
376
                        } else if (c == '!') {
377
                            b.append('/');
378
                        } else if (c == 'q') {
379
                            b.append('a');
380
                        } else if (c == 'a') {
381
                            b.append('q');
382
                        } else if (c == 'z') {
383
                            b.append('w');
384
                        } else if (c == 'w') {
385
                            b.append('z');
386
                        } else if (c == 'Q') {
387
                            b.append('A');
388
                        } else if (c == 'A') {
389
                            b.append('Q');
390
                        } else if (c == 'Z') {
391
                            b.append('W');
392
                        } else if (c == 'W') {
393
                            b.append('Z');
394
                        } else if (c == ',') {
395
                            b.append('m');
396
                        } else if (c == '?') {
397
                            b.append('M');
398
                        } else if (c == ':') {
399
                            b.append('.');
400
                        } else if (c == 'Ò') {
401
                            b.append('°');
402
                        } else if (c == 'ª') {
403
                            b.append('é');
404
                        } else if (c == '%') {
405
                            b.append('"');
406
                        } else if (c == 'ù') {
407
                            b.append('\'');
408
                        } else if (c == '¨') {
409
                            b.append('{');
410
                        } else if (c == '£') {
411
                            b.append('}');
412
                        } else if (c == 'ñ') {
413
                            if (kCode == 18) {
414
                                b.append('à');
415
                            } else
416
                                b.append('&');
417
                        } else if (c == '0') {
418
                            b.append(')');
419
                        } else if (c == '1') {
420
                            b.append('!');
421
                        } else if (c == '2') {
422
                            b.append('@');
423
                        } else if (c == '3') {
424
                            b.append('#');
425
                        } else if (c == '4') {
426
                            b.append('$');
427
                        } else if (c == '5') {
428
                            b.append('%');
429
                        } else if (c == '6') {
430
                            if (kCode == 54) {
431
                                b.append('^');
432
                            } else
433
                                b.append('ç');
434
                        } else if (c == '7') {
435
                            //
436
                            b.append('&');
437
                        } else if (c == '9') {
438
                            b.append('(');
439
                        } else if (c == '^') {
440
                            b.append('[');
441
                        } else if (c == 'µ') {
442
                            b.append('|');
443
                        } else if (c == '¿') {
444
                            b.append('è');
445
                        } else if (c == '²') {
446
                            b.append('`');
447
                        } else if (c == '°') {
448
                            b.append('_');
449
                        } else if (c == '/') {
450
                            b.append('>');
451
                        } else if (c == '.') {
452
                            b.append('<');
453
                        } else if (c == 'ý') {
454
                            b.append('§');
455
                        } else if (c == 'm') {
456
                            b.append(';');
457
                        } else if (c == '┤') {
458
                            b.append('ù');
459
                        } else if (c == '\\') {
460
                            b.append('*');
461
                        } else if (c == '§') {
462
                            b.append('?');
463
                        } else if (c == ';') {
464
                            b.append(',');
465
                        } else if (c == '*') {
466
                            if (kCode == 106) {
467
                                b.append('*');
468
                            } else
469
                                b.append('\\');
470
                        } else {
471
                            b.append(c);
472
                        }
473
 
474
                    }
475
                    this.value = b.toString();
476
                    fire(new Barcode(this.value));
477
                } else {
478
                    fire(new Barcode(this.value));
479
                }
18 ilm 480
                reset();
185 ilm 481
            } else if (e.getID() == KeyEvent.KEY_TYPED) {
156 ilm 482
                this.value += keyChar;
185 ilm 483
                this.valueCode.add(lastPressedkeyCode);
18 ilm 484
            }
185 ilm 485
 
486
        }
487
 
488
        // redispatch();
489
 
490
        // lance un timer s'il reste des evenements non dispatchés
491
        if (!this.eve.isEmpty())
492
 
493
        {
494
            this.firstTime = t;
495
            this.task = new TimerTask() {
496
                @Override
497
                public void run() {
498
                    SwingUtilities.invokeLater(new Runnable() {
499
                        @Override
500
                        public void run() {
501
                            redispatch();
502
                        }
503
                    });
182 ilm 504
                }
185 ilm 505
            };
506
            try {
507
                this.timer.schedule(this.task, this.maxInterKeyDelay);
508
            } catch (Exception ex) {
509
                ex.printStackTrace();
18 ilm 510
            }
511
        }
185 ilm 512
        // si pas d'evenement, pas de temps associé
513
        assert !this.eve.isEmpty() || this.firstTime == -1;
514
 
18 ilm 515
        return true;
180 ilm 516
 
18 ilm 517
    }
518
 
519
    private void redispatch() {
520
        for (int i = 0; i < this.eve.size(); i++) {
521
            final KeyEvent ee = this.eve.get(i);
522
            KeyboardFocusManager.getCurrentKeyboardFocusManager().redispatchEvent(ee.getComponent(), ee);
523
            for (int j = 0; j < this.listeners.size(); j++) {
524
                this.listeners.get(j).keyReceived(ee);
525
            }
526
        }
527
        reset();
528
    }
529
 
530
    private void reset() {
531
        this.value = "";
185 ilm 532
        this.valueCode.clear();
533
        this.lastPressedkeyCode = 0;
18 ilm 534
        this.eve.clear();
535
        this.firstTime = -1;
536
    }
537
 
156 ilm 538
    public void setDebug(boolean debug) {
539
        this.debug = debug;
540
    }
541
 
83 ilm 542
    public static void main(String[] args) {
185 ilm 543
        final String delay;
83 ilm 544
        if (args.length > 0) {
545
            delay = args[0];
185 ilm 546
        } else {
547
            delay = "40";
83 ilm 548
        }
549
        final int d = Integer.parseInt(delay);
550
        SwingUtilities.invokeLater(new Runnable() {
551
 
552
            @Override
553
            public void run() {
554
                try {
555
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
556
                } catch (Exception e) {
557
                    e.printStackTrace();
558
                }
185 ilm 559
                BarcodeReader reader = new BarcodeReader(d);
83 ilm 560
                System.out.println("BarCode reader");
561
                System.out.println("Using inter key delay: " + d);
562
                JFrame f = new JFrame();
563
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
185 ilm 564
                final JPanel panel = new JPanel();
565
                f.setTitle("Barcode reader tester (AIM ID required for GS1)");
83 ilm 566
                f.setContentPane(panel);
567
                panel.setLayout(new GridBagLayout());
185 ilm 568
                GridBagConstraints c = new GridBagConstraints();
569
 
570
                c.gridx = 0;
571
                c.gridy = 0;
572
                c.weighty = 0.5;
573
                c.fill = GridBagConstraints.BOTH;
574
                final KeyEventTableModel keyEventTableModel = reader.new KeyEventTableModel();
575
                JTable table = new JTable(keyEventTableModel);
576
                SimpleDateFormat df = new SimpleDateFormat(" hh:mm:ss.SSS");
577
                table.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
578
                    @Override
579
                    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
580
                        Date d = (Date) value;
581
                        value = df.format(d);
582
                        if (table.getModel().getRowCount() > 0) {
583
                            Date d1 = (Date) table.getModel().getValueAt(0, 0);
584
                            value += " " + (d.getTime() - d1.getTime()) + " ms";
585
                        }
586
                        return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
587
                    }
588
                });
589
 
590
                table.getColumnModel().getColumn(3).setCellRenderer(new DefaultTableCellRenderer() {
591
                    @Override
592
                    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
593
 
594
                        Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
595
 
596
                        String str = (String) value;
597
                        if (str.equals(KeyEventTableModel.CHAR_UNDEFINED)) {
598
 
599
                            String id = table.getModel().getValueAt(row, 0).toString();
600
                            if (id.equals(KeyEventTableModel.KEY_TYPED)) {
601
                                c.setBackground(Color.YELLOW);
602
                            }
603
                        }
604
                        return c;
605
 
606
                    }
607
                });
608
 
609
                panel.add(new JScrollPane(table), c);
83 ilm 610
                final JLabel l = new JLabel("BarCode reader output :");
611
                panel.add(l, c);
612
                c.gridy++;
613
                c.weighty = 1;
614
                c.weightx = 1;
185 ilm 615
 
616
                final JTextArea t1 = new JTextArea(20, 10);
617
                t1.setLineWrap(true);
618
                t1.setWrapStyleWord(true);
619
                t1.setMinimumSize(new Dimension(t1.getMinimumSize()));
620
 
83 ilm 621
                panel.add(new JScrollPane(t1), c);
622
 
185 ilm 623
                JPanel tools = new JPanel();
624
                tools.setLayout(new FlowLayout(FlowLayout.RIGHT));
625
 
626
                JSpinner spin = new JSpinner(new SpinnerNumberModel(d, 5, 800, 10));
627
                spin.addChangeListener(new ChangeListener() {
628
 
629
                    @Override
630
                    public void stateChanged(ChangeEvent e) {
631
                        int v = ((Number) spin.getValue()).intValue();
632
                        reader.setMaxInterKeyDelay(v);
633
                    }
634
                });
635
                tools.add(spin);
636
                JButton b = new JButton("Reset");
637
                tools.add(b);
638
                JButton bExport = new JButton("Export");
639
                tools.add(bExport);
640
                c.weighty = 0;
641
                c.gridx = 0;
642
                c.gridy++;
643
                c.gridwidth = 2;
644
 
645
                panel.add(tools, c);
646
 
156 ilm 647
                reader.setDebug(true);
185 ilm 648
                bExport.addActionListener(new ActionListener() {
156 ilm 649
 
185 ilm 650
                    @Override
651
                    public void actionPerformed(ActionEvent e) {
652
                        int colCount = keyEventTableModel.getColumnCount();
653
                        int rowCount = keyEventTableModel.getRowCount();
654
                        StringBuilder b = new StringBuilder();
655
                        SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss.SSS");
656
                        for (int i = 0; i < rowCount; i++) {
657
                            for (int j = 0; j < colCount; j++) {
658
                                Object o = keyEventTableModel.getValueAt(i, j);
659
                                if (o instanceof Date) {
660
                                    b.append(df.format((Date) o));
661
                                } else {
662
                                    final String string = o.toString();
663
                                    if (string.equals("\n")) {
664
                                        b.append("\\n");
665
                                    } else if (string.equals("\r")) {
666
                                        b.append("\\r");
667
                                    } else {
668
                                        b.append(string);
669
                                    }
670
                                }
671
                                b.append(';');
672
                            }
673
                            b.append("\n");
674
                        }
156 ilm 675
 
185 ilm 676
                        JFileChooser fileChooser = new JFileChooser();
677
                        fileChooser.setSelectedFile(new File("OpenConcerto-KeyEvents.txt"));
678
                        int retval = fileChooser.showSaveDialog(panel);
679
                        if (retval == JFileChooser.APPROVE_OPTION) {
680
                            File file = fileChooser.getSelectedFile();
681
                            if (file == null) {
682
                                return;
683
                            }
684
                            if (!file.getName().toLowerCase().endsWith(".txt")) {
685
                                file = new File(file.getParentFile(), file.getName() + ".txt");
686
                            }
687
                            try (OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file), "utf-8")) {
688
                                out.write(b.toString());
689
                                out.write(t1.getText());
690
                                out.write("\n");
691
                                out.write("Delay: " + delay);
692
                                out.flush();
693
                            } catch (Exception ex) {
694
                                ex.printStackTrace();
695
                            }
696
                            if (file.exists()) {
697
                                try {
698
                                    Desktop.getDesktop().open(file);
699
                                } catch (IOException e1) {
700
                                    e1.printStackTrace();
701
                                }
702
                            }
703
                        }
704
                    }
705
                });
706
                b.addActionListener(new ActionListener() {
707
 
708
                    @Override
709
                    public void actionPerformed(ActionEvent e) {
710
                        t1.setText("");
711
                        keyEventTableModel.clear();
712
 
713
                    }
714
                });
715
                reader.addKeyEventDispatcher(new KeyEventDispatcher() {
716
 
717
                    @Override
718
                    public boolean dispatchKeyEvent(KeyEvent e) {
719
                        keyEventTableModel.add(e);
720
                        return false;
721
                    }
722
                });
83 ilm 723
                reader.addBarcodeListener(new BarcodeListener() {
724
 
725
                    @Override
726
                    public void keyReceived(KeyEvent ee) {
727
                        System.err.println("BarcodeReader keyReceived() : " + ee);
728
                    }
729
 
730
                    @Override
185 ilm 731
                    public void barcodeRead(Barcode code) {
732
                        t1.append("Barcode OK : '" + code.getCode() + "'\nType : " + code.getType() + " \n");
733
                        t1.append("Hex: " + bytesToHexString(code.getCode().getBytes()) + "'\n");
734
                        t1.append("Data : '" + code.getData() + "'\n");
735
 
182 ilm 736
                        GS1Util e = new GS1Util();
737
                        try {
185 ilm 738
                            t1.append("GS1 : " + e.parse(code).formatHumanReadable());
182 ilm 739
                        } catch (Exception ex) {
185 ilm 740
                            final String message = ex.getMessage();
741
                            if (message == null) {
742
                                t1.append("Not a GS1 code");
743
                            } else
744
                                t1.append("Not a GS1 code : " + message);
182 ilm 745
                        }
746
                        t1.append("\n\n");
83 ilm 747
                    }
748
                });
749
 
185 ilm 750
                t1.setEditable(false);
751
                f.setSize(new Dimension(640, 580));
83 ilm 752
                f.setLocationRelativeTo(null);
753
                f.setVisible(true);
754
 
755
            }
185 ilm 756
 
83 ilm 757
        });
758
 
759
    }
142 ilm 760
 
761
    public void setEnabled(boolean b) {
762
        this.enable = b;
763
    }
185 ilm 764
 
765
    static final char[] hexArray = "0123456789ABCDEF".toCharArray();
766
 
767
    public static String charToHex(char c) {
768
        int v = c & 0xFF;
769
        char[] hexChars = new char[2];
770
        hexChars[0] = hexArray[v >>> 4];
771
        hexChars[1] = hexArray[v & 0x0F];
772
        return new String(hexChars);
773
    }
774
 
775
    public static String bytesToHexString(byte[] bytes) {
776
        int length = bytes.length;
777
        char[] hexChars = new char[length * 2];
778
        for (int j = 0; j < length; j++) {
779
            int v = bytes[j] & 0xFF;
780
            hexChars[j * 2] = hexArray[v >>> 4];
781
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
782
        }
783
        return new String(hexChars);
784
    }
18 ilm 785
}