1095 lines · 37.3 KB · Java
RawDownload
        // Draw ticks        int lastY = Integer.MAX_VALUE;        for (int i = 0; i < n; i++) {            long v = tickValues.get(i);            y = topMargin+h-(int)(h * (v-vMin) / (vMax-vMin));            g.drawLine(x-2, y, x+2, y);            String s = tickStrings[i];            if (unit == Unit.PERCENT) {                s += "%";            }            int sx = x-6-fm.stringWidth(s);            if (y < lastY-13) {                if (checkLeftMargin(sx)) {                    // Wait for next repaint                    return;                }                g.drawString(s, sx, y+4);            }            // Draw horizontal grid line            g.setColor(Color.lightGray);            g.drawLine(r.x + 4, y, r.x + r.width - 4, y);            g.setColor(fg);            lastY = y;        }         // Draw horizontal axis        x = leftMargin;        y = topMargin + h + 15;        g.drawLine(x,   y,   x+w, y);         long t1 = tMax;        if (t1 <= 0L) {            // No data yet, so draw current time            t1 = System.currentTimeMillis();        }        long tz = timeDF.getTimeZone().getOffset(t1);        long tickInterval = calculateTickInterval(w, 40, viewRangeMS);        if (tickInterval > 3 * HOUR) {            tickInterval = calculateTickInterval(w, 80, viewRangeMS);        }        long t0 = tickInterval - (t1 - viewRangeMS + tz) % tickInterval;        while (t0 < viewRangeMS) {            x = leftMargin + (int)(w * t0 / viewRangeMS);            g.drawLine(x, y-2, x, y+2);             long t = t1 - viewRangeMS + t0;            String str = formatClockTime(t);            g.drawString(str, x, y+16);            //if (tickInterval > (1 * HOUR) && t % (1 * DAY) == 0) {            if ((t + tz) % (1 * DAY) == 0) {                str = formatDate(t);                g.drawString(str, x, y+27);            }            // Draw vertical grid line            g.setColor(Color.lightGray);            g.drawLine(x, topMargin, x, topMargin + h);            g.setColor(fg);            t0 += tickInterval;        }         // Plot values        int start = 0;        int nValues = 0;        int nLists = seqs.size();        if (nLists > 0) {            nValues = seqs.get(0).size;        }        if (nValues == 0) {            g.setColor(oldColor);            return;        } else {            Sequence seq = seqs.get(0);            // Find starting point            for (int p = 0; p < seq.size; p++) {                if (times.time(p) >= tMax - viewRangeMS) {                    start = p;                    break;                }            }        }         //Optimization: collapse plot of more than four values per pixel        int pointsPerPixel = (nValues - start) / w;        if (pointsPerPixel < 4) {            pointsPerPixel = 1;        }         // Draw graphs        // Loop backwards over sequences because the first needs to be painted on top        for (int i = nLists-1; i >= 0; i--) {            int x0 = leftMargin;            int y0 = topMargin + h + 1;             Sequence seq = seqs.get(i);            if (seq.isPlotted && seq.size > 0) {                // Paint twice, with white and with color                for (int pass = 0; pass < 2; pass++) {                    g.setColor((pass == 0) ? Color.white : seq.color);                    int x1 = -1;                    long v1 = -1;                    for (int p = start; p < nValues; p += pointsPerPixel) {                        // Make sure we get the last value                        if (pointsPerPixel > 1 && p >= nValues - pointsPerPixel) {                            p = nValues - 1;                        }                        int x2 = (int)(w * (times.time(p)-(t1-viewRangeMS)) / viewRangeMS);                        long v2 = seq.value(p);                        if (v2 >= vMin && v2 <= vMax) {                            int y2  = (int)(h * (v2 -vMin) / (vMax-vMin));                            if (x1 >= 0 && v1 >= vMin && v1 <= vMax) {                                int y1 = (int)(h * (v1-vMin) / (vMax-vMin));                                 if (y1 == y2) {                                    // fillrect is much faster                                    g.fillRect(x0+x1, y0-y1-pass, x2-x1, 1);                                } else {                                    Graphics2D g2d = (Graphics2D)g;                                    Stroke oldStroke = null;                                    if (seq.transitionStroke != null) {                                        oldStroke = g2d.getStroke();                                        g2d.setStroke(seq.transitionStroke);                                    }                                    g.drawLine(x0+x1, y0-y1-pass, x0+x2, y0-y2-pass);                                    if (oldStroke != null) {                                        g2d.setStroke(oldStroke);                                    }                                }                            }                        }                        x1 = x2;                        v1 = v2;                    }                }                 // Current value                long v = seq.value(seq.size - 1);                if (v >= vMin && v <= vMax) {                    if (bgIsLight) {                        g.setColor(seq.color);                    } else {                        g.setColor(fg);                    }                    x = r.x + r.width + 2;                    y = topMargin+h-(int)(h * (v-vMin) / (vMax-vMin));                    // a small triangle/arrow                    g.fillPolygon(new int[] { x+2, x+6, x+6 },                                  new int[] { y,   y+3, y-3 },                                  3);                }                g.setColor(fg);            }        }         int[] valueStringSlots = new int[nLists];        for (int i = 0; i < nLists; i++) valueStringSlots[i] = -1;        for (int i = 0; i < nLists; i++) {            Sequence seq = seqs.get(i);            if (seq.isPlotted && seq.size > 0) {                // Draw current value                 // TODO: collapse values if pointsPerPixel >= 4                 long v = seq.value(seq.size - 1);                if (v >= vMin && v <= vMax) {                    x = r.x + r.width + 2;                    y = topMargin+h-(int)(h * (v-vMin) / (vMax-vMin));                    int y2 = getValueStringSlot(valueStringSlots, y, 2*10, i);                    g.setFont(smallFont);                    if (bgIsLight) {                        g.setColor(seq.color);                    } else {                        g.setColor(fg);                    }                    String curValue = getFormattedValue(v, true);                    if (unit == Unit.PERCENT) {                        curValue += "%";                    }                    int valWidth = fm.stringWidth(curValue);                    String legend = (displayLegend?seq.name:"");                    int legendWidth = fm.stringWidth(legend);                    if (checkRightMargin(valWidth) || checkRightMargin(legendWidth)) {                        // Wait for next repaint                        return;                    }                    g.drawString(legend  , x + 17, Math.min(topMargin+h,      y2 + 3 - 10));                    g.drawString(curValue, x + 17, Math.min(topMargin+h + 10, y2 + 3));                     // Maybe draw a short line to value                    if (y2 > y + 3) {                        g.drawLine(x + 9, y + 2, x + 14, y2);                    } else if (y2 < y - 3) {                        g.drawLine(x + 9, y - 2, x + 14, y2);                    }                }                g.setFont(oldFont);                g.setColor(fg);             }        }        g.setColor(oldColor);    }     private boolean checkLeftMargin(int x) {        // Make sure leftMargin has at least 2 pixels over        if (x < 2) {            leftMargin += (2 - x);            // Repaint from top (above any cell renderers)            SwingUtilities.getWindowAncestor(this).repaint();            return true;        }        return false;    }     private boolean checkRightMargin(int w) {        // Make sure rightMargin has at least 2 pixels over        if (w + 2 > rightMargin) {            rightMargin = (w + 2);            // Repaint from top (above any cell renderers)            SwingUtilities.getWindowAncestor(this).repaint();            return true;        }        return false;    }     private int getValueStringSlot(int[] slots, int y, int h, int i) {        for (int s = 0; s < slots.length; s++) {            if (slots[s] >= y && slots[s] < y + h) {                // collide below us                if (slots[s] > h) {                    return getValueStringSlot(slots, slots[s]-h, h, i);                } else {                    return getValueStringSlot(slots, slots[s]+h, h, i);                }            } else if (y >= h && slots[s] > y - h && slots[s] < y) {                // collide above us                return getValueStringSlot(slots, slots[s]+h, h, i);            }        }        slots[i] = y;        return y;    }     private long calculateTickInterval(int w, int hGap, long viewRangeMS) {        long tickInterval = viewRangeMS * hGap / w;        if (tickInterval < 1 * MINUTE) {            tickInterval = 1 * MINUTE;        } else if (tickInterval < 5 * MINUTE) {            tickInterval = 5 * MINUTE;        } else if (tickInterval < 10 * MINUTE) {            tickInterval = 10 * MINUTE;        } else if (tickInterval < 30 * MINUTE) {            tickInterval = 30 * MINUTE;        } else if (tickInterval < 1 * HOUR) {            tickInterval = 1 * HOUR;        } else if (tickInterval < 3 * HOUR) {            tickInterval = 3 * HOUR;        } else if (tickInterval < 6 * HOUR) {            tickInterval = 6 * HOUR;        } else if (tickInterval < 12 * HOUR) {            tickInterval = 12 * HOUR;        } else if (tickInterval < 1 * DAY) {            tickInterval = 1 * DAY;        } else {            tickInterval = normalizeMax(tickInterval / DAY) * DAY;        }        return tickInterval;    }     private long normalizeMin(long l) {        int exp = (int)Math.log10((double)l);        long multiple = (long)Math.pow(10.0, exp);        int i = (int)(l / multiple);        return i * multiple;    }     private long normalizeMax(long l) {        int exp = (int)Math.log10((double)l);        long multiple = (long)Math.pow(10.0, exp);        int i = (int)(l / multiple);        l = (i+1)*multiple;        return l;    }     private String getFormattedValue(long v, boolean groupDigits) {        String str;        String fmt = "%";        if (groupDigits) {            fmt += ",";        }        if (decimals > 0) {            fmt += "." + decimals + "f";            str = String.format(fmt, v / decimalsMultiplier);        } else {            fmt += "d";            str = String.format(fmt, v);        }        return str;    }     private String getSizeString(long v, long vMax) {        String s;         if (unit == Unit.BYTES && decimals == 0) {            s = formatBytes(v, vMax);        } else {            s = getFormattedValue(v, true);        }        return s;    }     private static synchronized Stroke getDashedStroke() {        if (dashedStroke == null) {            dashedStroke = new BasicStroke(1.0f,                                           BasicStroke.CAP_BUTT,                                           BasicStroke.JOIN_MITER,                                           10.0f,                                           new float[] { 2.0f, 3.0f },                                           0.0f);        }        return dashedStroke;    }     private static Object extendArray(Object a1) {        int n = Array.getLength(a1);        Object a2 =            Array.newInstance(a1.getClass().getComponentType(),                              n + ARRAY_SIZE_INCREMENT);        System.arraycopy(a1, 0, a2, 0, n);        return a2;    }      private static class TimeStamps {        // Time stamps (long) are split into offsets (long) and a        // series of times from the offsets (int). A new offset is        // stored when the the time value doesn't fit in an int        // (approx every 24 days).  An array of indices is used to        // define the starting point for each offset in the times        // array.        long[] offsets = new long[0];        int[] indices = new int[0];        int[] rtimes = new int[ARRAY_SIZE_INCREMENT];         // Number of stored timestamps        int size = 0;         /**         * Returns the time stamp for index i         */        public long time(int i) {            long offset = 0;            for (int j = indices.length - 1; j >= 0; j--) {                if (i >= indices[j]) {                    offset = offsets[j];                    break;                }            }            return offset + rtimes[i];        }         public void add(long time) {            // May need to store a new time offset            int n = offsets.length;            if (n == 0 || time - offsets[n - 1] > Integer.MAX_VALUE) {                // Grow offset and indices arrays and store new offset                offsets = Arrays.copyOf(offsets, n + 1);                offsets[n] = time;                indices = Arrays.copyOf(indices, n + 1);                indices[n] = size;            }             // May need to extend the array size            if (rtimes.length == size) {                rtimes = (int[])extendArray(rtimes);            }             // Store the time            rtimes[size]  = (int)(time - offsets[offsets.length - 1]);            size++;        }    }     private static class Sequence {        String key;        String name;        Color color;        boolean isPlotted;        Stroke transitionStroke = null;         // Values are stored in an int[] if all values will fit,        // otherwise in a long[]. An int can represent up to 2 GB.        // Use a random start size, so all arrays won't need to        // be grown during the same update interval        Object values =            new byte[ARRAY_SIZE_INCREMENT + (int)(Math.random() * 100)];         // Number of stored values        int size = 0;         public Sequence(String key) {            this.key = key;        }         /**         * Returns the value at index i         */        public long value(int i) {            return Array.getLong(values, i);        }         public void add(long value) {            // May need to switch to a larger array type            if ((values instanceof byte[] ||                 values instanceof short[] ||                 values instanceof int[]) &&                       value > Integer.MAX_VALUE) {                long[] la = new long[Array.getLength(values)];                for (int i = 0; i < size; i++) {                    la[i] = Array.getLong(values, i);                }                values = la;            } else if ((values instanceof byte[] ||                        values instanceof short[]) &&                       value > Short.MAX_VALUE) {                int[] ia = new int[Array.getLength(values)];                for (int i = 0; i < size; i++) {                    ia[i] = Array.getInt(values, i);                }                values = ia;            } else if (values instanceof byte[] &&                       value > Byte.MAX_VALUE) {                short[] sa = new short[Array.getLength(values)];                for (int i = 0; i < size; i++) {                    sa[i] = Array.getShort(values, i);                }                values = sa;            }             // May need to extend the array size            if (Array.getLength(values) == size) {                values = extendArray(values);            }             // Store the value            if (values instanceof long[]) {                ((long[])values)[size] = value;            } else if (values instanceof int[]) {                ((int[])values)[size] = (int)value;            } else if (values instanceof short[]) {                ((short[])values)[size] = (short)value;            } else {                ((byte[])values)[size] = (byte)value;            }            size++;        }    }     // Can be overridden by subclasses    long getValue() {        return 0;    }     long getLastTimeStamp() {        return times.time(times.size - 1);    }     long getLastValue(String key) {        Sequence seq = getSequence(key);        return (seq != null && seq.size > 0) ? seq.value(seq.size - 1) : 0L;    }      // Called on EDT    public void propertyChange(PropertyChangeEvent ev) {        String prop = ev.getPropertyName();         if (prop == JConsoleContext.CONNECTION_STATE_PROPERTY) {            ConnectionState newState = (ConnectionState)ev.getNewValue();             switch (newState) {              case DISCONNECTED:                synchronized(this) {                    long time = System.currentTimeMillis();                    times.add(time);                    for (Sequence seq : seqs) {                        seq.add(Long.MIN_VALUE);                    }                }                break;            }        }    }     private static class SaveDataFileChooser extends JFileChooser {        private static final long serialVersionUID = -5182890922369369669L;        SaveDataFileChooser() {            setFileFilter(new FileNameExtensionFilter("CSV file", "csv"));        }         @Override

Lines 501–1000 of 1095. Previous lines