1/* 2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23package org.netbeans.jemmy.explorer; 24 25import java.awt.AWTEvent; 26import java.awt.AWTException; 27import java.awt.BorderLayout; 28import java.awt.Color; 29import java.awt.Component; 30import java.awt.Container; 31import java.awt.Dimension; 32import java.awt.Frame; 33import java.awt.Graphics; 34import java.awt.Rectangle; 35import java.awt.Robot; 36import java.awt.Window; 37import java.awt.event.ActionEvent; 38import java.awt.event.ActionListener; 39import java.awt.event.ComponentEvent; 40import java.awt.event.ComponentListener; 41import java.awt.event.WindowEvent; 42import java.awt.event.WindowListener; 43import java.awt.image.BufferedImage; 44import java.io.ByteArrayOutputStream; 45import java.io.File; 46import java.io.FileInputStream; 47import java.io.FileOutputStream; 48import java.io.IOException; 49import java.io.OutputStream; 50import java.io.OutputStreamWriter; 51import java.io.PrintWriter; 52import java.lang.reflect.Field; 53import java.lang.reflect.InvocationTargetException; 54import java.lang.reflect.Method; 55import java.lang.reflect.Modifier; 56import java.util.Arrays; 57import java.util.Collections; 58import java.util.Comparator; 59import java.util.Hashtable; 60import java.util.Properties; 61import java.util.Vector; 62 63import javax.swing.DefaultListModel; 64import javax.swing.JButton; 65import javax.swing.JCheckBox; 66import javax.swing.JComboBox; 67import javax.swing.JDialog; 68import javax.swing.JFileChooser; 69import javax.swing.JFrame; 70import javax.swing.JLabel; 71import javax.swing.JList; 72import javax.swing.JPanel; 73import javax.swing.JScrollPane; 74import javax.swing.JSplitPane; 75import javax.swing.JTabbedPane; 76import javax.swing.JTable; 77import javax.swing.JTextArea; 78import javax.swing.JTextField; 79import javax.swing.JTree; 80import javax.swing.ListCellRenderer; 81import javax.swing.border.BevelBorder; 82import javax.swing.event.ChangeEvent; 83import javax.swing.event.ChangeListener; 84import javax.swing.event.ListSelectionEvent; 85import javax.swing.event.ListSelectionListener; 86import javax.swing.event.TreeModelListener; 87import javax.swing.event.TreeSelectionEvent; 88import javax.swing.event.TreeSelectionListener; 89import javax.swing.filechooser.FileFilter; 90import javax.swing.table.DefaultTableModel; 91import javax.swing.tree.TreeCellRenderer; 92import javax.swing.tree.TreeModel; 93import javax.swing.tree.TreePath; 94 95import org.netbeans.jemmy.ClassReference; 96import org.netbeans.jemmy.QueueTool; 97import org.netbeans.jemmy.TestOut; 98import org.netbeans.jemmy.operators.Operator; 99import org.netbeans.jemmy.util.Dumper; 100 101/** 102 * An application allowing to explore a Java GUI application. Could be executed 103 * by command: <br> 104 * <pre> 105 * java "application java options" \ 106 * org.netbeans.jemmy.explorer.GUIBrowser \ 107 * "application main class" \ 108 * "application parameters" 109 * </pre> or from java code by {@code GUIBrowser.showBrowser()} method 110 * using. 111 * 112 * @author Alexandre Iline (alexandre.iline@oracle.com) 113 */ 114public class GUIBrowser extends JFrame { 115 116 private static String WINDOWS_TAB = "Subwindows"; 117 private static String COMPONENTS_TAB = "Hierarchy"; 118 private static String PROPERTIES_TAB = "Properties"; 119 private static String REFLECTION_TAB = "Reflection"; 120 private static String EVENT_TAB = "Events"; 121 private static String IMAGE_TAB = "Image"; 122 123 boolean exit; 124 PropertyDialog propDialog; 125 RootNode root; 126 QueueTool qt; 127 JTextField refreshDelay; 128 JTree mainTree; 129 JLabel status; 130 JButton viewButton; 131 JButton expandButton; 132 JSplitPane split; 133 ByteArrayOutputStream dumpData; 134 PrintWriter dumpWriter; 135 136 private GUIBrowser(boolean exitNecessary) { 137 super("GUI Browser"); 138 139 dumpData = new ByteArrayOutputStream(); 140 dumpWriter = new PrintWriter(new OutputStreamWriter(dumpData)); 141 142 exit = exitNecessary; 143 propDialog = new PropertyDialog(this); 144 qt = new QueueTool(); 145 qt.setOutput(TestOut.getNullOutput()); 146 root = new RootNode(); 147 148 mainTree = new JTree(root.getWindowModel()); 149 mainTree.setCellRenderer(new WindowRenderer()); 150 mainTree.setEditable(false); 151 152 refreshDelay = new JTextField(3); 153 refreshDelay.setText("0"); 154 155 viewButton = new JButton("View"); 156 viewButton.setEnabled(false); 157 viewButton.addActionListener(new ActionListener() { 158 @Override 159 public void actionPerformed(ActionEvent e) { 160 new ComponentBrowser(getOwnr(), 161 (ComponentNode) mainTree.getSelectionPath(). 162 getLastPathComponent()). 163 setVisible(true); 164 } 165 }); 166 167 expandButton = new JButton("Expand All"); 168 expandButton.setEnabled(false); 169 expandButton.addActionListener(new ActionListener() { 170 @Override 171 public void actionPerformed(ActionEvent e) { 172 expandAll(mainTree, 173 mainTree.getSelectionPath()); 174 } 175 }); 176 177 JButton refreshButton = new JButton("Reload in ..."); 178 refreshButton.addActionListener(new ActionListener() { 179 @Override 180 public void actionPerformed(ActionEvent e) { 181 reload(Integer.parseInt(refreshDelay.getText())); 182 } 183 }); 184 185 JButton dumpButton = new JButton("Dump"); 186 dumpButton.addActionListener(new ActionListener() { 187 @Override 188 public void actionPerformed(ActionEvent e) { 189 JFileChooser chooser 190 = new JFileChooser(System.getProperty("user.home")); 191 chooser.addChoosableFileFilter(new FileFilter() { 192 @Override 193 public boolean accept(File f) { 194 return f.getName().endsWith(".xml"); 195 } 196 197 @Override 198 public String getDescription() { 199 return "xml files"; 200 } 201 202 @Override 203 public String toString() { 204 return "dumpButton.ActionListener{description = " + getDescription() + '}'; 205 } 206 }); 207 chooser.showSaveDialog(GUIBrowser.this); 208 try { 209 File file = chooser.getSelectedFile(); 210 try (OutputStream output = new FileOutputStream(file)) { 211 output.write(dumpData.toByteArray()); 212 } 213 } catch (IOException ee) { 214 ee.printStackTrace(); 215 } 216 } 217 }); 218 219 JPanel refreshPane = new JPanel(); 220 refreshPane.add(viewButton); 221 refreshPane.add(expandButton); 222 refreshPane.add(new JLabel("")); 223 refreshPane.add(new JLabel("")); 224 refreshPane.add(new JLabel("")); 225 refreshPane.add(new JLabel("")); 226 refreshPane.add(new JLabel("")); 227 refreshPane.add(new JLabel("")); 228 refreshPane.add(refreshButton); 229 refreshPane.add(refreshDelay); 230 refreshPane.add(new JLabel("seconds ")); 231 refreshPane.add(dumpButton); 232 233 split = createUnderPane(mainTree); 234 235 JPanel nonStatusPane = new JPanel(); 236 nonStatusPane.setLayout(new BorderLayout()); 237 nonStatusPane.add(refreshPane, BorderLayout.SOUTH); 238 nonStatusPane.add(split, BorderLayout.CENTER); 239 240 split.setDividerLocation(0.8); 241 242 status = new JLabel("Reloaded"); 243 244 JPanel statusPane = new JPanel(); 245 statusPane.setLayout(new BorderLayout()); 246 statusPane.add(status, BorderLayout.CENTER); 247 statusPane.setBorder(new BevelBorder(BevelBorder.LOWERED)); 248 249 JPanel bottomPane = new JPanel(); 250 bottomPane.setLayout(new BorderLayout()); 251 bottomPane.add(statusPane, BorderLayout.NORTH); 252 bottomPane.add(statusPane, BorderLayout.CENTER); 253 254 getContentPane().setLayout(new BorderLayout()); 255 getContentPane().add(bottomPane, BorderLayout.SOUTH); 256 getContentPane().add(nonStatusPane, BorderLayout.CENTER); 257 258 Component[] cpss = {viewButton, expandButton}; 259 mainTree.addTreeSelectionListener(new SelectionManager(cpss)); 260 261 addWindowListener(new WindowListener() { 262 @Override 263 public void windowActivated(WindowEvent e) { 264 } 265 266 @Override 267 public void windowClosed(WindowEvent e) { 268 setVisible(false); 269 if (exit) { 270 System.exit(0); 271 } 272 } 273 274 @Override 275 public void windowClosing(WindowEvent e) { 276 } 277 278 @Override 279 public void windowDeactivated(WindowEvent e) { 280 } 281 282 @Override 283 public void windowDeiconified(WindowEvent e) { 284 } 285 286 @Override 287 public void windowIconified(WindowEvent e) { 288 } 289 290 @Override 291 public void windowOpened(WindowEvent e) { 292 } 293 }); 294 addComponentListener(new ComponentListener() { 295 @Override 296 public void componentHidden(ComponentEvent e) { 297 } 298 299 @Override 300 public void componentMoved(ComponentEvent e) { 301 } 302 303 @Override 304 public void componentResized(ComponentEvent e) { 305 split.setDividerLocation(0.8); 306 } 307 308 @Override 309 public void componentShown(ComponentEvent e) { 310 } 311 }); 312 313 setSize(800, 400); 314 } 315 316 boolean shown = false; 317 318 @Override 319 @Deprecated 320 public void show() { 321 super.show(); 322 viewButton.setEnabled(false); 323 if (!shown) { 324 split.setDividerLocation(0.8); 325 shown = true; 326 } 327 } 328 329 /** 330 * Specifies a status text. 331 * 332 * @param st a status text. 333 */ 334 public void setStatus(String st) { 335 status.setText(st); 336 } 337 338 /** 339 * Method to invoke GUIBrowser from java code. 340 */ 341 public static void showBrowser() { 342 showBrowser(new String[0], false); 343 } 344 345 /** 346 * Method to invoke GUIBrowser as java application. 347 * 348 * @param argv Argument array. If not empty, first element should be<br> 349 * main class of an aplication to be browsed.<br> 350 * Other elements are application parameters. 351 */ 352 public static void main(String[] argv) { 353 showBrowser(argv, true); 354 } 355 356 private static void showBrowser(String[] argv, boolean exitNecessary) { 357 if (argv.length >= 1) { 358 String[] newArgv = new String[argv.length - 1]; 359 System.arraycopy(argv, 1, newArgv, 0, argv.length - 1); 360 try { 361 new ClassReference(argv[0]).startApplication(newArgv); 362 } catch (ClassNotFoundException 363 | InvocationTargetException 364 | NoSuchMethodException e) { 365 e.printStackTrace(); 366 return; 367 } 368 } 369 new GUIBrowser(exitNecessary).show(); 370 } 371 372 private void reload(final int delay) { 373 viewButton.setEnabled(false); 374 expandButton.setEnabled(false); 375 new Thread(new Runnable() { 376 @Override 377 public void run() { 378 try { 379 for (int i = delay - 1; i >= 0; i--) { 380 setStatus("Reloading after " + Integer.toString(i) + " second"); 381 Thread.sleep(1000); 382 } 383 setStatus("Reloading ..."); 384 Dumper.dumpAll(dumpWriter); 385 //qt.lock(); 386 root = new RootNode(); 387 //qt.unlock(); 388 mainTree.setModel(root.getWindowModel()); 389 setStatus("Reloaded"); 390 } catch (InterruptedException ignored) { 391 } 392 } 393 }).start(); 394 } 395 396 private JFrame getOwnr() { 397 return this; 398 } 399 400 private class ClassNode { 401 402 Class<?> clzz; 403 404 protected ClassNode() { 405 clzz = null; 406 } 407 408 public ClassNode(Class<?> clzz) { 409 this.clzz = clzz; 410 } 411 412 public ClassNode[] getSuperClasses() { 413 int count = 0; 414 Class<?> parent = clzz; 415 while ((parent = parent.getSuperclass()) != null) { 416 count++; 417 } 418 Class<?>[] interfaces = clzz.getInterfaces(); 419 ClassNode[] result = new ClassNode[count + interfaces.length + 1]; 420 result[0] = new SuperClassNode(clzz); 421 count = 1; 422 parent = clzz; 423 while ((parent = parent.getSuperclass()) != null) { 424 result[count] = new SuperClassNode(parent); 425 count++; 426 } 427 for (int i = count; i < count + interfaces.length; i++) { 428 result[i] = new InterfaceNode(interfaces[i - count]); 429 } 430 return result; 431 } 432 433 public String toString() { 434 if (clzz.isArray()) { 435 return clzz.getComponentType().getName() + "[]"; 436 } else { 437 return clzz.getName(); 438 } 439 } 440 441 public TreeModel getMethodsModel() { 442 return new ClassModel(this); 443 } 444 445 public ClassNode[] getSubNodes() { 446 Vector<ClassNode> res = new Vector<>(); 447 Field[] fields = clzz.getFields(); 448 Arrays.sort(fields, new Comparator<Field>() { 449 @Override 450 public int compare(Field f1, Field f2) { 451 return f1.getName().compareTo(f2.getName()); 452 } 453 }); 454 Method[] mtds = clzz.getMethods(); 455 Arrays.sort(mtds, new Comparator<Method>() { 456 @Override 457 public int compare(Method m1, Method m2) { 458 return m1.getName().compareTo(m2.getName()); 459 } 460 }); 461 for (Field field : fields) { 462 if (field.getDeclaringClass().getName().equals(clzz.getName())) { 463 res.add(new FieldNode(field)); 464 } 465 } 466 for (Method mtd : mtds) { 467 if (mtd.getDeclaringClass().getName().equals(clzz.getName())) { 468 res.add(new MethodNode(mtd)); 469 } 470 } 471 ClassNode[] result = new ClassNode[res.size()]; 472 for (int i = 0; i < result.length; i++) { 473 result[i] = res.get(i); 474 } 475 return result; 476 } 477 } 478 479 private class SuperClassNode extends ClassNode { 480 481 public SuperClassNode(Class<?> clzz) { 482 super(clzz); 483 } 484 485 public String toString() { 486 return "Class: " + super.toString(); 487 } 488 } 489 490 private class InterfaceNode extends ClassNode { 491 492 public InterfaceNode(Class<?> clzz) { 493 super(clzz); 494 } 495 496 public String toString() { 497 return "Interfac: " + super.toString(); 498 } 499 } 500 501 private class FieldNode extends ClassNode { 502 503 Field field; 504 505 public FieldNode(Field fld) { 506 super(fld.getType()); 507 field = fld; 508 } 509 510 public String toString() { 511 return ("Field: " 512 + Modifier.toString(field.getModifiers()) + " " 513 + super.toString() + " " 514 + field.getName()); 515 } 516 } 517 518 private class MethodNode extends ClassNode { 519 520 Method method; 521 522 public MethodNode(Method mtd) { 523 super(mtd.getReturnType()); 524 method = mtd; 525 } 526 527 public String toString() { 528 return ("Method: " 529 + Modifier.toString(method.getModifiers()) + " " 530 + super.toString() + " " 531 + method.getName()); 532 533 } 534 535 public ClassNode[] getParameters() { 536 Class<?>[] ptps = method.getParameterTypes(); 537 ClassNode[] result = new ClassNode[ptps.length]; 538 for (int i = 0; i < ptps.length; i++) { 539 result[i] = new ClassNode(ptps[i]); 540 } 541 return result; 542 } 543 } 544 545 private class ComponentNode extends ClassNode { 546 547 protected Hashtable<String, Object> props; 548 protected String clss = ""; 549 protected String compToString = ""; 550 Component comp; 551 ComponentImageProvider image; 552 protected int x, y, w, h; 553 554 protected ComponentNode() { 555 props = new Hashtable<>(); 556 } 557 558 public ComponentNode(Component comp) { 559 super(comp.getClass()); 560 try { 561 props = Operator.createOperator(comp).getDump(); 562 } catch (Exception e) { 563 props = new Hashtable<>(); 564 } 565 clss = comp.getClass().getName(); 566 compToString = comp.toString(); 567 this.comp = comp; 568 x = comp.getLocationOnScreen().x; 569 y = comp.getLocationOnScreen().y; 570 w = comp.getWidth(); 571 h = comp.getHeight(); 572 } 573 574 public String toString() { 575 return clss; 576 } 577 578 public Hashtable<String, Object> getProperties() { 579 return props; 580 } 581 582 public String getToString() { 583 return compToString; 584 } 585 586 public void setComponentImageProvider(ComponentImageProvider provider) { 587 image = provider; 588 } 589 590 public BufferedImage getImage() { 591 if (image != null) { 592 return image.getImage(x, y, w, h); 593 } else { 594 return null; 595 } 596 } 597 } 598 599 private class ContainerNode extends ComponentNode { 600 601 protected ComponentNode[] comps; 602 603 protected ContainerNode() { 604 super(); 605 comps = new ComponentNode[0]; 606 } 607 608 public ContainerNode(Container comp) { 609 super(comp); 610 Component[] cmps = comp.getComponents(); 611 Vector<ComponentNode> wwns = new Vector<>(); 612 for (Component cmp : cmps) { 613 if (cmp != null && (propDialog.showAll || cmp.isVisible())) { 614 if (cmp instanceof Container) { 615 wwns.add(new ContainerNode((Container) cmp)); 616 } else { 617 wwns.add(new ComponentNode(cmp)); 618 } 619 } 620 } 621 comps = new ComponentNode[wwns.size()]; 622 for (int i = 0; i < wwns.size(); i++) { 623 comps[i] = wwns.get(i); 624 } 625 } 626 627 public ComponentNode[] getComponents() { 628 return comps; 629 } 630 631 public int getComponentIndex(ComponentNode comp) { 632 for (int i = 0; i < comps.length; i++) { 633 if (comps[i].equals(comp)) { 634 return i; 635 } 636 } 637 return -1; 638 } 639 640 @Override 641 public void setComponentImageProvider(ComponentImageProvider provider) { 642 super.setComponentImageProvider(provider); 643 for (ComponentNode comp1 : comps) { 644 comp1.setComponentImageProvider(provider); 645 } 646 } 647 648 public ComponentModel getComponentModel() { 649 return new ComponentModel(this); 650 } 651 } 652 653 private class WindowNode extends ContainerNode { 654 655 protected WindowNode[] wins; 656 String title; 657 658 protected WindowNode() { 659 super(); 660 wins = new WindowNode[0]; 661 title = "All Frames"; 662 clss = ""; 663 } 664 665 public WindowNode(Window win) { 666 super(win); 667 Window[] wns = win.getOwnedWindows(); 668 Vector<WindowNode> wwns = new Vector<>(); 669 for (Window wn : wns) { 670 if (propDialog.showAll || wn.isVisible()) { 671 wwns.add(new WindowNode(wn)); 672 } 673 } 674 wins = new WindowNode[wwns.size()]; 675 for (int i = 0; i < wwns.size(); i++) { 676 wins[i] = wwns.get(i); 677 } 678 title = win.toString(); 679 clss = win.getClass().getName(); 680 BufferedImage image = null; 681 try { 682 image = new Robot(). 683 createScreenCapture(new Rectangle(win.getLocationOnScreen(), 684 win.getSize())); 685 } catch (AWTException e) { 686 e.printStackTrace(); 687 } 688 setComponentImageProvider(new ComponentImageProvider(image, x, y)); 689 } 690 691 public WindowNode[] getWindows() { 692 return wins; 693 } 694 695 public int getWindowIndex(WindowNode node) { 696 for (int i = 0; i < wins.length; i++) { 697 if (wins[i].equals(node)) { 698 return i; 699 } 700 } 701 return -1; 702 } 703 704 public WindowModel getWindowModel() { 705 return new WindowModel(this); 706 } 707 708 public String toString() { 709 return clss + " \"" + title + "\""; 710 } 711 } 712 713 private class RootNode extends WindowNode { 714 715 public RootNode() { 716 super(); 717 Window[] wns = Frame.getFrames(); 718 wins = new WindowNode[wns.length]; 719 int count = 0; 720 for (Window wn1 : wns) { 721 if (propDialog.showAll || wn1.isVisible()) { 722 count++; 723 } 724 } 725 wins = new WindowNode[count]; 726 count = 0; 727 for (Window wn : wns) { 728 if (propDialog.showAll || wn.isVisible()) { 729 wins[count] = new WindowNode(wn); 730 count++; 731 } 732 } 733 } 734 } 735 736 private static class ClassModel implements TreeModel { 737 738 ClassNode clsn; 739 740 ClassModel(ClassNode clsn) { 741 this.clsn = clsn; 742 } 743 744 @Override 745 public void addTreeModelListener(TreeModelListener l) { 746 } 747 748 @Override 749 public Object getChild(Object parent, int index) { 750 if (parent == clsn) { 751 return clsn.getSuperClasses()[index]; 752 } else if (parent instanceof SuperClassNode 753 || parent instanceof InterfaceNode) { 754 return ((ClassNode) parent).getSubNodes()[index]; 755 } else if (parent instanceof MethodNode) { 756 return ((MethodNode) parent).getParameters()[index]; 757 } 758 return null; 759 } 760 761 @Override 762 public int getChildCount(Object parent) { 763 if (parent == clsn) { 764 return clsn.getSuperClasses().length; 765 } else if (parent instanceof SuperClassNode 766 || parent instanceof InterfaceNode) { 767 return ((ClassNode) parent).getSubNodes().length; 768 } else if (parent instanceof MethodNode) { 769 return ((MethodNode) parent).getParameters().length; 770 } 771 return 0; 772 } 773 774 @Override 775 public int getIndexOfChild(Object parent, Object child) { 776 if (parent == clsn 777 || parent instanceof MethodNode 778 || parent instanceof SuperClassNode 779 || parent instanceof InterfaceNode) { 780 Object[] children; 781 if (parent instanceof SuperClassNode 782 || parent instanceof InterfaceNode) { 783 children = ((ClassNode) parent).getSuperClasses(); 784 } else if (parent instanceof MethodNode) { 785 children = ((MethodNode) parent).getParameters(); 786 } else { 787 children = clsn.getSuperClasses(); 788 } 789 for (int i = 0; i < children.length; i++) { 790 if (children.equals(child)) { 791 return i; 792 } 793 } 794 } 795 return 0; 796 } 797 798 @Override 799 public Object getRoot() { 800 return clsn; 801 } 802 803 @Override 804 public boolean isLeaf(Object node) { 805 return getChildCount(node) == 0; 806 } 807 808 @Override 809 public void removeTreeModelListener(TreeModelListener l) { 810 } 811 812 @Override 813 public void valueForPathChanged(TreePath path, Object newValue) { 814 } 815 } 816 817 private static class WindowModel implements TreeModel { 818 819 WindowNode win; 820 821 WindowModel(WindowNode win) { 822 this.win = win; 823 } 824 825 @Override 826 public void addTreeModelListener(TreeModelListener l) { 827 } 828 829 @Override 830 public Object getChild(Object parent, int index) { 831 return ((WindowNode) parent).getWindows()[index]; 832 } 833 834 @Override 835 public int getChildCount(Object parent) { 836 return ((WindowNode) parent).getWindows().length; 837 } 838 839 @Override 840 public int getIndexOfChild(Object parent, Object child) { 841 return ((WindowNode) parent).getWindowIndex((WindowNode) child); 842 } 843 844 @Override 845 public Object getRoot() { 846 return win; 847 } 848 849 @Override 850 public boolean isLeaf(Object node) { 851 return ((WindowNode) node).getWindows().length == 0; 852 } 853 854 @Override 855 public void removeTreeModelListener(TreeModelListener l) { 856 } 857 858 @Override 859 public void valueForPathChanged(TreePath path, Object newValue) { 860 } 861 } 862 863 private static class ComponentModel implements TreeModel { 864 865 ContainerNode cont; 866 867 ComponentModel(ContainerNode cont) { 868 this.cont = cont; 869 } 870 871 @Override 872 public void addTreeModelListener(TreeModelListener l) { 873 } 874 875 @Override 876 public Object getChild(Object parent, int index) { 877 if (parent instanceof ContainerNode) { 878 return ((ContainerNode) parent).getComponents()[index]; 879 } else { 880 return ""; 881 } 882 } 883 884 @Override 885 public int getChildCount(Object parent) { 886 if (parent instanceof ContainerNode) { 887 return ((ContainerNode) parent).getComponents().length; 888 } else { 889 return 0; 890 } 891 } 892 893 @Override 894 public int getIndexOfChild(Object parent, Object child) { 895 if (parent instanceof ContainerNode) { 896 return ((ContainerNode) parent).getComponentIndex((ComponentNode) child); 897 } else { 898 return -1; 899 } 900 } 901 902 @Override 903 public Object getRoot() { 904 return cont; 905 } 906 907 @Override 908 public boolean isLeaf(Object node) { 909 if (node instanceof ContainerNode) { 910 return ((ContainerNode) node).getComponents().length == 0; 911 } else { 912 return true; 913 } 914 } 915 916 @Override 917 public void removeTreeModelListener(TreeModelListener l) { 918 } 919 920 @Override 921 public void valueForPathChanged(TreePath path, Object newValue) { 922 } 923 } 924 925 private static class WindowRenderer implements TreeCellRenderer, ListCellRenderer<ClassNode> { 926 927 public WindowRenderer() { 928 } 929 930 @Override 931 public Component getTreeCellRendererComponent(JTree tree, 932 Object value, 933 boolean selected, 934 boolean expanded, 935 boolean leaf, 936 int row, 937 boolean hasFocus) { 938 return get((ClassNode) value, selected); 939 } 940 941 @Override 942 public Component getListCellRendererComponent(JList<? extends ClassNode> list, 943 ClassNode value, 944 int index, 945 boolean isSelected, 946 boolean cellHasFocus) { 947 return get(value, isSelected); 948 } 949 950 private Component get(ClassNode value, boolean selected) { 951 Component result = new JLabel(value.toString()); 952 if (selected) { 953 result.setBackground(Color.blue); 954 result.setForeground(Color.white); 955 JPanel resPane = new JPanel(); 956 resPane.setLayout(new BorderLayout()); 957 resPane.add(result, BorderLayout.CENTER); 958 return resPane; 959 } else { 960 return result; 961 } 962 } 963 } 964 965 private static class PropertyDialog extends JDialog { 966 967 public boolean showAll = false; 968 JComboBox<String> visibleCombo; 969 JCheckBox showToString; 970 JCheckBox showReflection; 971 JCheckBox showEvents; 972 DefaultListModel<String> viewTabs; 973 JList<String> orderList; 974 JButton up; 975 JButton down; 976 Properties props; 977 File propFile; 978 979 public PropertyDialog(JFrame owner) { 980 super(owner, "Properties", true); 981 982 propFile = new File(System.getProperty("user.home") 983 + System.getProperty("file.separator") 984 + ".guibrowser"); 985 986 props = new Properties(); 987 988 String[] cpItems = {"Showing", "All"}; 989 visibleCombo = new JComboBox<>(cpItems); 990 visibleCombo.addActionListener(new ActionListener() { 991 @Override 992 public void actionPerformed(ActionEvent e) { 993 showAll = (visibleCombo.getSelectedIndex() == 1); 994 } 995 }); 996 997 JPanel visiblePane = new JPanel(); 998 visiblePane.add(new JLabel("Show ")); 999 visiblePane.add(visibleCombo); 1000 1001 showToString = new JCheckBox("Show toString() method result"); 1002 showToString.setSelected(true); 1003 1004 JPanel compTreePane = new JPanel(); 1005 compTreePane.add(visiblePane); 1006 1007 viewTabs = new DefaultListModel<>(); 1008 viewTabs.addElement(WINDOWS_TAB); 1009 viewTabs.addElement(COMPONENTS_TAB); 1010 viewTabs.addElement(PROPERTIES_TAB); 1011 viewTabs.addElement(REFLECTION_TAB); 1012 viewTabs.addElement(IMAGE_TAB); 1013 1014 orderList = new JList<>(viewTabs); 1015 orderList.addListSelectionListener(new ListSelectionListener() { 1016 @Override 1017 public void valueChanged(ListSelectionEvent e) { 1018 up.setEnabled(orderList.getSelectedIndex() > -1); 1019 down.setEnabled(orderList.getSelectedIndex() > -1); 1020 } 1021 }); 1022 1023 showReflection = new JCheckBox("Show reflection tab"); 1024 showReflection.setSelected(true); 1025 showReflection.addActionListener(new ActionListener() { 1026 @Override 1027 public void actionPerformed(ActionEvent e) { 1028 if (showReflection.isSelected()) { 1029 viewTabs.addElement(REFLECTION_TAB); 1030 } else { 1031 viewTabs.remove(viewTabs.indexOf(REFLECTION_TAB)); 1032 } 1033 up.setEnabled(orderList.getSelectedIndex() > -1); 1034 down.setEnabled(orderList.getSelectedIndex() > -1); 1035 } 1036 }); 1037 1038 showEvents = new JCheckBox("Show event tab"); 1039 showEvents.setSelected(true); 1040 showEvents.addActionListener(new ActionListener() { 1041 @Override 1042 public void actionPerformed(ActionEvent e) { 1043 if (showEvents.isSelected()) { 1044 viewTabs.addElement(EVENT_TAB); 1045 } else { 1046 viewTabs.remove(viewTabs.indexOf(EVENT_TAB)); 1047 } 1048 up.setEnabled(orderList.getSelectedIndex() > -1); 1049 down.setEnabled(orderList.getSelectedIndex() > -1); 1050 } 1051 }); 1052 1053 up = new JButton("Move Up"); 1054 up.setEnabled(false); 1055 up.addActionListener(new ActionListener() { 1056 @Override 1057 public void actionPerformed(ActionEvent e) { 1058 int index = orderList.getSelectedIndex(); 1059 if (index > 0) { 1060 viewTabs.add(index - 1, 1061 viewTabs.remove(index)); 1062 orderList.setSelectedIndex(index - 1); 1063 } 1064 } 1065 }); 1066 1067 down = new JButton("Move Down"); 1068 down.setEnabled(false); 1069 down.addActionListener(new ActionListener() { 1070 @Override 1071 public void actionPerformed(ActionEvent e) { 1072 int index = orderList.getSelectedIndex(); 1073 if (index < viewTabs.size() - 1) { 1074 viewTabs.add(index + 1, 1075 viewTabs.remove(index)); 1076 orderList.setSelectedIndex(index + 1); 1077 } 1078 } 1079 }); 1080 1081 JPanel movePane = new JPanel(); 1082 movePane.add(showEvents); 1083 movePane.add(showReflection); 1084 movePane.add(up); 1085 movePane.add(down); 1086 1087 JPanel compViewPane = new JPanel(); 1088 compViewPane.setLayout(new BorderLayout()); 1089 compViewPane.add(new JLabel("Tab order:"), BorderLayout.NORTH); 1090 compViewPane.add(movePane, BorderLayout.SOUTH); 1091 compViewPane.add(orderList, BorderLayout.CENTER); 1092 1093 JTabbedPane tbpn = new JTabbedPane(); 1094 tbpn.add("Component Tree", compTreePane); 1095 tbpn.add("Component View", compViewPane); 1096 1097 JButton okBUtton = new JButton("OK"); 1098 okBUtton.addActionListener(new ActionListener() { 1099 @Override 1100 public void actionPerformed(ActionEvent e) { 1101 save(); 1102 setVisible(false); 1103 } 1104 }); 1105 1106 JButton cnBUtton = new JButton("Cancel"); 1107 cnBUtton.addActionListener(new ActionListener() { 1108 @Override 1109 public void actionPerformed(ActionEvent e) { 1110 setVisible(false); 1111 load(); 1112 } 1113 }); 1114 1115 JPanel pn = new JPanel(); 1116 pn.add(okBUtton); 1117 pn.add(cnBUtton); 1118 1119 getContentPane().setLayout(new BorderLayout()); 1120 getContentPane().add(pn, BorderLayout.SOUTH); 1121 getContentPane().add(tbpn, BorderLayout.CENTER); 1122 1123 load(); 1124 1125 setSize(400, 400); 1126 } 1127 1128 private void save() { 1129 try { 1130 props.setProperty("guibrowser.showall", 1131 showAll ? "on" : "off"); 1132 for (int i = 0; i < viewTabs.size(); i++) { 1133 props.setProperty("guibrowser.viewpage_" + Integer.toString(i), 1134 viewTabs.elementAt(i)); 1135 } 1136 try (FileOutputStream fileOutputStream = new FileOutputStream(propFile)) { 1137 props.store(fileOutputStream, 1138 "Jemmy GUIBrowser"); 1139 } 1140 } catch (IOException e) { 1141 e.printStackTrace(); 1142 } 1143 } 1144 1145 private void load() { 1146 if (propFile.exists()) { 1147 try { 1148 try (FileInputStream fileInputStream = new FileInputStream(propFile)) { 1149 props.load(fileInputStream); 1150 } 1151 showAll 1152 = props.getProperty("guibrowser.showall") == null 1153 || props.getProperty("guibrowser.showall").equals("") 1154 || props.getProperty("guibrowser.showall").equals("on"); 1155 visibleCombo.setSelectedIndex(showAll ? 1 : 0); 1156 if (props.getProperty("guibrowser.viewpage_0") != null 1157 && !props.getProperty("guibrowser.viewpage_0").equals("")) { 1158 viewTabs.removeAllElements(); 1159 viewTabs.addElement(props.getProperty("guibrowser.viewpage_0")); 1160 viewTabs.addElement(props.getProperty("guibrowser.viewpage_1")); 1161 viewTabs.addElement(props.getProperty("guibrowser.viewpage_2")); 1162 if (props.getProperty("guibrowser.viewpage_3") != null 1163 && !props.getProperty("guibrowser.viewpage_3").equals("")) { 1164 viewTabs.addElement(props.getProperty("guibrowser.viewpage_3")); 1165 } 1166 if (props.getProperty("guibrowser.viewpage_4") != null 1167 && !props.getProperty("guibrowser.viewpage_4").equals("")) { 1168 viewTabs.addElement(props.getProperty("guibrowser.viewpage_4")); 1169 } 1170 } 1171 } catch (IOException e) { 1172 e.printStackTrace(); 1173 } 1174 showReflection.setSelected(viewTabs.indexOf(REFLECTION_TAB) > -1); 1175 showEvents.setSelected(viewTabs.indexOf(EVENT_TAB) > -1); 1176 } 1177 } 1178 } 1179 1180 private class ComponentBrowser extends JFrame { 1181 1182 JTree winTree; 1183 JTree componentTree; 1184 JTree methodTree; 1185 ClassNode compNode; 1186 JTabbedPane tbd; 1187 JButton viewButton; 1188 JButton expandButton; 1189 JSplitPane winSplit = null; 1190 JSplitPane componentSplit = null; 1191 WindowRenderer renderer; 1192 SelectionManager selManager; 1193 JList<AWTEvent> eventList; 1194 ListListener listListener; 1195 DefaultListModel<AWTEvent> eventModel; 1196 JCheckBox mouseEvents; 1197 JCheckBox mouseMotionEvents; 1198 JCheckBox keyEvents; 1199 1200 public ComponentBrowser(JFrame owner, ClassNode componentNode) { 1201 super("Component " + componentNode.toString()); 1202 fill(componentNode); 1203 } 1204 1205 private void fill(ClassNode componentNode) { 1206 compNode = componentNode; 1207 1208 viewButton = new JButton("View"); 1209 viewButton.setEnabled(false); 1210 viewButton.addActionListener(new ActionListener() { 1211 @Override 1212 public void actionPerformed(ActionEvent e) { 1213 new ComponentBrowser(getOwnr(), 1214 getSelectedNode()). 1215 setVisible(true); 1216 } 1217 }); 1218 1219 expandButton = new JButton("Expand All"); 1220 expandButton.setEnabled(false); 1221 expandButton.addActionListener(new ActionListener() { 1222 @Override 1223 public void actionPerformed(ActionEvent e) { 1224 expandAll(getSelectedTree(), 1225 getSelectionPath()); 1226 } 1227 }); 1228 1229 JPanel buttonPane = new JPanel(); 1230 buttonPane.add(viewButton); 1231 buttonPane.add(expandButton); 1232 1233 Component[] cpss = {viewButton, expandButton}; 1234 selManager = new SelectionManager(cpss); 1235 renderer = new WindowRenderer(); 1236 1237 tbd = new JTabbedPane(); 1238 1239 for (int i = 0; i < propDialog.viewTabs.size(); i++) { 1240 String next = propDialog.viewTabs.elementAt(i); 1241 if (next.equals(PROPERTIES_TAB)) { 1242 addPropertiesTab(); 1243 } else if (next.equals(WINDOWS_TAB)) { 1244 addWindowTab(); 1245 } else if (next.equals(COMPONENTS_TAB)) { 1246 addComponentTab(); 1247 } else if (next.equals(REFLECTION_TAB)) { 1248 addReflectionTab(); 1249 } else if (next.equals(EVENT_TAB)) { 1250 addEventTab(); 1251 } else if (next.equals(IMAGE_TAB)) { 1252 addImageTab(); 1253 } 1254 } 1255 1256 tbd.addChangeListener(new ChangeListener() { 1257 @Override 1258 public void stateChanged(ChangeEvent e) { 1259 viewButton.setEnabled(getSelectedNode() != null); 1260 } 1261 }); 1262 1263 getContentPane().setLayout(new BorderLayout()); 1264 getContentPane().add(buttonPane, BorderLayout.SOUTH); 1265 getContentPane().add(tbd, BorderLayout.CENTER); 1266 1267 addComponentListener(new ComponentListener() { 1268 @Override 1269 public void componentHidden(ComponentEvent e) { 1270 } 1271 1272 @Override 1273 public void componentMoved(ComponentEvent e) { 1274 } 1275 1276 @Override 1277 public void componentResized(ComponentEvent e) { 1278 if (winSplit != null) { 1279 winSplit.setDividerLocation(0.8); 1280 } 1281 if (componentSplit != null) { 1282 componentSplit.setDividerLocation(0.8); 1283 } 1284 } 1285 1286 @Override 1287 public void componentShown(ComponentEvent e) { 1288 } 1289 }); 1290 1291 setSize(800, 400); 1292 } 1293 1294 private void addImageTab() { 1295 BufferedImage image = null; 1296 if (compNode instanceof ComponentNode) { 1297 image = ((ComponentNode) compNode).getImage(); 1298 } 1299 if (image != null) { 1300 JPanel imagePane = new ImagePane(image); 1301 imagePane.prepareImage(image, imagePane); 1302 JScrollPane pane = new JScrollPane(imagePane); 1303 tbd.add(IMAGE_TAB, pane); 1304 } 1305 } 1306 1307 private void addWindowTab() { 1308 if (compNode instanceof WindowNode 1309 && ((WindowNode) compNode).getWindows().length > 0) { 1310 winTree = new JTree(((WindowNode) compNode).getWindowModel()); 1311 winTree.setCellRenderer(renderer); 1312 winTree.setEditable(false); 1313 winTree.addTreeSelectionListener(selManager); 1314 winSplit = createUnderPane(winTree); 1315 tbd.add(WINDOWS_TAB, winSplit); 1316 } 1317 1318 } 1319 1320 private void addComponentTab() { 1321 if (compNode instanceof ContainerNode 1322 && ((ContainerNode) compNode).getComponents().length > 0) { 1323 componentTree = new JTree(((ContainerNode) compNode).getComponentModel()); 1324 componentTree.setCellRenderer(renderer); 1325 componentTree.setEditable(false); 1326 componentTree.addTreeSelectionListener(selManager); 1327 componentSplit = createUnderPane(componentTree); 1328 tbd.add(COMPONENTS_TAB, componentSplit); 1329 } 1330 1331 } 1332 1333 private void addReflectionTab() { 1334 methodTree = new JTree(compNode.getMethodsModel()); 1335 methodTree.setCellRenderer(renderer); 1336 methodTree.setEditable(false); 1337 methodTree.addTreeSelectionListener(selManager); 1338 tbd.add(REFLECTION_TAB, new JScrollPane(methodTree)); 1339 } 1340 1341 private void addPropertiesTab() { 1342 if (compNode instanceof ComponentNode) { 1343 Hashtable<String, Object> props = ((ContainerNode) compNode).getProperties(); 1344 if (props.size() > 0) { 1345 JTable propTable = new JTable(new MyModel(props)); 1346 propTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); 1347 tbd.add(PROPERTIES_TAB, new JScrollPane(propTable)); 1348 /* 1349 propTable.addMouseListener(new MouseListener() { 1350 public void mouseClicked(MouseEvent e) { 1351 new ComponentBrowser(getOwnr(), 1352 getSelectedNode()). 1353 show(); 1354 } 1355 public void mouseExited(MouseEvent e) { 1356 } 1357 public void mouseEntered(MouseEvent e) { 1358 } 1359 public void mousePressed(MouseEvent e) { 1360 } 1361 public void mouseReleased(MouseEvent e) { 1362 } 1363 }); 1364 */ 1365 } 1366 } 1367 } 1368 1369 private void addEventTab() { 1370 if (compNode instanceof ComponentNode) { 1371 eventModel = new DefaultListModel<>(); 1372 eventList = new JList<>(eventModel); 1373 listListener = new ListListener(eventModel, ((ComponentNode) compNode).comp); 1374 mouseEvents = new JCheckBox("Mouse events"); 1375 mouseEvents.addActionListener(new ActionListener() { 1376 @Override 1377 public void actionPerformed(ActionEvent e) { 1378 if (mouseEvents.isSelected()) { 1379 listListener.addMouseListener(); 1380 } else { 1381 listListener.removeMouseListener(); 1382 } 1383 } 1384 }); 1385 mouseMotionEvents = new JCheckBox("Mouse motion events"); 1386 mouseMotionEvents.addActionListener(new ActionListener() { 1387 @Override 1388 public void actionPerformed(ActionEvent e) { 1389 if (mouseMotionEvents.isSelected()) { 1390 listListener.addMouseMotionListener(); 1391 } else { 1392 listListener.removeMouseMotionListener(); 1393 } 1394 } 1395 }); 1396 keyEvents = new JCheckBox("Key events"); 1397 keyEvents.addActionListener(new ActionListener() { 1398 @Override 1399 public void actionPerformed(ActionEvent e) { 1400 if (keyEvents.isSelected()) { 1401 listListener.addKeyListener(); 1402 } else { 1403 listListener.removeKeyListener(); 1404 } 1405 } 1406 }); 1407 JButton clear = new JButton("Clear list"); 1408 clear.addActionListener(new ActionListener() { 1409 @Override 1410 public void actionPerformed(ActionEvent e) { 1411 eventModel.removeAllElements(); 1412 } 1413 }); 1414 JPanel checkPane = new JPanel(); 1415 checkPane.add(mouseEvents); 1416 checkPane.add(mouseMotionEvents); 1417 checkPane.add(keyEvents); 1418 checkPane.add(clear); 1419 JPanel subPane = new JPanel(); 1420 subPane.setLayout(new BorderLayout()); 1421 subPane.add(checkPane, BorderLayout.SOUTH); 1422 subPane.add(new JScrollPane(eventList), BorderLayout.CENTER); 1423 tbd.add(EVENT_TAB, subPane); 1424 } 1425 } 1426 1427 private JFrame getOwnr() { 1428 return this; 1429 } 1430 1431 private JTree getSelectedTree() { 1432 String title = tbd.getTitleAt(tbd.getSelectedIndex()); 1433 if (title.equals(WINDOWS_TAB)) { 1434 return winTree; 1435 } else if (title.equals(COMPONENTS_TAB)) { 1436 return componentTree; 1437 } else if (title.equals(REFLECTION_TAB)) { 1438 return methodTree; 1439 } 1440 return null; 1441 } 1442 1443 private TreePath getSelectionPath() { 1444 JTree tree = getSelectedTree(); 1445 if (tree != null) { 1446 return tree.getSelectionPath(); 1447 } else { 1448 return null; 1449 } 1450 } 1451 1452 private ClassNode getSelectedNode() { 1453 TreePath path = getSelectionPath(); 1454 if (path != null) { 1455 return (ClassNode) path.getLastPathComponent(); 1456 } else { 1457 return null; 1458 } 1459 } 1460 1461 } 1462 1463 private static class SelectionManager implements TreeSelectionListener, ListSelectionListener { 1464 1465 Component[] comps; 1466 1467 public SelectionManager(Component[] comps) { 1468 this.comps = comps; 1469 } 1470 1471 @Override 1472 public void valueChanged(TreeSelectionEvent e) { 1473 for (Component comp : comps) { 1474 comp.setEnabled(e.getPath() != null); 1475 } 1476 } 1477 1478 @Override 1479 public void valueChanged(ListSelectionEvent e) { 1480 for (Component comp : comps) { 1481 comp.setEnabled(e.getFirstIndex() != -1); 1482 } 1483 } 1484 } 1485 1486 private void expandAll(JTree tree, TreePath path) { 1487 tree.expandPath(path); 1488 TreeModel model = tree.getModel(); 1489 Object lastComponent = path.getLastPathComponent(); 1490 for (int i = 0; i < model.getChildCount(lastComponent); i++) { 1491 expandAll(tree, 1492 path.pathByAddingChild(model.getChild(lastComponent, i))); 1493 } 1494 } 1495 1496 private static class ToStringListener implements TreeSelectionListener { 1497 1498 JTextArea area; 1499 1500 public ToStringListener(JTextArea area) { 1501 this.area = area; 1502 } 1503 1504 @Override 1505 public void valueChanged(TreeSelectionEvent e) { 1506 if (e.getPath() != null 1507 && e.getPath().getLastPathComponent() instanceof ComponentNode) { 1508 area.setText("toString(): " 1509 + ((ComponentNode) e.getPath().getLastPathComponent()). 1510 getToString()); 1511 } else { 1512 area.setText(""); 1513 } 1514 } 1515 } 1516 1517 private JSplitPane createUnderPane(JTree tree) { 1518 JTextArea toStringArea = new JTextArea(); 1519 toStringArea.setLineWrap(true); 1520 toStringArea.setEditable(false); 1521 tree.addTreeSelectionListener(new ToStringListener(toStringArea)); 1522 JSplitPane result = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 1523 new JScrollPane(tree), 1524 new JScrollPane(toStringArea)); 1525 result.setOneTouchExpandable(true); 1526 result.setDividerSize(8); 1527 result.setDividerLocation(0.8); 1528 return result; 1529 } 1530 1531 private static class MyModel extends DefaultTableModel { 1532 1533 private static final long serialVersionUID = 42L; 1534 1535 @SuppressWarnings(value = "unchecked") 1536 public MyModel(Hashtable<String, Object> props) { 1537 super(); 1538 Object[] keys = props.keySet().toArray(); 1539 if (keys.length > 0) { 1540 addColumn("Name"); 1541 addColumn("Value"); 1542 setNumRows(keys.length); 1543 for (int i = 0; i < keys.length; i++) { 1544 setValueAt(keys[i].toString(), i, 0); 1545 setValueAt(props.get(keys[i]).toString(), i, 1); 1546 } 1547 Collections.sort((Vector<Vector<?>>) (Vector<?>) getDataVector(), new Comparator<Vector<?>>() { 1548 @Override 1549 public int compare(Vector<?> v1, Vector<?> v2) { 1550 return v1.get(0).toString().compareTo(v2.get(0).toString()); 1551 } 1552 }); 1553 } 1554 } 1555 1556 @Override 1557 public boolean isCellEditable(int x, int y) { 1558 return false; 1559 } 1560 } 1561 1562 private static class ListListener extends TrialListenerManager { 1563 1564 DefaultListModel<AWTEvent> model; 1565 1566 public ListListener(DefaultListModel<AWTEvent> m, Component comp) { 1567 super(comp); 1568 model = m; 1569 } 1570 1571 @Override 1572 void printEvent(AWTEvent e) { 1573 model.addElement(e); 1574 } 1575 } 1576 1577 private static class ImagePane extends JPanel { 1578 1579 private static final long serialVersionUID = 42L; 1580 BufferedImage image; 1581 1582 public ImagePane(BufferedImage image) { 1583 super(); 1584 this.image = image; 1585 setPreferredSize(new Dimension(image.getWidth(), image.getHeight())); 1586 } 1587 1588 @Override 1589 public void paint(Graphics g) { 1590 g.drawImage(image, 0, 0, null); 1591 } 1592 } 1593 1594 private static class ComponentImageProvider { 1595 1596 BufferedImage image; 1597 int x; 1598 int y; 1599 1600 public ComponentImageProvider(BufferedImage image, int x, int y) { 1601 this.image = image; 1602 this.x = x; 1603 this.y = y; 1604 } 1605 1606 public BufferedImage getImage(int x, int y, int w, int h) { 1607 /* 1608 BufferedImage newImage = image.getSubimage(0, 0, image.getWidth(), image.getHeight()); 1609 Graphics g = newImage.getGraphics(); 1610 g.setColor(Color.RED); 1611 g.drawRect(x - this.x, y - this.y, w, h); 1612 return newImage; 1613 */ 1614 int realW = Math.min(image.getWidth() - x, w); 1615 int realH = Math.min(image.getHeight() - y, h); 1616 return image.getSubimage(x - this.x, y - this.y, realW, realH); 1617 } 1618 } 1619} 1620