Source Code Cross Referenced for Plotter.java in  » 6.0-JDK-Modules-sun » tools » sun » tools » jconsole » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules sun » tools » sun.tools.jconsole 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2004-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package sun.tools.jconsole;
0027:
0028:        import java.awt.*;
0029:        import java.awt.event.*;
0030:        import java.beans.*;
0031:        import java.io.*;
0032:        import java.lang.reflect.Array;
0033:        import java.text.*;
0034:        import java.util.*;
0035:
0036:        import javax.accessibility.*;
0037:        import javax.swing.*;
0038:        import javax.swing.border.*;
0039:        import javax.swing.event.*;
0040:        import javax.swing.filechooser.*;
0041:        import javax.swing.filechooser.FileFilter;
0042:
0043:        import com.sun.tools.jconsole.JConsoleContext;
0044:        import com.sun.tools.jconsole.JConsoleContext.ConnectionState;
0045:
0046:        import static com.sun.tools.jconsole.JConsoleContext.ConnectionState.*;
0047:
0048:        import static sun.tools.jconsole.Formatter.*;
0049:        import static sun.tools.jconsole.ProxyClient.*;
0050:        import static sun.tools.jconsole.Resources.*;
0051:        import static sun.tools.jconsole.Utilities.*;
0052:
0053:        @SuppressWarnings("serial")
0054:        public class Plotter extends JComponent implements  Accessible,
0055:                ActionListener, PropertyChangeListener {
0056:
0057:            public static enum Unit {
0058:                NONE, BYTES, PERCENT
0059:            }
0060:
0061:            static final String[] rangeNames = { Resources.getText(" 1 min"),
0062:                    Resources.getText(" 5 min"), Resources.getText("10 min"),
0063:                    Resources.getText("30 min"), Resources.getText(" 1 hour"),
0064:                    Resources.getText(" 2 hours"),
0065:                    Resources.getText(" 3 hours"),
0066:                    Resources.getText(" 6 hours"),
0067:                    Resources.getText("12 hours"), Resources.getText(" 1 day"),
0068:                    Resources.getText(" 7 days"),
0069:                    Resources.getText(" 1 month"),
0070:                    Resources.getText(" 3 months"),
0071:                    Resources.getText(" 6 months"),
0072:                    Resources.getText(" 1 year"), Resources.getText("All") };
0073:
0074:            static final int[] rangeValues = { 1, 5, 10, 30, 1 * 60, 2 * 60,
0075:                    3 * 60, 6 * 60, 12 * 60, 1 * 24 * 60, 7 * 24 * 60,
0076:                    1 * 31 * 24 * 60, 3 * 31 * 24 * 60, 6 * 31 * 24 * 60,
0077:                    366 * 24 * 60, -1 };
0078:
0079:            final static long SECOND = 1000;
0080:            final static long MINUTE = 60 * SECOND;
0081:            final static long HOUR = 60 * MINUTE;
0082:            final static long DAY = 24 * HOUR;
0083:
0084:            final static Color bgColor = new Color(250, 250, 250);
0085:            final static Color defaultColor = Color.blue.darker();
0086:
0087:            final static int ARRAY_SIZE_INCREMENT = 4000;
0088:
0089:            private static Stroke dashedStroke;
0090:
0091:            private TimeStamps times = new TimeStamps();
0092:            private ArrayList<Sequence> seqs = new ArrayList<Sequence>();
0093:            private JPopupMenu popupMenu;
0094:            private JMenu timeRangeMenu;
0095:            private JRadioButtonMenuItem[] menuRBs;
0096:            private JMenuItem saveAsMI;
0097:            private JFileChooser saveFC;
0098:
0099:            private int viewRange = -1; // Minutes (value <= 0 means full range)
0100:            private Unit unit;
0101:            private int decimals;
0102:            private double decimalsMultiplier;
0103:            private Border border = null;
0104:            private Rectangle r = new Rectangle(1, 1, 1, 1);
0105:            private Font smallFont = null;
0106:
0107:            // Initial margins, may be recalculated as needed
0108:            private int topMargin = 10;
0109:            private int bottomMargin = 45;
0110:            private int leftMargin = 65;
0111:            private int rightMargin = 70;
0112:
0113:            public Plotter() {
0114:                this (Unit.NONE, 0);
0115:            }
0116:
0117:            public Plotter(Unit unit) {
0118:                this (unit, 0);
0119:            }
0120:
0121:            // Note: If decimals > 0 then values must be decimally shifted left
0122:            // that many places, i.e. multiplied by Math.pow(10.0, decimals).
0123:            public Plotter(Unit unit, int decimals) {
0124:                setUnit(unit);
0125:                setDecimals(decimals);
0126:
0127:                enableEvents(AWTEvent.MOUSE_EVENT_MASK);
0128:
0129:                addMouseListener(new MouseAdapter() {
0130:                    public void mousePressed(MouseEvent e) {
0131:                        if (getParent() instanceof  PlotterPanel) {
0132:                            getParent().requestFocusInWindow();
0133:                        }
0134:                    }
0135:                });
0136:
0137:            }
0138:
0139:            public void setUnit(Unit unit) {
0140:                this .unit = unit;
0141:            }
0142:
0143:            public void setDecimals(int decimals) {
0144:                this .decimals = decimals;
0145:                this .decimalsMultiplier = Math.pow(10.0, decimals);
0146:            }
0147:
0148:            public void createSequence(String key, String name, Color color,
0149:                    boolean isPlotted) {
0150:                Sequence seq = getSequence(key);
0151:                if (seq == null) {
0152:                    seq = new Sequence(key);
0153:                }
0154:                seq.name = name;
0155:                seq.color = (color != null) ? color : defaultColor;
0156:                seq.isPlotted = isPlotted;
0157:
0158:                seqs.add(seq);
0159:            }
0160:
0161:            public void setUseDashedTransitions(String key, boolean b) {
0162:                Sequence seq = getSequence(key);
0163:                if (seq != null) {
0164:                    seq.transitionStroke = b ? getDashedStroke() : null;
0165:                }
0166:            }
0167:
0168:            public void setIsPlotted(String key, boolean isPlotted) {
0169:                Sequence seq = getSequence(key);
0170:                if (seq != null) {
0171:                    seq.isPlotted = isPlotted;
0172:                }
0173:            }
0174:
0175:            // Note: If decimals > 0 then values must be decimally shifted left
0176:            // that many places, i.e. multiplied by Math.pow(10.0, decimals).
0177:            public synchronized void addValues(long time, long... values) {
0178:                assert (values.length == seqs.size());
0179:                times.add(time);
0180:                for (int i = 0; i < values.length; i++) {
0181:                    seqs.get(i).add(values[i]);
0182:                }
0183:                repaint();
0184:            }
0185:
0186:            private Sequence getSequence(String key) {
0187:                for (Sequence seq : seqs) {
0188:                    if (seq.key.equals(key)) {
0189:                        return seq;
0190:                    }
0191:                }
0192:                return null;
0193:            }
0194:
0195:            /**
0196:             * @return the displayed time range in minutes, or -1 for all data
0197:             */
0198:            public int getViewRange() {
0199:                return viewRange;
0200:            }
0201:
0202:            /**
0203:             * @param minutes the displayed time range in minutes, or -1 to diaplay all data
0204:             */
0205:            public void setViewRange(int minutes) {
0206:                if (minutes != viewRange) {
0207:                    int oldValue = viewRange;
0208:                    viewRange = minutes;
0209:                    /* Do not i18n this string */
0210:                    firePropertyChange("viewRange", oldValue, viewRange);
0211:                    if (popupMenu != null) {
0212:                        for (int i = 0; i < menuRBs.length; i++) {
0213:                            if (rangeValues[i] == viewRange) {
0214:                                menuRBs[i].setSelected(true);
0215:                                break;
0216:                            }
0217:                        }
0218:                    }
0219:                    repaint();
0220:                }
0221:            }
0222:
0223:            public JPopupMenu getComponentPopupMenu() {
0224:                if (popupMenu == null) {
0225:                    popupMenu = new JPopupMenu(Resources.getText("Chart:"));
0226:                    timeRangeMenu = new JMenu(Resources
0227:                            .getText("Plotter.timeRangeMenu"));
0228:                    timeRangeMenu
0229:                            .setMnemonic(getMnemonicInt("Plotter.timeRangeMenu"));
0230:                    popupMenu.add(timeRangeMenu);
0231:                    menuRBs = new JRadioButtonMenuItem[rangeNames.length];
0232:                    ButtonGroup rbGroup = new ButtonGroup();
0233:                    for (int i = 0; i < rangeNames.length; i++) {
0234:                        menuRBs[i] = new JRadioButtonMenuItem(rangeNames[i]);
0235:                        rbGroup.add(menuRBs[i]);
0236:                        menuRBs[i].addActionListener(this );
0237:                        if (viewRange == rangeValues[i]) {
0238:                            menuRBs[i].setSelected(true);
0239:                        }
0240:                        timeRangeMenu.add(menuRBs[i]);
0241:                    }
0242:
0243:                    popupMenu.addSeparator();
0244:
0245:                    saveAsMI = new JMenuItem(getText("Plotter.saveAsMenuItem"));
0246:                    saveAsMI
0247:                            .setMnemonic(getMnemonicInt("Plotter.saveAsMenuItem"));
0248:                    saveAsMI.addActionListener(this );
0249:                    popupMenu.add(saveAsMI);
0250:                }
0251:                return popupMenu;
0252:            }
0253:
0254:            public void actionPerformed(ActionEvent ev) {
0255:                JComponent src = (JComponent) ev.getSource();
0256:                if (src == saveAsMI) {
0257:                    saveAs();
0258:                } else {
0259:                    int index = timeRangeMenu.getPopupMenu().getComponentIndex(
0260:                            src);
0261:                    setViewRange(rangeValues[index]);
0262:                }
0263:            }
0264:
0265:            private void saveAs() {
0266:                if (saveFC == null) {
0267:                    saveFC = new SaveDataFileChooser();
0268:                }
0269:                int ret = saveFC.showSaveDialog(this );
0270:                if (ret == JFileChooser.APPROVE_OPTION) {
0271:                    saveDataToFile(saveFC.getSelectedFile());
0272:                }
0273:            }
0274:
0275:            private void saveDataToFile(File file) {
0276:                try {
0277:                    PrintStream out = new PrintStream(
0278:                            new FileOutputStream(file));
0279:
0280:                    // Print header line
0281:                    out.print("Time");
0282:                    for (Sequence seq : seqs) {
0283:                        out.print("," + seq.name);
0284:                    }
0285:                    out.println();
0286:
0287:                    // Print data lines
0288:                    if (seqs.size() > 0 && seqs.get(0).size > 0) {
0289:                        for (int i = 0; i < seqs.get(0).size; i++) {
0290:                            double excelTime = toExcelTime(times.time(i));
0291:                            out.print(String.format(Locale.ENGLISH, "%.6f",
0292:                                    excelTime));
0293:                            for (Sequence seq : seqs) {
0294:                                out
0295:                                        .print(","
0296:                                                + getFormattedValue(seq
0297:                                                        .value(i), false));
0298:                            }
0299:                            out.println();
0300:                        }
0301:                    }
0302:
0303:                    out.close();
0304:                    JOptionPane.showMessageDialog(this , getText(
0305:                            "FileChooser.savedFile", file.getAbsolutePath(),
0306:                            file.length()));
0307:                } catch (IOException ex) {
0308:                    String msg = ex.getLocalizedMessage();
0309:                    String path = file.getAbsolutePath();
0310:                    if (msg.startsWith(path)) {
0311:                        msg = msg.substring(path.length()).trim();
0312:                    }
0313:                    JOptionPane.showMessageDialog(this , getText(
0314:                            "FileChooser.saveFailed.message", path, msg),
0315:                            getText("FileChooser.saveFailed.title"),
0316:                            JOptionPane.ERROR_MESSAGE);
0317:                }
0318:            }
0319:
0320:            public void paintComponent(Graphics g) {
0321:                super .paintComponent(g);
0322:
0323:                Color oldColor = g.getColor();
0324:                Font oldFont = g.getFont();
0325:                Color fg = getForeground();
0326:                Color bg = getBackground();
0327:                boolean bgIsLight = (bg.getRed() > 200 && bg.getGreen() > 200 && bg
0328:                        .getBlue() > 200);
0329:
0330:                ((Graphics2D) g).setRenderingHint(
0331:                        RenderingHints.KEY_ANTIALIASING,
0332:                        RenderingHints.VALUE_ANTIALIAS_ON);
0333:
0334:                if (smallFont == null) {
0335:                    smallFont = oldFont.deriveFont(9.0F);
0336:                }
0337:
0338:                r.x = leftMargin - 5;
0339:                r.y = topMargin - 8;
0340:                r.width = getWidth() - leftMargin - rightMargin;
0341:                r.height = getHeight() - topMargin - bottomMargin + 16;
0342:
0343:                if (border == null) {
0344:                    // By setting colors here, we avoid recalculating them
0345:                    // over and over.
0346:                    border = new BevelBorder(BevelBorder.LOWERED,
0347:                            getBackground().brighter().brighter(),
0348:                            getBackground().brighter(), getBackground()
0349:                                    .darker().darker(), getBackground()
0350:                                    .darker());
0351:                }
0352:
0353:                border.paintBorder(this , g, r.x, r.y, r.width, r.height);
0354:
0355:                // Fill background color
0356:                g.setColor(bgColor);
0357:                g.fillRect(r.x + 2, r.y + 2, r.width - 4, r.height - 4);
0358:                g.setColor(oldColor);
0359:
0360:                long tMin = Long.MAX_VALUE;
0361:                long tMax = Long.MIN_VALUE;
0362:                long vMin = Long.MAX_VALUE;
0363:                long vMax = 1;
0364:
0365:                int w = getWidth() - rightMargin - leftMargin - 10;
0366:                int h = getHeight() - topMargin - bottomMargin;
0367:
0368:                if (times.size > 1) {
0369:                    tMin = Math.min(tMin, times.time(0));
0370:                    tMax = Math.max(tMax, times.time(times.size - 1));
0371:                }
0372:                long viewRangeMS;
0373:                if (viewRange > 0) {
0374:                    viewRangeMS = viewRange * MINUTE;
0375:                } else {
0376:                    // Display full time range, but no less than a minute
0377:                    viewRangeMS = Math.max(tMax - tMin, 1 * MINUTE);
0378:                }
0379:
0380:                // Calculate min/max values
0381:                for (Sequence seq : seqs) {
0382:                    if (seq.size > 0) {
0383:                        for (int i = 0; i < seq.size; i++) {
0384:                            if (seq.size == 1
0385:                                    || times.time(i) >= tMax - viewRangeMS) {
0386:                                long val = seq.value(i);
0387:                                if (val > Long.MIN_VALUE) {
0388:                                    vMax = Math.max(vMax, val);
0389:                                    vMin = Math.min(vMin, val);
0390:                                }
0391:                            }
0392:                        }
0393:                    } else {
0394:                        vMin = 0L;
0395:                    }
0396:                    if (unit == Unit.BYTES || !seq.isPlotted) {
0397:                        // We'll scale only to the first (main) value set.
0398:                        // TODO: Use a separate property for this.
0399:                        break;
0400:                    }
0401:                }
0402:
0403:                // Normalize scale
0404:                vMax = normalizeMax(vMax);
0405:                if (vMin > 0) {
0406:                    if (vMax / vMin > 4) {
0407:                        vMin = 0;
0408:                    } else {
0409:                        vMin = normalizeMin(vMin);
0410:                    }
0411:                }
0412:
0413:                g.setColor(fg);
0414:
0415:                // Axes
0416:                // Draw vertical axis
0417:                int x = leftMargin - 18;
0418:                int y = topMargin;
0419:                FontMetrics fm = g.getFontMetrics();
0420:
0421:                g.drawLine(x, y, x, y + h);
0422:
0423:                int n = 5;
0424:                if (("" + vMax).startsWith("2")) {
0425:                    n = 4;
0426:                } else if (("" + vMax).startsWith("3")) {
0427:                    n = 6;
0428:                } else if (("" + vMax).startsWith("4")) {
0429:                    n = 4;
0430:                } else if (("" + vMax).startsWith("6")) {
0431:                    n = 6;
0432:                } else if (("" + vMax).startsWith("7")) {
0433:                    n = 7;
0434:                } else if (("" + vMax).startsWith("8")) {
0435:                    n = 8;
0436:                } else if (("" + vMax).startsWith("9")) {
0437:                    n = 3;
0438:                }
0439:
0440:                // Ticks
0441:                ArrayList<Long> tickValues = new ArrayList<Long>();
0442:                tickValues.add(vMin);
0443:                for (int i = 0; i < n; i++) {
0444:                    long v = i * vMax / n;
0445:                    if (v > vMin) {
0446:                        tickValues.add(v);
0447:                    }
0448:                }
0449:                tickValues.add(vMax);
0450:                n = tickValues.size();
0451:
0452:                String[] tickStrings = new String[n];
0453:                for (int i = 0; i < n; i++) {
0454:                    long v = tickValues.get(i);
0455:                    tickStrings[i] = getSizeString(v, vMax);
0456:                }
0457:
0458:                // Trim trailing decimal zeroes.
0459:                if (decimals > 0) {
0460:                    boolean trimLast = true;
0461:                    boolean removedDecimalPoint = false;
0462:                    do {
0463:                        for (String str : tickStrings) {
0464:                            if (!(str.endsWith("0") || str.endsWith("."))) {
0465:                                trimLast = false;
0466:                                break;
0467:                            }
0468:                        }
0469:                        if (trimLast) {
0470:                            if (tickStrings[0].endsWith(".")) {
0471:                                removedDecimalPoint = true;
0472:                            }
0473:                            for (int i = 0; i < n; i++) {
0474:                                String str = tickStrings[i];
0475:                                tickStrings[i] = str.substring(0,
0476:                                        str.length() - 1);
0477:                            }
0478:                        }
0479:                    } while (trimLast && !removedDecimalPoint);
0480:                }
0481:
0482:                // Draw ticks
0483:                int lastY = Integer.MAX_VALUE;
0484:                for (int i = 0; i < n; i++) {
0485:                    long v = tickValues.get(i);
0486:                    y = topMargin + h - (int) (h * (v - vMin) / (vMax - vMin));
0487:                    g.drawLine(x - 2, y, x + 2, y);
0488:                    String s = tickStrings[i];
0489:                    if (unit == Unit.PERCENT) {
0490:                        s += "%";
0491:                    }
0492:                    int sx = x - 6 - fm.stringWidth(s);
0493:                    if (y < lastY - 13) {
0494:                        if (checkLeftMargin(sx)) {
0495:                            // Wait for next repaint
0496:                            return;
0497:                        }
0498:                        g.drawString(s, sx, y + 4);
0499:                    }
0500:                    // Draw horizontal grid line
0501:                    g.setColor(Color.lightGray);
0502:                    g.drawLine(r.x + 4, y, r.x + r.width - 4, y);
0503:                    g.setColor(fg);
0504:                    lastY = y;
0505:                }
0506:
0507:                // Draw horizontal axis
0508:                x = leftMargin;
0509:                y = topMargin + h + 15;
0510:                g.drawLine(x, y, x + w, y);
0511:
0512:                long t1 = tMax;
0513:                if (t1 <= 0L) {
0514:                    // No data yet, so draw current time
0515:                    t1 = System.currentTimeMillis();
0516:                }
0517:                long tz = timeDF.getTimeZone().getOffset(t1);
0518:                long tickInterval = calculateTickInterval(w, 40, viewRangeMS);
0519:                if (tickInterval > 3 * HOUR) {
0520:                    tickInterval = calculateTickInterval(w, 80, viewRangeMS);
0521:                }
0522:                long t0 = tickInterval - (t1 - viewRangeMS + tz) % tickInterval;
0523:                while (t0 < viewRangeMS) {
0524:                    x = leftMargin + (int) (w * t0 / viewRangeMS);
0525:                    g.drawLine(x, y - 2, x, y + 2);
0526:
0527:                    long t = t1 - viewRangeMS + t0;
0528:                    String str = formatClockTime(t);
0529:                    g.drawString(str, x, y + 16);
0530:                    //if (tickInterval > (1 * HOUR) && t % (1 * DAY) == 0) {
0531:                    if ((t + tz) % (1 * DAY) == 0) {
0532:                        str = formatDate(t);
0533:                        g.drawString(str, x, y + 27);
0534:                    }
0535:                    // Draw vertical grid line
0536:                    g.setColor(Color.lightGray);
0537:                    g.drawLine(x, topMargin, x, topMargin + h);
0538:                    g.setColor(fg);
0539:                    t0 += tickInterval;
0540:                }
0541:
0542:                // Plot values
0543:                int start = 0;
0544:                int nValues = 0;
0545:                int nLists = seqs.size();
0546:                if (nLists > 0) {
0547:                    nValues = seqs.get(0).size;
0548:                }
0549:                if (nValues == 0) {
0550:                    g.setColor(oldColor);
0551:                    return;
0552:                } else {
0553:                    Sequence seq = seqs.get(0);
0554:                    // Find starting point
0555:                    for (int p = 0; p < seq.size; p++) {
0556:                        if (times.time(p) >= tMax - viewRangeMS) {
0557:                            start = p;
0558:                            break;
0559:                        }
0560:                    }
0561:                }
0562:
0563:                //Optimization: collapse plot of more than four values per pixel
0564:                int pointsPerPixel = (nValues - start) / w;
0565:                if (pointsPerPixel < 4) {
0566:                    pointsPerPixel = 1;
0567:                }
0568:
0569:                // Draw graphs
0570:                // Loop backwards over sequences because the first needs to be painted on top
0571:                for (int i = nLists - 1; i >= 0; i--) {
0572:                    int x0 = leftMargin;
0573:                    int y0 = topMargin + h + 1;
0574:
0575:                    Sequence seq = seqs.get(i);
0576:                    if (seq.isPlotted && seq.size > 0) {
0577:                        // Paint twice, with white and with color
0578:                        for (int pass = 0; pass < 2; pass++) {
0579:                            g.setColor((pass == 0) ? Color.white : seq.color);
0580:                            int x1 = -1;
0581:                            long v1 = -1;
0582:                            for (int p = start; p < nValues; p += pointsPerPixel) {
0583:                                // Make sure we get the last value
0584:                                if (pointsPerPixel > 1
0585:                                        && p >= nValues - pointsPerPixel) {
0586:                                    p = nValues - 1;
0587:                                }
0588:                                int x2 = (int) (w
0589:                                        * (times.time(p) - (t1 - viewRangeMS)) / viewRangeMS);
0590:                                long v2 = seq.value(p);
0591:                                if (v2 >= vMin && v2 <= vMax) {
0592:                                    int y2 = (int) (h * (v2 - vMin) / (vMax - vMin));
0593:                                    if (x1 >= 0 && v1 >= vMin && v1 <= vMax) {
0594:                                        int y1 = (int) (h * (v1 - vMin) / (vMax - vMin));
0595:
0596:                                        if (y1 == y2) {
0597:                                            // fillrect is much faster
0598:                                            g.fillRect(x0 + x1, y0 - y1 - pass,
0599:                                                    x2 - x1, 1);
0600:                                        } else {
0601:                                            Graphics2D g2d = (Graphics2D) g;
0602:                                            Stroke oldStroke = null;
0603:                                            if (seq.transitionStroke != null) {
0604:                                                oldStroke = g2d.getStroke();
0605:                                                g2d
0606:                                                        .setStroke(seq.transitionStroke);
0607:                                            }
0608:                                            g.drawLine(x0 + x1, y0 - y1 - pass,
0609:                                                    x0 + x2, y0 - y2 - pass);
0610:                                            if (oldStroke != null) {
0611:                                                g2d.setStroke(oldStroke);
0612:                                            }
0613:                                        }
0614:                                    }
0615:                                }
0616:                                x1 = x2;
0617:                                v1 = v2;
0618:                            }
0619:                        }
0620:
0621:                        // Current value
0622:                        long v = seq.value(seq.size - 1);
0623:                        if (v >= vMin && v <= vMax) {
0624:                            if (bgIsLight) {
0625:                                g.setColor(seq.color);
0626:                            } else {
0627:                                g.setColor(fg);
0628:                            }
0629:                            x = r.x + r.width + 2;
0630:                            y = topMargin + h
0631:                                    - (int) (h * (v - vMin) / (vMax - vMin));
0632:                            // a small triangle/arrow
0633:                            g.fillPolygon(new int[] { x + 2, x + 6, x + 6 },
0634:                                    new int[] { y, y + 3, y - 3 }, 3);
0635:                        }
0636:                        g.setColor(fg);
0637:                    }
0638:                }
0639:
0640:                int[] valueStringSlots = new int[nLists];
0641:                for (int i = 0; i < nLists; i++)
0642:                    valueStringSlots[i] = -1;
0643:                for (int i = 0; i < nLists; i++) {
0644:                    Sequence seq = seqs.get(i);
0645:                    if (seq.isPlotted && seq.size > 0) {
0646:                        // Draw current value
0647:
0648:                        // TODO: collapse values if pointsPerPixel >= 4
0649:
0650:                        long v = seq.value(seq.size - 1);
0651:                        if (v >= vMin && v <= vMax) {
0652:                            x = r.x + r.width + 2;
0653:                            y = topMargin + h
0654:                                    - (int) (h * (v - vMin) / (vMax - vMin));
0655:                            int y2 = getValueStringSlot(valueStringSlots, y,
0656:                                    2 * 10, i);
0657:                            g.setFont(smallFont);
0658:                            if (bgIsLight) {
0659:                                g.setColor(seq.color);
0660:                            } else {
0661:                                g.setColor(fg);
0662:                            }
0663:                            String curValue = getFormattedValue(v, true);
0664:                            if (unit == Unit.PERCENT) {
0665:                                curValue += "%";
0666:                            }
0667:                            int valWidth = fm.stringWidth(curValue);
0668:                            String legend = seq.name;
0669:                            int legendWidth = fm.stringWidth(legend);
0670:                            if (checkRightMargin(valWidth)
0671:                                    || checkRightMargin(legendWidth)) {
0672:                                // Wait for next repaint
0673:                                return;
0674:                            }
0675:                            g.drawString(legend, x + 17, Math.min(
0676:                                    topMargin + h, y2 + 3 - 10));
0677:                            g.drawString(curValue, x + 17, Math.min(topMargin
0678:                                    + h + 10, y2 + 3));
0679:
0680:                            // Maybe draw a short line to value
0681:                            if (y2 > y + 3) {
0682:                                g.drawLine(x + 9, y + 2, x + 14, y2);
0683:                            } else if (y2 < y - 3) {
0684:                                g.drawLine(x + 9, y - 2, x + 14, y2);
0685:                            }
0686:                        }
0687:                        g.setFont(oldFont);
0688:                        g.setColor(fg);
0689:
0690:                    }
0691:                }
0692:                g.setColor(oldColor);
0693:            }
0694:
0695:            private boolean checkLeftMargin(int x) {
0696:                // Make sure leftMargin has at least 2 pixels over
0697:                if (x < 2) {
0698:                    leftMargin += (2 - x);
0699:                    // Repaint from top (above any cell renderers)
0700:                    SwingUtilities.getWindowAncestor(this ).repaint();
0701:                    return true;
0702:                }
0703:                return false;
0704:            }
0705:
0706:            private boolean checkRightMargin(int w) {
0707:                // Make sure rightMargin has at least 2 pixels over
0708:                if (w + 2 > rightMargin) {
0709:                    rightMargin = (w + 2);
0710:                    // Repaint from top (above any cell renderers)
0711:                    SwingUtilities.getWindowAncestor(this ).repaint();
0712:                    return true;
0713:                }
0714:                return false;
0715:            }
0716:
0717:            private int getValueStringSlot(int[] slots, int y, int h, int i) {
0718:                for (int s = 0; s < slots.length; s++) {
0719:                    if (slots[s] >= y && slots[s] < y + h) {
0720:                        // collide below us
0721:                        if (slots[s] > h) {
0722:                            return getValueStringSlot(slots, slots[s] - h, h, i);
0723:                        } else {
0724:                            return getValueStringSlot(slots, slots[s] + h, h, i);
0725:                        }
0726:                    } else if (y >= h && slots[s] > y - h && slots[s] < y) {
0727:                        // collide above us
0728:                        return getValueStringSlot(slots, slots[s] + h, h, i);
0729:                    }
0730:                }
0731:                slots[i] = y;
0732:                return y;
0733:            }
0734:
0735:            private long calculateTickInterval(int w, int hGap, long viewRangeMS) {
0736:                long tickInterval = viewRangeMS * hGap / w;
0737:                if (tickInterval < 1 * MINUTE) {
0738:                    tickInterval = 1 * MINUTE;
0739:                } else if (tickInterval < 5 * MINUTE) {
0740:                    tickInterval = 5 * MINUTE;
0741:                } else if (tickInterval < 10 * MINUTE) {
0742:                    tickInterval = 10 * MINUTE;
0743:                } else if (tickInterval < 30 * MINUTE) {
0744:                    tickInterval = 30 * MINUTE;
0745:                } else if (tickInterval < 1 * HOUR) {
0746:                    tickInterval = 1 * HOUR;
0747:                } else if (tickInterval < 3 * HOUR) {
0748:                    tickInterval = 3 * HOUR;
0749:                } else if (tickInterval < 6 * HOUR) {
0750:                    tickInterval = 6 * HOUR;
0751:                } else if (tickInterval < 12 * HOUR) {
0752:                    tickInterval = 12 * HOUR;
0753:                } else if (tickInterval < 1 * DAY) {
0754:                    tickInterval = 1 * DAY;
0755:                } else {
0756:                    tickInterval = normalizeMax(tickInterval / DAY) * DAY;
0757:                }
0758:                return tickInterval;
0759:            }
0760:
0761:            private long normalizeMin(long l) {
0762:                int exp = (int) Math.log10((double) l);
0763:                long multiple = (long) Math.pow(10.0, exp);
0764:                int i = (int) (l / multiple);
0765:                return i * multiple;
0766:            }
0767:
0768:            private long normalizeMax(long l) {
0769:                int exp = (int) Math.log10((double) l);
0770:                long multiple = (long) Math.pow(10.0, exp);
0771:                int i = (int) (l / multiple);
0772:                l = (i + 1) * multiple;
0773:                return l;
0774:            }
0775:
0776:            private String getFormattedValue(long v, boolean groupDigits) {
0777:                String str;
0778:                String fmt = "%";
0779:                if (groupDigits) {
0780:                    fmt += ",";
0781:                }
0782:                if (decimals > 0) {
0783:                    fmt += "." + decimals + "f";
0784:                    str = String.format(fmt, v / decimalsMultiplier);
0785:                } else {
0786:                    fmt += "d";
0787:                    str = String.format(fmt, v);
0788:                }
0789:                return str;
0790:            }
0791:
0792:            private String getSizeString(long v, long vMax) {
0793:                String s;
0794:
0795:                if (unit == Unit.BYTES && decimals == 0) {
0796:                    s = formatBytes(v, vMax);
0797:                } else {
0798:                    s = getFormattedValue(v, true);
0799:                }
0800:                return s;
0801:            }
0802:
0803:            private static synchronized Stroke getDashedStroke() {
0804:                if (dashedStroke == null) {
0805:                    dashedStroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT,
0806:                            BasicStroke.JOIN_MITER, 10.0f, new float[] { 2.0f,
0807:                                    3.0f }, 0.0f);
0808:                }
0809:                return dashedStroke;
0810:            }
0811:
0812:            private static Object extendArray(Object a1) {
0813:                int n = Array.getLength(a1);
0814:                Object a2 = Array.newInstance(a1.getClass().getComponentType(),
0815:                        n + ARRAY_SIZE_INCREMENT);
0816:                System.arraycopy(a1, 0, a2, 0, n);
0817:                return a2;
0818:            }
0819:
0820:            private static class TimeStamps {
0821:                // Time stamps (long) are split into offsets (long) and a
0822:                // series of times from the offsets (int). A new offset is
0823:                // stored when the the time value doesn't fit in an int
0824:                // (approx every 24 days).  An array of indices is used to
0825:                // define the starting point for each offset in the times
0826:                // array.
0827:                long[] offsets = new long[0];
0828:                int[] indices = new int[0];
0829:                int[] rtimes = new int[ARRAY_SIZE_INCREMENT];
0830:
0831:                // Number of stored timestamps
0832:                int size = 0;
0833:
0834:                /**
0835:                 * Returns the time stamp for index i
0836:                 */
0837:                public long time(int i) {
0838:                    long offset = 0;
0839:                    for (int j = indices.length - 1; j >= 0; j--) {
0840:                        if (i >= indices[j]) {
0841:                            offset = offsets[j];
0842:                            break;
0843:                        }
0844:                    }
0845:                    return offset + rtimes[i];
0846:                }
0847:
0848:                public void add(long time) {
0849:                    // May need to store a new time offset
0850:                    int n = offsets.length;
0851:                    if (n == 0 || time - offsets[n - 1] > Integer.MAX_VALUE) {
0852:                        // Grow offset and indices arrays and store new offset
0853:                        offsets = Arrays.copyOf(offsets, n + 1);
0854:                        offsets[n] = time;
0855:                        indices = Arrays.copyOf(indices, n + 1);
0856:                        indices[n] = size;
0857:                    }
0858:
0859:                    // May need to extend the array size
0860:                    if (rtimes.length == size) {
0861:                        rtimes = (int[]) extendArray(rtimes);
0862:                    }
0863:
0864:                    // Store the time
0865:                    rtimes[size] = (int) (time - offsets[offsets.length - 1]);
0866:                    size++;
0867:                }
0868:            }
0869:
0870:            private static class Sequence {
0871:                String key;
0872:                String name;
0873:                Color color;
0874:                boolean isPlotted;
0875:                Stroke transitionStroke = null;
0876:
0877:                // Values are stored in an int[] if all values will fit,
0878:                // otherwise in a long[]. An int can represent up to 2 GB.
0879:                // Use a random start size, so all arrays won't need to
0880:                // be grown during the same update interval
0881:                Object values = new byte[ARRAY_SIZE_INCREMENT
0882:                        + (int) (Math.random() * 100)];
0883:
0884:                // Number of stored values
0885:                int size = 0;
0886:
0887:                public Sequence(String key) {
0888:                    this .key = key;
0889:                }
0890:
0891:                /**
0892:                 * Returns the value at index i
0893:                 */
0894:                public long value(int i) {
0895:                    return Array.getLong(values, i);
0896:                }
0897:
0898:                public void add(long value) {
0899:                    // May need to switch to a larger array type
0900:                    if ((values instanceof  byte[] || values instanceof  short[] || values instanceof  int[])
0901:                            && value > Integer.MAX_VALUE) {
0902:                        long[] la = new long[Array.getLength(values)];
0903:                        for (int i = 0; i < size; i++) {
0904:                            la[i] = Array.getLong(values, i);
0905:                        }
0906:                        values = la;
0907:                    } else if ((values instanceof  byte[] || values instanceof  short[])
0908:                            && value > Short.MAX_VALUE) {
0909:                        int[] ia = new int[Array.getLength(values)];
0910:                        for (int i = 0; i < size; i++) {
0911:                            ia[i] = Array.getInt(values, i);
0912:                        }
0913:                        values = ia;
0914:                    } else if (values instanceof  byte[]
0915:                            && value > Byte.MAX_VALUE) {
0916:                        short[] sa = new short[Array.getLength(values)];
0917:                        for (int i = 0; i < size; i++) {
0918:                            sa[i] = Array.getShort(values, i);
0919:                        }
0920:                        values = sa;
0921:                    }
0922:
0923:                    // May need to extend the array size
0924:                    if (Array.getLength(values) == size) {
0925:                        values = extendArray(values);
0926:                    }
0927:
0928:                    // Store the value
0929:                    if (values instanceof  long[]) {
0930:                        ((long[]) values)[size] = value;
0931:                    } else if (values instanceof  int[]) {
0932:                        ((int[]) values)[size] = (int) value;
0933:                    } else if (values instanceof  short[]) {
0934:                        ((short[]) values)[size] = (short) value;
0935:                    } else {
0936:                        ((byte[]) values)[size] = (byte) value;
0937:                    }
0938:                    size++;
0939:                }
0940:            }
0941:
0942:            // Can be overridden by subclasses
0943:            long getValue() {
0944:                return 0;
0945:            }
0946:
0947:            long getLastTimeStamp() {
0948:                return times.time(times.size - 1);
0949:            }
0950:
0951:            long getLastValue(String key) {
0952:                Sequence seq = getSequence(key);
0953:                return (seq != null && seq.size > 0) ? seq.value(seq.size - 1)
0954:                        : 0L;
0955:            }
0956:
0957:            // Called on EDT
0958:            public void propertyChange(PropertyChangeEvent ev) {
0959:                String prop = ev.getPropertyName();
0960:
0961:                if (prop == JConsoleContext.CONNECTION_STATE_PROPERTY) {
0962:                    ConnectionState newState = (ConnectionState) ev
0963:                            .getNewValue();
0964:
0965:                    switch (newState) {
0966:                    case DISCONNECTED:
0967:                        synchronized (this ) {
0968:                            long time = System.currentTimeMillis();
0969:                            times.add(time);
0970:                            for (Sequence seq : seqs) {
0971:                                seq.add(Long.MIN_VALUE);
0972:                            }
0973:                        }
0974:                        break;
0975:                    }
0976:                }
0977:            }
0978:
0979:            private static class SaveDataFileChooser extends JFileChooser {
0980:                SaveDataFileChooser() {
0981:                    setFileFilter(new FileNameExtensionFilter("CSV file", "csv"));
0982:                }
0983:
0984:                public void approveSelection() {
0985:                    File file = getSelectedFile();
0986:                    if (file != null) {
0987:                        FileFilter filter = getFileFilter();
0988:                        if (filter != null
0989:                                && filter instanceof  FileNameExtensionFilter) {
0990:                            String[] extensions = ((FileNameExtensionFilter) filter)
0991:                                    .getExtensions();
0992:
0993:                            boolean goodExt = false;
0994:                            for (String ext : extensions) {
0995:                                if (file.getName().toLowerCase().endsWith(
0996:                                        "." + ext.toLowerCase())) {
0997:                                    goodExt = true;
0998:                                    break;
0999:                                }
1000:                            }
1001:                            if (!goodExt) {
1002:                                file = new File(file.getParent(), file
1003:                                        .getName()
1004:                                        + "." + extensions[0]);
1005:                            }
1006:                        }
1007:
1008:                        if (file.exists()) {
1009:                            String okStr = getText("FileChooser.fileExists.okOption");
1010:                            String cancelStr = getText("FileChooser.fileExists.cancelOption");
1011:                            int ret = JOptionPane.showOptionDialog(this ,
1012:                                    getText("FileChooser.fileExists.message",
1013:                                            file.getName()),
1014:                                    getText("FileChooser.fileExists.title"),
1015:                                    JOptionPane.OK_CANCEL_OPTION,
1016:                                    JOptionPane.WARNING_MESSAGE, null,
1017:                                    new Object[] { okStr, cancelStr }, okStr);
1018:                            if (ret != JOptionPane.OK_OPTION) {
1019:                                return;
1020:                            }
1021:                        }
1022:                        setSelectedFile(file);
1023:                    }
1024:                    super .approveSelection();
1025:                }
1026:            }
1027:
1028:            public AccessibleContext getAccessibleContext() {
1029:                if (accessibleContext == null) {
1030:                    accessibleContext = new AccessiblePlotter();
1031:                }
1032:                return accessibleContext;
1033:            }
1034:
1035:            protected class AccessiblePlotter extends AccessibleJComponent {
1036:                protected AccessiblePlotter() {
1037:                    setAccessibleName(getText("Plotter.accessibleName"));
1038:                }
1039:
1040:                public String getAccessibleName() {
1041:                    String name = super .getAccessibleName();
1042:
1043:                    if (seqs.size() > 0 && seqs.get(0).size > 0) {
1044:                        String keyValueList = "";
1045:                        for (Sequence seq : seqs) {
1046:                            if (seq.isPlotted) {
1047:                                String value = "null";
1048:                                if (seq.size > 0) {
1049:                                    if (unit == Unit.BYTES) {
1050:                                        value = getText("Size Bytes", seq
1051:                                                .value(seq.size - 1));
1052:                                    } else {
1053:                                        value = getFormattedValue(seq
1054:                                                .value(seq.size - 1), false)
1055:                                                + ((unit == Unit.PERCENT) ? "%"
1056:                                                        : "");
1057:                                    }
1058:                                }
1059:                                // Assume format string ends with newline
1060:                                keyValueList += getText(
1061:                                        "Plotter.accessibleName.keyAndValue",
1062:                                        seq.key, value);
1063:                            }
1064:                        }
1065:                        name += "\n" + keyValueList + ".";
1066:                    } else {
1067:                        name += "\n" + getText("Plotter.accessibleName.noData");
1068:                    }
1069:                    return name;
1070:                }
1071:
1072:                public AccessibleRole getAccessibleRole() {
1073:                    return AccessibleRole.CANVAS;
1074:                }
1075:            }
1076:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.