001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.iso.gui;
020
021import org.jpos.iso.ISOMsg;
022
023import javax.swing.*;
024import java.awt.*;
025import java.awt.event.MouseAdapter;
026import java.awt.event.MouseEvent;
027import java.awt.event.MouseListener;
028
029/**
030 * ISOMsgPanel
031 * Swing based GUI to ISOMsg
032 * @author apr@cs.com.uy
033 * @author Kris Leite <kleite at imcsoftware.com>
034 * @see org.jpos.iso.ISOMsg
035 */
036@SuppressWarnings("deprecation")
037public class ISOMeter extends JComponent implements Runnable {
038
039    private static final long serialVersionUID = -1770533267122111538L;
040    /**
041     * @serial
042     */
043    Color color = new Color (255, 255, 255);
044    /**
045     * @serial
046     */
047    Image im;
048    /**
049     * @serial
050     */
051    Graphics img;
052    /**
053     * @serial
054     */
055    Font fontBig, fontSmall;
056    /**
057     * @serial
058     */
059    String positiveText;
060    /**
061     * @serial
062     */
063    String negativeText;
064    /**
065     * @serial
066     */
067    Timer ti;
068    /**
069     * handle ISOMeter's counters outside of this class in order
070     * to reduce 'int' to 'String' conversions.
071     * @serial
072     */
073    String positiveCounter;
074    /**
075     * @serial
076     */
077    String negativeCounter;
078    /**
079     * @serial
080     */
081    int lastPositive;
082    /**
083     * @serial
084     */
085    int lastNegative;
086    /**
087     * @serial
088     */
089    boolean connected;
090    /**
091     * @serial
092     */
093    ISOChannelPanel parent;
094
095    final static int width    = 200;
096    final static int height   = 60;
097    final static int mass     = height/2;
098    final static int MAX_VALUE = 1000;
099
100    /**
101     * @serial
102     */
103    int[] yPoints;
104    /**
105     * @serial
106     */
107    int[] xPoints;
108    /**
109     * counter to keep the scrolling active
110     */
111    int continueScroll;
112    /**
113     * used to determine if to scroll mark to end of graph
114     */
115    boolean scroll = true;
116    /**
117     * Refresh panel in millseconds
118     */
119    int refreshPanel = 50;
120
121    private Image imb;
122    private Thread repaintThread;
123
124    public ISOMeter(ISOChannelPanel parent) {
125        super();
126        this.parent = parent;
127
128        fontBig   = new Font ("Helvetica", Font.ITALIC, mass*3/4);
129        fontSmall = new Font ("Helvetica", Font.PLAIN, 10);
130        yPoints = new int[width];
131        xPoints = new int[width];
132        for (int i=0; i<width; i++) {
133            xPoints[i] = i;
134            yPoints[i] = mass;
135        }
136        positiveText  = null;
137        negativeText  = null;
138        positiveCounter = negativeCounter = "";
139        connected     = false;
140
141        MouseListener mouseListener = new MouseAdapter() {
142            public void mouseClicked(MouseEvent e) {
143                showLogList();
144            }
145        };
146        addMouseListener(mouseListener);
147    }
148
149    public synchronized void start() {
150        if (repaintThread == null) {
151            repaintThread = new Thread (this,"ISOMeter");
152            repaintThread.setPriority (Thread.NORM_PRIORITY-1);
153            repaintThread.start();
154        }
155    }
156
157    public void showLogList() {
158        JFrame f = new JFrame(parent.getSymbolicName());
159        f.getContentPane().add(createLogList());
160        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
161        f.validate();
162        f.pack();
163        f.setSize(width,width+50);
164        f.show();
165    }
166
167    public JComponent createLogList() {
168        final JList logList = new JList(parent.getLog());
169        JPanel A = new JPanel();
170        A.setLayout(new BorderLayout());
171
172        MouseListener mouseListener = new MouseAdapter() {
173            public void mouseClicked(MouseEvent e) {
174                ISOMsg m = (ISOMsg) logList.getSelectedValue();
175                if (m != null) {
176                    JFrame f = new JFrame(
177                        parent.getSymbolicName()+":"+m.toString());
178                    ISOMsgPanel p = new ISOMsgPanel(m);
179                    f.getContentPane().add(p);
180                    f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
181                    f.pack();
182                    f.show();
183                }
184            }
185        };
186        logList.addMouseListener(mouseListener);
187
188        logList.setPrototypeCellValue("9999 99999999 999999");
189        JScrollPane scrollPane = new JScrollPane(logList);
190        A.add(scrollPane, BorderLayout.CENTER);
191        return A;
192    }
193
194    public void setValue(int val) {
195        int y = mass - val%1000 * height / 2000;
196        yPoints[width-1] = y;
197        continueScroll = width;
198        scroll();
199    }
200
201    public void setScroll (boolean scroll) {
202        this.scroll = scroll;
203    }
204    public void setRefresh (int refreshPanel) {
205        if (refreshPanel > 0)
206            this.refreshPanel = refreshPanel;
207    }
208    public void setConnected(boolean connected) {
209        if (this.connected != connected) {
210            if (!scroll)
211                if (connected)
212                    continueScroll = width;
213                else
214                    continueScroll = 1;
215            repaint();
216        }
217        this.connected = connected;
218    }
219    public void setPositiveCounter(String s) {
220        positiveCounter = s;
221    }
222    public void setNegativeCounter(String s){
223        negativeCounter = s;
224    }
225    public void setValue(int val, String textString) {
226        setValue(val);
227        if (val < 0) {
228            negativeText = textString;
229            lastNegative = 0;
230        }
231        else {
232            positiveText = textString;
233            lastPositive = 0;
234        }
235    }
236    public void paint (Graphics g) {
237        if (repaintThread == null)
238            start();
239        plot();
240        g.drawImage (im, 0, 0, null);
241    }
242    public Dimension getPreferredSize() {
243        return new Dimension(width, height);
244    }
245    private void scroll() {
246        System.arraycopy(yPoints, 1, yPoints, 0, width - 1);
247        if (continueScroll > 0)
248            continueScroll--;
249    }
250    public void plot() {
251       if (im == null) {
252            im = createImage(width, height);
253            img = im.getGraphics ();
254            img.setColor (Color.black);
255            img.fillRoundRect (0, 0, width, height, 10, 10);
256            img.clipRect (0, 0, width, height);
257            plotGrid();
258
259            /* save a copy of the image */
260            imb = createImage(width, height);
261            Graphics imbCopy = imb.getGraphics();
262            imbCopy.drawImage (im, 0, 0, this);
263        }
264        img.drawImage (imb, 0, 0, this);
265        if (continueScroll > 0)
266            scroll();
267        plotText(positiveText, lastPositive++, 3, mass-3);
268        plotText(negativeText, lastNegative++, 3, height-3);
269        plotCounters(positiveCounter, negativeCounter);
270        img.setColor (connected ? Color.green : Color.red);
271        img.drawPolyline(xPoints, yPoints, width);
272    }
273    private void plotGrid() {
274        img.setColor(Color.blue);
275        for (int i=0; i<width; i++)
276            if (i % 20 == 0) 
277                img.drawLine(i,0,i,height);
278        for (int i=-1000; i<1000; i+= 200) {
279            int y = mass + i*height/2000;
280            img.drawLine(0,y,width,y);
281        }
282    }
283    private void plotText(String t, int l, int x, int y) {
284        if (t != null && l < 20) {
285            img.setColor(Color.lightGray);
286            img.setFont(fontBig);
287            img.drawString (t, x, y);
288        }
289    }
290    private void plotCounters(String p, String n) {
291        img.setColor(Color.lightGray);
292        img.setFont(fontSmall);
293        img.drawString (p, width-55, 13);
294        img.drawString (n, width-55, height-3);
295    }
296    public void run () {
297        while (isShowing()) {
298            if (continueScroll > 0)
299                repaint();
300            try { 
301                Thread.sleep(refreshPanel);
302            } catch (InterruptedException e) {
303                // OK to ignore
304            }
305        }
306        repaintThread = null;
307    }
308    public void update (Graphics g) {
309        paint (g);
310    }
311}