Package DisplayProject.swingdisplayer

Source Code of DisplayProject.swingdisplayer.SwingDisplayer$TableData

/*
Copyright (c) 2003-2009 ITerative Consulting Pty Ltd. All Rights Reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

o Redistributions of source code must retain the above copyright notice, this list of conditions and
the following disclaimer.
 
o Redistributions in binary form must reproduce the above copyright notice, this list of conditions
and the following disclaimer in the documentation and/or other materials provided with the distribution.
   
o This jcTOOL Helper Class software, whether in binary or source form may not be used within,
or to derive, any other product without the specific prior written permission of the copyright holder

 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


*/
package DisplayProject.swingdisplayer;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FocusTraversalPolicy;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.EventObject;
import java.util.List;

import javax.swing.AbstractCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.JWindow;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import org.apache.log4j.Logger;
import org.springframework.util.StringUtils;

import DisplayProject.Constants;
import DisplayProject.GridCell;
import DisplayProject.GridField;
import DisplayProject.LayoutManagerHelper;
import DisplayProject.UIutils;
import DisplayProject.actions.SkipOnTab;
import DisplayProject.plaf.ForteLayoutFocusTraversalPolicy;

/**
* This helper class is invoked by doing Ctrl-Shift-F1 on a window, much like the
* standard window dump. However, this one will give a graphical representation of
* of the window and a view of the properties, as well as allowing other nice things
* like explicitly forcing a layout at a given component level to ensure that the
* layout is correct.
* @author Tim
*
*/
@SuppressWarnings("serial")
public class SwingDisplayer extends JFrame {
    private JTree tree;
    private JTable table;
    private JLabel imageView = new JLabel("Select a component to display");
    DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
    private JPopupMenu contextMenu = new JPopupMenu();
    private Component currentNode = null;
    private JComboBox history;
    private boolean disableListener = false;
    private Component currentFocusOwner;
   
    /**
     * The scale of the shown image
     */
    private double scale = 1.0;
   
    /**
     * The location of the shown image
     */
    private Point location = new Point();
    /**
     * The monitor which monitors the focus changes
     */
    private FocusMonitor monitor;
    /**
     * A label used to render the focus traversal numbers
     */
    private static final JLabel numberLabel = new JLabel();
    private static final Color ALTERNATE_COLOUR = new Color(230, 230, 230);
   
    private class FocusMonitor implements PropertyChangeListener {
      Component rootComponent;
      public FocusMonitor(Component comp) {
        rootComponent = comp;
      }
      public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getNewValue() instanceof Component) {
          Component newComp = (Component)evt.getNewValue();
          if (getTopLevelAncestor(newComp) == getTopLevelAncestor(rootComponent)) {
            currentFocusOwner = newComp;
                  focusOwnerLabel.setText(getShortDescription(currentFocusOwner));
            redrawImage();
          }
        }
      }
    }
   
    public SwingDisplayer(final Component pRoot) {
        UIutils.invokeOnGuiThread(new Runnable() {
            public void run() {
                 // CONV:TF:22 Jul 2009: Catch exception when the focus owner is null.  Handle condition when focusHandler is null.
        // Begin
              try
              {
                currentFocusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
                if (currentFocusOwner != null)
                {
                  focusOwnerLabel.setText(getShortDescription(currentFocusOwner));
                }
                else
                {
                  focusOwnerLabel.setText("<No focus owner>");
                }
                monitor = new FocusMonitor(pRoot);
                KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("permanentFocusOwner", monitor);
                  initialize(pRoot);
                  addWindowListener(new WindowAdapter() {
                    @Override
                    public void windowClosed(WindowEvent e) {
                      KeyboardFocusManager.getCurrentKeyboardFocusManager().removePropertyChangeListener("permanentFocusOwner", monitor);
                    }
                  });
              }
                catch (Throwable t) {
                  System.out.println("Unhandled exception in SwingDisplayer " + t);
                  t.printStackTrace();
                }
                 // CONV:TF:22 Jul 2009: Catch exception when the focus owner is null.  Handle condition when focusHandler is null.
        // End
            }
        });
    }

    private String getShortDescription(Component comp) {
      StringBuilder result = new StringBuilder();
      result.append("<html><u>");
      result.append(comp.getClass().getName());
      if (comp.getName() != null) {
        result.append("(").append(comp.getName()).append(")");
      }
      result.append("</u></html>");
      return result.toString();
    }
    /**
     * Returns the top-level ancestor of this component (either the
     * containing <code>Window</code> or <code>Applet</code>),
     * or <code>null</code> if this component has not
     * been added to any container.
     *
     * @return the top-level <code>Container</code> that this component is in,
     *    or <code>null</code> if not in any container
     */
    public Component getTopLevelAncestor(Component c) {
        for(Component p = c; p != null; p = p.getParent()) {
            if(p instanceof Window || p instanceof Applet) {
                return p;
            }
        }
        return null;
    }

    /**
     * Get a list of the components that are children
     * @param c
     * @return
     */
    private List<Component> getFocusList(Container c) {
      List<Component> result = new ArrayList<Component>();
     
        try {
        Container container = (Container)c;
        Container root = c.getFocusCycleRootAncestor();
        if (root == null) {
          root = container;
          while (root.getParent() != null) {
            root = root.getParent();
          }
          if (root instanceof JFrame) {
            root = ((JFrame)root).getContentPane();
          }
          else if (root instanceof JDialog) {
            root = ((JDialog)root).getContentPane();
          }
          else if (root instanceof JWindow) {
            root = ((JWindow)root).getContentPane();
          }
        }
        if (root != null) {
          FocusTraversalPolicy policy = root.getFocusTraversalPolicy();
         
          // CraigM:01/09/2008 - Switch off the special ArrayField focus handling as it causes an endless loop
          if (policy instanceof ForteLayoutFocusTraversalPolicy) {
            ((ForteLayoutFocusTraversalPolicy)policy).setSwingDisplayerIgnoreArrayField(true);
          }
         
          // DK:30/09/2008:With some of the forms lastComponent is null and component after the last one
          //is the first one and we do not need to continue to avoid endless loop.
          Component firstComponent = policy.getFirstComponent(container);
          Component lastComponent = policy.getLastComponent(container);
        Component child = firstComponent;
          while (child != null) {
            // TF:28/10/2008:There are some situation where getComponentAfter returns the same component, so prevent infinite looping
            if (result.contains(child)) {
              break;
            }
            result.add(child);
          if (child == lastComponent) {
              break;
            }
            child = policy.getComponentAfter(root, child);

            if (child == firstComponent) {
              break;
            }
          }
         
          // CraigM:01/09/2008 - Make sure we switch the normal traversal policy back on
          if (policy instanceof ForteLayoutFocusTraversalPolicy) {
            ((ForteLayoutFocusTraversalPolicy)policy).setSwingDisplayerIgnoreArrayField(false);
          }
        }
        }
        catch (Exception e) {
          // Do nothing, this will just stop us displaying
        }
        return result;
    }
   
    /**
     * Paint the focus numbers of the components in the passed container with the passed graphics
     * context. Only those components that will gain the focus (as per the FocusTraversalPolicy will
     * get their numbers painted. If the component has focus, the number will be painted in a different colour.
     * @param g
     * @param c
     */
    private void paintFocusNumbers(Graphics g, Container c) {
        // Now superimpose ontop of this image the numbers
        List<Component> focusList = getFocusList(c);               
        Dimension largestSize = new Dimension(0,0);
        FontMetrics fm = numberLabel.getFontMetrics(numberLabel.getFont());
        largestSize.height = fm.getHeight();
        for (int i = 0; i < focusList.size(); i++) {
          Rectangle2D thisStringSize = fm.getStringBounds(Integer.toString(i+1), g);
          if (thisStringSize.getWidth() > largestSize.width) {
            largestSize.width = (int)thisStringSize.getWidth();
          }
        }
        // Now the diameter of our circle will be (length from top left (0,0) to bottom right(width, height)
        int size = (int)(Math.sqrt(largestSize.width * largestSize.width + largestSize.height * largestSize.height) + 0.99) - 2;
        for (int i = 0; i < focusList.size(); i++) {
          Component comp = focusList.get(i);
          g.drawString(Integer.toString(i+1), getX(), getY());
          g.setColor(currentFocusOwner == comp ? Color.yellow : Color.magenta);
          Point originalPoint = new Point(comp.getX() - size/2, comp.getY() - size/2);
          Point newPoint = SwingUtilities.convertPoint(comp.getParent(), originalPoint, c);
          g.fillOval(newPoint.x, newPoint.y, size, size);
          int width = (int)fm.getStringBounds(Integer.toString(i+1), g).getWidth();
          g.setColor(currentFocusOwner == comp ? Color.lightGray : Color.black);
          g.drawString(Integer.toString(i+1), newPoint.x + size/2 - width/2 + 1, newPoint.y + size - fm.getMaxDescent());
          g.setColor(currentFocusOwner == comp ? Color.black : Color.white);
          g.drawString(Integer.toString(i+1), newPoint.x + size/2 - width/2, newPoint.y + size - fm.getMaxDescent()-1);
        }
    }

    /**
     * Redraw the image component of the window
     */
    private void redrawImage() {
        TreePath path = tree.getSelectionPath();
        if (path == null) {
            imageView.setIcon(null);
            imageView.setText("Select a component to display");
            scale = 0.0;
        }
        else {
            try {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
                Component c = (Component)node.getUserObject();
                Image bi;
                if (c.isOpaque()) {
                  bi = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_RGB);
                }
                else {
                  // TF:Non-opaque images need to be rendered onto bitmaps with an alpha mask
                  bi = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_ARGB);
                }
                Graphics g = bi.getGraphics();
        // CONV:TF:22 Jul 2009: Changed paint method to print method so the off screen graphics will be rendered properly
                c.print(g);
                if (c instanceof Container && showTabOrder) {
                  this.paintFocusNumbers(g, (Container)c);
                }
                g.dispose();
                int currWidth = imageView.getWidth();
                int currHeight = imageView.getHeight();
                int imageWidth = c.getWidth();
                int imageHeight = c.getHeight();
                Image newImage;
                if (imageWidth <= currWidth && imageHeight <= currHeight) {
                    // We can fit this whole thing on screen
                    newImage = bi;
                    scale = 1.0;
                }
                else if (imageWidth <= currWidth) {
                    // Scale by height (as this is the one that doesn't fit onscreen), keeping ratio the same
                    newImage = bi.getScaledInstance(-1, currHeight, 0);
                    scale = ((double)currHeight) / imageHeight;
                }
                else if (imageHeight <= currHeight) {
                    // Scale by height (as this is the one that doesn't fit onscreen), keeping ratio the same
                    newImage = bi.getScaledInstance(currWidth, -1, 0);
                    scale = ((double)currWidth) / imageWidth;
                }
                else {
                    // We need to scale by the smaller of the 2 ratios
                    if ((((double)imageWidth) / ((double)currWidth)) > (((double)imageHeight) / ((double)currHeight))) {
                        newImage = bi.getScaledInstance(currWidth, -1, 0);
                        scale = ((double)currWidth) / imageWidth;
                    }
                    else {
                        newImage = bi.getScaledInstance(-1, currHeight, 0);
                        scale = ((double)currHeight) / imageHeight;
                    }
                }
                // Draw a checkered background to ensure that we can accurately see the background
                BufferedImage bi2 = new BufferedImage(currWidth, currHeight, BufferedImage.TYPE_INT_ARGB);
                g = bi2.getGraphics();
                final int SQUARE_SIZE = 5;
                g.setColor(Color.white);
                g.fillRect(0, 0, currWidth, currHeight);
                for (int i = 0; i < currWidth; i+=SQUARE_SIZE) {
                    for (int j = 0; j < currHeight; j+= SQUARE_SIZE) {
                        if (((i+j) % 2) == 0) {
                            g.setColor(ALTERNATE_COLOUR);
                            g.fillRect(i, j, SQUARE_SIZE, SQUARE_SIZE);
                        }
                    }
                }
                location.x = (currWidth - newImage.getWidth(null)) / 2;
                location.y = (currHeight - newImage.getHeight(null)) / 2;
                g.drawImage(newImage, location.x, location.y, null);
                g.dispose();
                imageView.setIcon(new ImageIcon(bi2));
                imageView.setText(null);
                imageView.setMinimumSize(new Dimension(0, 0));
            }
            catch (Exception e) {
                imageView.setIcon(null);
                imageView.setText("Could not render component");
            }
        }
    }

    private class PropertyMonitor extends AbstractCellEditor implements PropertyChangeListener, TableCellEditor, TableCellRenderer {
        protected EventListenerList listenerList = new EventListenerList();
      private final PropertyDescriptor property;
      private final Method readMethod;
      private final Method writeMethod;
      private final Component component;
      private int row = -1;
      private Object currentValue;
     
      public PropertyMonitor(Component component, PropertyDescriptor property) {
        this.property = property;
        this.component = component;
        component.addPropertyChangeListener(property.getName(), this);
        this.readMethod = property.getReadMethod();
        this.writeMethod = property.getWriteMethod();
        try {
          currentValue = this.readMethod.invoke(component);
      } catch (Exception e) {
      }
      }
     
    public void propertyChange(PropertyChangeEvent evt) {
      currentValue = evt.getNewValue();
      if (row >= 0) {
        table.getModel().setValueAt(evt.getNewValue(), row, 1);
      }
    }

    public Object getCellEditorValue() {
      // return box == null ? null : box.getSelectedItem();
      return this;
    }

    public boolean isCellEditable() {
      if (property.getPropertyType().equals(Boolean.TYPE) && writeMethod != null && readMethod != null) {
        return true;
      }
      return false;
    }

    public boolean isCellEditable(EventObject anEvent) {
      return isCellEditable();
    }

    public boolean shouldSelectCell(EventObject anEvent) {
            if (anEvent instanceof MouseEvent) {
                MouseEvent e = (MouseEvent)anEvent;
                return e.getID() != MouseEvent.MOUSE_DRAGGED;
            }
            return true;
    }

    public Component getTableCellEditorComponent(JTable table,
        Object value, boolean isSelected, int row, int column) {
      if (property.getPropertyType().equals(Boolean.TYPE)) {
        this.row = row;
        final JComboBox aBox = new JComboBox(new Object[] {"true", "false"});
        aBox.setBorder(null);
        aBox.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            try {
              writeMethod.invoke(component, Boolean.valueOf(aBox.getSelectedIndex() == 0));
              currentValue = Boolean.valueOf(aBox.getSelectedIndex() == 0);
            } catch (Exception e1) {
            }
          }
        });
        aBox.setSelectedIndex(currentValue instanceof Boolean && ((Boolean)currentValue).booleanValue() ? 0 : 1);
        return aBox;
      }
      return null;
    }

    public Component getTableCellRendererComponent(JTable table,
        Object value, boolean isSelected, boolean hasFocus, int row,
        int column) {
      return new JLabel(String.valueOf(currentValue));
    }
    }

    private class TableData implements Comparable<TableData> {
        public String name;
        public String value;
        public PropertyMonitor monitor;
        public TableData(String name, String value) {
            this.name = name;
            this.value = value;
        }
       
        public TableData(String name, Component comp, PropertyDescriptor descriptor) {
          this.name = name;
          this.monitor = new PropertyMonitor(comp, descriptor);
        }

        public int compareTo(TableData o) {
            if (o == null) {
                return -1;
            }
            else {
                return name.compareTo(o.name);
            }
        }
    }

    private Object[][] formTableData(ArrayList<TableData> pData) {
        Object[][] result = new Object[pData.size()][2];
        int count = 0;
        for (TableData data : pData) {
            result[count][0] = data.name;
            result[count++][1] = data.monitor == null ? data.value : data.monitor;
        }
        return result;
    }

    private String showDimension(Dimension d) {
        return "[width=" + d.width + ",height=" + d.height + "]";
    }

    private String showCursor(Cursor c) {
        if (c.equals(Cursor.CROSSHAIR_CURSOR))  return "[Crosshair Cursor]";
        if (c.equals(Cursor.CUSTOM_CURSOR))    return "[Custom Cursor]";
        if (c.equals(Cursor.DEFAULT_CURSOR))  return "[Default Cursor]";
        if (c.equals(Cursor.E_RESIZE_CURSOR))  return "[E Resize Cursor]";
        if (c.equals(Cursor.HAND_CURSOR))    return "[Hand Cursor]";
        if (c.equals(Cursor.MOVE_CURSOR))    return "[Move Cursor]";
        if (c.equals(Cursor.N_RESIZE_CURSOR))  return "[N Resize Cursor]";
        if (c.equals(Cursor.NE_RESIZE_CURSOR))  return "[NE Resize Cursor]";
        if (c.equals(Cursor.S_RESIZE_CURSOR))  return "[S Resize Cursor]";
        if (c.equals(Cursor.SE_RESIZE_CURSOR))  return "[SE Resize Cursor]";
        if (c.equals(Cursor.SW_RESIZE_CURSOR))  return "[SW Resize Cursor]";
        if (c.equals(Cursor.TEXT_CURSOR))    return "[Text Cursor]";
        if (c.equals(Cursor.W_RESIZE_CURSOR))  return "[W Resize Cursor]";
        if (c.equals(Cursor.WAIT_CURSOR))    return "[Wait Cursor]";
        return "Cursor[name="+c.getName()+",type="+c.getType()+"]";
    }
   
    private String showState(JComponent comp) {
      Integer state = (Integer)comp.getClientProperty("qq_state");
      if (state == null) {
        return "<html><i>Not set</i></html>";
      }
      else {
        switch (state.intValue()) {
          case Constants.FS_DISABLED:      return "FS_DISABLED";
          case Constants.FS_DRAG:        return "FS_DRAG";
          case Constants.FS_DRAGSELECT:    return "FS_DRAGSELECT";
            case Constants.FS_EXPAND:      return "FS_EXPAND";
            case Constants.FS_HORZEXPAND:    return "FS_HORZEXPAND";
            case Constants.FS_HORZMOVE:      return "FS_HORZMOVE";
            case Constants.FS_HORZSTRETCH:    return "FS_HORZSTRETCH";
            case Constants.FS_INACTIVE:      return "FS_INACTIVE";
            case Constants.FS_INVISIBLE:    return "FS_INVISIBLE";
            case Constants.FS_MARKLINE:      return "FS_MARKLINE";
            case Constants.FS_MARKPOINT:    return "FS_MARKPOINT";
            case Constants.FS_MARKPOLYLINE:    return "FS_MARKPOLYLINE";
            case Constants.FS_MARKRECTANGLE:  return "FS_MARKRECTANGLE";
            case Constants.FS_MOVE:           return "FS_MOVE";
            case Constants.FS_MOVEANDROUTE:    return "FS_MOVEANDROUTE";
            case Constants.FS_QUERY:           return "FS_QUERY";
            case Constants.FS_ROUTE:      return "FS_ROUTE";
            case Constants.FS_SELECTONLY:    return "FS_SELECTONLY";
            case Constants.FS_STRETCH:      return "FS_STRETCH";
            case Constants.FS_UPDATE:      return "FS_UPDATE";
            case Constants.FS_USAGESTATE:    return "FS_USAGESTATE";
            case Constants.FS_VERTEXPAND:    return "FS_VERTEXPAND";
            case Constants.FS_VERTMOVE:      return "FS_VERTMOVE";
            case Constants.FS_VERTSTRETCH:    return "FS_VERTSTRETCH";
            case Constants.FS_VIEWONLY:      return "FS_VIEWONLY";
            default:
              return "<html><i>Unknown (" + state + ")</i></html>";
        }
      }
    }

    private class TreeHistory {
      public TreePath path;
      TreeHistory(TreePath path) {
        this.path = path;
      }
     
      @Override
      public String toString() {
        return path.getLastPathComponent().toString();
      }
    }
   
    public void setTableData() {
        TreePath path = tree.getSelectionPath();
        if (path == null) {
            ((DefaultTableModel)table.getModel()).setDataVector(new Object[0][2], new String[] {"Name", "Value"});
        }
        else {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
            Component c = (Component)node.getUserObject();
            currentNode = c;
            Object[][] objects = new Object[0][2];
            try {
                ArrayList<TableData> results = new ArrayList<TableData>();
                ArrayList<String> propertiesToExclude = new ArrayList<String>();
                ArrayList<TableData> stdProperties = new ArrayList<TableData>();
               
                // Check if has a Name and if not see if there is generated name
                String componentName = c.getName();
                if (!StringUtils.hasText(componentName)) {
          if (c instanceof GridField) {
            GridField gf = (GridField) c;
            componentName = gf.getGeneratedName();
          }
        }
               
                // TF:16/11/07:First do standard properties...
                stdProperties.add(new TableData("<html><b>Name</b></html>", componentName));
                stdProperties.add(new TableData("<html><b>Sizing</b></html>", ""));
                stdProperties.add(new TableData("  location", "[x="+ c.getX()+",y="+c.getY()+"]"));
                stdProperties.add(new TableData("  size", "[width="+ c.getWidth()+",height="+ c.getHeight()+"]"));
                stdProperties.add(new TableData("  minimumSize", c.isMinimumSizeSet() ? showDimension(c.getMinimumSize()): "<html><i>Not set</i></html>"));
                stdProperties.add(new TableData("  maximumSize", c.isMaximumSizeSet() ? showDimension(c.getMaximumSize()): "<html><i>Not set</i></html>"));
                stdProperties.add(new TableData("  preferredSize", c.isPreferredSizeSet() ? showDimension(c.getPreferredSize()): "<html><i>Not set</i></html>"));
                if (c instanceof JComponent) {
                    JComponent comp = (JComponent)c;
                    GridCell cell = GridCell.get(comp);
                    stdProperties.add(new TableData("<html><b>Layout Info</b></html>", ""));
                    stdProperties.add(new TableData("  cell", "[row="+ cell.getRow()+",column="+cell.getColumn()+"]"));
                    stdProperties.add(new TableData("  widthPolicy", cell.sizePolicyToString(cell.getWidthPolicy())));
                    if (cell.getWidthPolicy() == Constants.SP_TO_PARTNER) {
                      JComponent comp1 = LayoutManagerHelper.getWidthPartner(comp);
                      for (int i = 1; comp1 != null && comp1 != comp; i++) {
                            stdProperties.add(new TableData("      ["+i+"]", "  " + comp1.toString()));
                            comp1 = LayoutManagerHelper.getWidthPartner(comp1);
                      }
                    }
                    else if (cell.getWidthPolicy() == Constants.SP_TO_MATRIX_PARTNER && comp instanceof GridField) {
                      GridField partner = ((GridField)comp).getWidthMatrixPartner();
                      for (int i = 1; partner != null && partner != comp; i++) {
                            stdProperties.add(new TableData("      ["+i+"]", "  " + partner.toString()));
                            partner = partner.getWidthMatrixPartner();
                      }
                    }
                    stdProperties.add(new TableData("  heightPolicy", cell.sizePolicyToString(cell.getHeightPolicy())));
                    if (cell.getHeightPolicy() == Constants.SP_TO_PARTNER) {
                      JComponent comp1 = LayoutManagerHelper.getHeightPartner(comp);
                      for (int i = 1; comp1 != null && comp1 != comp; i++) {
                            stdProperties.add(new TableData("      ["+i+"]", "  " + comp1.toString()));
                            comp1 = LayoutManagerHelper.getHeightPartner(comp1);
                      }
                    }
                    else if (cell.getHeightPolicy() == Constants.SP_TO_MATRIX_PARTNER && comp instanceof GridField) {
                      GridField partner = ((GridField)comp).getHeightMatrixPartner();
                      for (int i = 1; partner != null && partner != comp; i++) {
                            stdProperties.add(new TableData("      ["+i+"]", "  " + partner.toString()));
                            partner = partner.getHeightMatrixPartner();
                      }
                    }
                    stdProperties.add(new TableData("  gravity", cell.gravityAsString()));
                    stdProperties.add(new TableData("  margins", "[t="+cell.getTopMargin()+
                                                                ",l="+cell.getLeftMargin()+
                                                                ",b="+cell.getBottomMargin()+
                                                                ",r="+cell.getRightMargin()+"]"))
                    if (comp.getParent() instanceof GridField) {
                        GridField gf = (GridField)comp.getParent();
                        stdProperties.add(new TableData("  rowWeight", ""+gf.getRowJustifyWeight(cell.getRow())));
                        stdProperties.add(new TableData("  columnWeight", ""+gf.getColumnJustifyWeight(cell.getColumn())));
                    }
                    if (comp instanceof GridField) {
                        StringBuilder buffer = new StringBuilder(50);
                        GridField gf = (GridField)comp;
                        int[] rowWeights = gf.getRowJustifyWeight();
                        buffer.append('[');
                        for (int i = 0; i < rowWeights.length; i++) {
                            if (i > 0) {
                                buffer.append(',');
                            }
                            buffer.append(rowWeights[i]);
                        }
                        buffer.append(']');
                        stdProperties.add(new TableData("  rowWeights", buffer.toString()));

                        buffer = new StringBuilder(50);
                        int[] colWeights = gf.getColumnJustifyWeight();
                        buffer.append('[');
                        for (int i = 0; i < colWeights.length; i++) {
                            if (i > 0) {
                                buffer.append(',');
                            }
                            buffer.append(colWeights[i]);
                        }
                        buffer.append(']');
                        stdProperties.add(new TableData("  columnWeights", buffer.toString()));
                    }
                    // Add in standard Forte properties, like State
                    stdProperties.add(new TableData("<html><b>Properties</b></html>", ""));
                    stdProperties.add(new TableData("  skipOnTab", Boolean.toString(SkipOnTab.get(comp))));
                    stdProperties.add(new TableData("  state", showState(comp)));
                   
                    // Add in the client properties, if there are any. Note that because of the way
                    // these are implemented, we have to discover them via introspection
                    Class<JComponent> clazz = JComponent.class;
                    Field field = clazz.getDeclaredField("clientProperties");
                    if (field != null) {
                      field.setAccessible(true);
                      Object o = field.get(comp);
                      Field field1 = o.getClass().getDeclaredField("table");
                      if (field1 != null) {
                        field1.setAccessible(true);
                        Object o1 = field1.get(o);
                        if (o1 instanceof Object[]) {
                          Object[] propertiesList = (Object[])o1;
                          if (propertiesList.length > 1) {
                                    stdProperties.add(new TableData("<html><b>ClientProperties</b></html>", ""));
                            for (int i = 0; i+1 < propertiesList.length; i+= 2) {
                                      stdProperties.add(new TableData("  " + propertiesList[i].toString(), propertiesList[i+1].toString()));
                           
                            }
                          }
                        }
                      }
                    }
                   
                    // Popup menu properties.
                    stdProperties.add(new TableData("<html><b>Popup Menu Properties</b></html>", ""));
                    stdProperties.add(new TableData("  inheritsPopupMenu", Boolean.toString(comp.getInheritsPopupMenu())));
                    stdProperties.add(new TableData("  componentPopupMenu", ""+comp.getComponentPopupMenu()));
                    if (comp.getInheritsPopupMenu()) {
                      comp.setInheritsPopupMenu(false);
                      stdProperties.add(new TableData("  ownedPopupMenu", ""+comp.getComponentPopupMenu()));
                      comp.setInheritsPopupMenu(true);
                    }
                }
                stdProperties.add(new TableData("<html><b>Other</b></html>", ""));

                results.add(new TableData("  cursor", showCursor(c.getCursor())));

                propertiesToExclude.add("name");
                propertiesToExclude.add("x");
                propertiesToExclude.add("y");
                propertiesToExclude.add("width");
                propertiesToExclude.add("height");
                propertiesToExclude.add("minimumSize");
                propertiesToExclude.add("maximumSize");
                propertiesToExclude.add("preferredSize");
                propertiesToExclude.add("MinimumSize");
                propertiesToExclude.add("MaximumSize");
                propertiesToExclude.add("PreferredSize");
                propertiesToExclude.add("cursor");

                BeanInfo beanInfo = Introspector.getBeanInfo(c.getClass());
                PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
               
                String myPackage = this.getClass().getName();
                myPackage = myPackage.substring(0, myPackage.lastIndexOf('.'));
                if (myPackage.endsWith(".swingdisplayer")) {
                  myPackage = myPackage.substring(0, myPackage.length() - ".swingdisplayer".length());
                }
                PROPERTY_LOOP:
                for (PropertyDescriptor aProperty : properties) {
                    String name = aProperty.getDisplayName();
                    Method reader = aProperty.getReadMethod();
                    Object value = "<not readable>";
                    boolean skipProperty = false;

                    for (String skipName : propertiesToExclude) {
                        if (name.equals(skipName)) {
                            continue PROPERTY_LOOP;
                        }
                    }

                    try {
                        if (reader != null) {
                            // We cannot get all properties, otherwise there is a risk that we'll actually
                            // be invoking application code on the EDT. For example, if there is a method "isA"
                            // then this has to be an application method. We will get the properties only if:
                            // 1) The method is on a class in the java package
                            // 2) The method is on a class in this package or below
                            // 3) The method is backed by an actual attribute, in which case we use the real attribute
                            String owner = reader.getDeclaringClass().getName();
                            if (owner.startsWith("java.") || owner.startsWith("javax.") || owner.startsWith(myPackage)) {
                                value = reader.invoke(c, (Object[])null);
                            }
                            else {
                                skipProperty = true;
                            }
                        }
                        else {
                            skipProperty = true;
                        }
                    }
                    catch (Exception e) {
                    }
                    if (!skipProperty) {
                      if (Boolean.TYPE.equals(aProperty.getPropertyType())) {
                        results.add(new TableData("  "+name, c, aProperty));
                      }
                      else {
                        results.add(new TableData("  "+name, value == null ? "null" : value.toString()));
                      }
                    }
                }
                Collections.sort(results);
                results.addAll(0, stdProperties);

                objects = formTableData(results);
            }
            catch (Exception e) {
                Logger.getLogger("task.part.logmgr").error("Unhandled error ", e);
            }
            ((DefaultTableModel)table.getModel()).setDataVector(objects, new String[] {"Name", "Value"});
        }
    }

    private String findClassForComponent(Component comp) {
      Component lastComp = null;
      while (comp != null) {
      lastComp = comp;
        if (comp.getName() != null && comp.getName().endsWith(".Form")) {
          return comp.getName().substring(0, comp.getName().length() - 5);
        }
        comp = comp.getParent();
      }
      return lastComp.getClass().getName();
    }
   
    private void jumpToComponent(Component comp) {
    TreePath path = findComponentInTree(tree.getSelectionPath(), comp);
    if (path != null) {
      tree.setSelectionPath(path);
      tree.scrollPathToVisible(path);
      ((JScrollPane)tree.getParent().getParent()).getHorizontalScrollBar().setValue(0);
      this.owningClassLabel.setText(findClassForComponent(comp));
    }
    }

    public void initialize(Component pComp) {
        JMenuItem layoutRequest = new JMenuItem("Force Layout");
        layoutRequest.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                TreePath path = tree.getSelectionPath();
                if (path != null) {
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
                    Component c = (Component)node.getUserObject();
                    c.doLayout();
                }
            }
        });
       
        contextMenu.add(layoutRequest);
        // Set the component to show the popup menu

        table = new JTable() {
          private final Color disabledColor = new Color(240, 240, 240);
          @Override
          public boolean isCellEditable(int row, int column) {
            if (column == 0) {
              // First column is never editable
              return false;
            }
            if (this.getModel().getValueAt(row, column) instanceof PropertyMonitor) {
              return ((PropertyMonitor)this.getModel().getValueAt(row, column)).isCellEditable();
            }
            return false;
          }
          @Override
          public TableCellEditor getCellEditor(int row, int column) {
            Object value = this.getModel().getValueAt(row, column);
            if (value instanceof PropertyMonitor) {
              return (PropertyMonitor)value;
            }
            /*
            if ("true".equals(value)||"false".equals(value)) {
              JComboBox box = new JComboBox(new Object[] {"true", "false"});
              box.setBorder(null);
              box.setSelectedIndex("true".equals(value) ? 0 : 1);
              TableCellEditor result = new DefaultCellEditor(box);
              return result;
            }
            */
            return super.getCellEditor(row, column);
          }
          @Override
          public TableCellRenderer getCellRenderer(int row, int column) {
            Object value = this.getModel().getValueAt(row, column);
            if (value instanceof PropertyMonitor) {
              return (PropertyMonitor)value;
            }
            /*
            if ("true".equals(value)||"false".equals(value)) {
              JComboBox box = new JComboBox(new Object[] {"true", "false"});
              box.setBorder(null);
              box.setSelectedIndex("true".equals(value) ? 0 : 1);
              TableCellEditor result = new DefaultCellEditor(box);
              return result;
            }
            */
            return super.getCellRenderer(row, column);
          }
         
          @Override
          public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
            Component result = super.prepareRenderer(renderer, row, column);
            if (!isCellEditable(row, column) && !isRowSelected(row)) {
              result.setBackground(disabledColor);
            }
            return result;
          }
        };
       
        // If the user selects a row, copy the value to the clipboard
        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
          public void valueChanged(ListSelectionEvent e) {
            if (table.getSelectedRow() >= 0) {
              Object value = table.getValueAt(table.getSelectedRow(), 1);
              if (value != null) {
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                clipboard.setContents(new StringSelection(value.toString()), null);
              }
            }
          }
        });
        imageView.setAlignmentX(JLabel.CENTER_ALIGNMENT);
        imageView.setAlignmentY(JLabel.CENTER_ALIGNMENT);
        imageView.setHorizontalTextPosition(SwingConstants.CENTER);
        imageView.addComponentListener(new ComponentAdapter() {
            public void componentResized(ComponentEvent e) {
                redrawImage();
            }
        });
        imageView.addMouseListener(new MouseAdapter() {
          @Override
          public void mouseReleased(MouseEvent e) {
            int x = e.getX();
            int y = e.getY();
           
            // Scale the point back to what it should be
            x -= location.x;
            y -= location.y;
            x  = (int)(x / scale);
            y  = (int)(y / scale);
            Component comp = SwingUtilities.getDeepestComponentAt(currentNode, x, y);
            jumpToComponent(comp);
          }
        });
        imageView.setMinimumSize(new Dimension(0, 0));
        imageView.setPreferredSize(new Dimension(250, 60));
        imageView.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
       
        tree = new JTree(addComponent(pComp));
        tree.setShowsRootHandles(true);
        tree.setExpandsSelectedPaths(true);
        tree.addTreeSelectionListener(new TreeSelectionListener() {
            public void valueChanged(TreeSelectionEvent e) {
                redrawImage();
                setTableData();
            }
        });
        tree.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent evt) {
                if (evt.isPopupTrigger()) {
                    contextMenu.show(evt.getComponent(), evt.getX(), evt.getY());
                }
            }
            public void mouseReleased(MouseEvent evt) {
                if (evt.isPopupTrigger()) {
                    contextMenu.show(evt.getComponent(), evt.getX(), evt.getY());
                }
            }
        });

        history = new JComboBox();
        tree.addTreeSelectionListener(new TreeSelectionListener() {
          public void valueChanged(TreeSelectionEvent e) {
            if (e.getNewLeadSelectionPath() != null && !disableListener) {
              DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.getNewLeadSelectionPath().getLastPathComponent();
              Component comp = (Component)node.getUserObject();
              TreeHistory path = new TreeHistory(e.getNewLeadSelectionPath());
              history.addItem(path);
              history.setSelectedItem(path);
              owningClassLabel.setText(findClassForComponent(comp));
            }
          }
        });
        history.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
          int i = history.getSelectedIndex();
            TreePath path = ((TreeHistory)history.getSelectedItem()).path;
          tree.setSelectionPath(path);
          tree.scrollPathToVisible(path);
          ((JScrollPane)tree.getParent().getParent()).getHorizontalScrollBar().setValue(0);
          while (i < history.getItemCount()-1 && !disableListener) {
            history.removeItemAt(i);
          }
          }
        });
       
        tree.addKeyListener(new KeyAdapter() {
          public void keyReleased(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
              // Rewind one in the history
              if (history.getItemCount() > 1) {
                disableListener = true;
                history.removeItemAt(history.getItemCount() - 1);
                history.setSelectedIndex(history.getItemCount()-1);
                disableListener = false;
              }
            }
          }
        });
        JScrollPane scrollPane = new JScrollPane(tree);

        table.setModel(new DefaultTableModel(new Object[0][2], new String[] {"Name", "Value"}));
        JScrollPane tablePane = new JScrollPane(table);
        tablePane.setMinimumSize(new Dimension(0,0));
        tablePane.setPreferredSize(new Dimension(0, 0));

        // Create the bottom panel, with a left and a right component
        JSplitPane bottomSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        bottomSplit.setLeftComponent(imageView);
        bottomSplit.setRightComponent(tablePane);
        bottomSplit.setDividerLocation(0.5);
        bottomSplit.setResizeWeight(0.5);

        JSplitPane splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        splitter.setTopComponent(scrollPane);
        splitter.setBottomComponent(bottomSplit);
        splitter.setDividerLocation(0.9);
        splitter.setResizeWeight(0);
       
        JPanel panel = new JPanel() {
            @Override
            public void list(java.io.PrintStream out, int indent) {
              try {
                BeanInfo beanInfo = Introspector.getBeanInfo(currentNode.getClass());
                PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
               
                new TestWin().display(currentNode, properties);
              }
              catch (Exception ex) {
                System.out.println("Unhandled exception in SwingDisplayer");
                ex.printStackTrace();
              }
            }
        };
        panel.setLayout(new BorderLayout());
        setContentPane(panel);
        getContentPane().add(splitter);
        getContentPane().add(BorderLayout.SOUTH, getControlsPanel());
        getContentPane().add(BorderLayout.NORTH, history);
        setSize(800, 700);
        setResizable(true);
        setVisible(true);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        tree.requestFocusInWindow();
        tree.setSelectionRow(0);
    }

    private DefaultMutableTreeNode addComponent(Component pComponent) {
        DefaultMutableTreeNode node = new DefaultMutableTreeNode(pComponent);
        if (pComponent instanceof JMenu){
          for (Component c : ((JMenu)pComponent).getMenuComponents()) {
                DefaultMutableTreeNode newNode = addComponent(c);
                node.add(newNode);
            }
        }
        else if (pComponent instanceof Container) {
            for (Component c : ((Container)pComponent).getComponents()) {
                DefaultMutableTreeNode newNode = addComponent(c);
                node.add(newNode);
            }
        }
        return node;
    }
   
    @SuppressWarnings("unchecked")
  private TreePath findComponentInTree(TreePath root, Component c) {
      if (root != null && c != null) {
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)root.getLastPathComponent();
        if (node.getUserObject() == c) {
          return root;
        }
        else {
            // Traverse children
              if (node.getChildCount() >= 0) {
                  for (Enumeration<TreeNode> e = node.children(); e.hasMoreElements(); ) {
                      TreePath path = root.pathByAddingChild(e.nextElement());
                      TreePath result = findComponentInTree(path, c);
                      // Found a match
                      if (result != null) {
                          return result;
                      }
                  }
              }
        }
      }
      return null;
    }
   
    private JLabel focusOwnerLabel = new JLabel();
    private boolean showTabOrder = true;
    private JLabel owningClassLabel = new JLabel();
    protected JPanel getControlsPanel() {
      JPanel aPanel = new JPanel();
      aPanel.setLayout(new GridBagLayout());
      GridBagConstraints gbc = new GridBagConstraints();
      gbc.gridx = 0;
      gbc.gridy = 0;
      gbc.weightx = 0;
      gbc.insets = new Insets(2, 2, 2, 2);
      gbc.fill = GridBagConstraints.NONE;
      aPanel.add(new JLabel("Current focus owner:"), gbc);
      gbc.fill = GridBagConstraints.HORIZONTAL;
      gbc.weightx = 1;
      gbc.gridx = 1;
      aPanel.add(focusOwnerLabel, gbc);
      focusOwnerLabel.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseEntered(MouseEvent e) {
          focusOwnerLabel.setForeground(Color.blue);
        }
        @Override
        public void mouseClicked(MouseEvent e) {
          jumpToComponent(currentFocusOwner);
        }
        @Override
        public void mouseExited(MouseEvent e) {
          focusOwnerLabel.setForeground(Color.black);
        }
      });
      gbc.gridx = 2;
      gbc.gridy = 0;
      gbc.anchor = GridBagConstraints.EAST;
      gbc.fill = GridBagConstraints.NONE;
      gbc.weightx = 0;
      final JCheckBox showTabOrderCheckBox = new JCheckBox("", true);
      showTabOrderCheckBox.addChangeListener(new ChangeListener() {
        public void stateChanged(ChangeEvent e) {
          showTabOrder = showTabOrderCheckBox.isSelected();
          redrawImage();
        }
      });
      aPanel.add(showTabOrderCheckBox, gbc);
      gbc.gridx = 3;
      gbc.anchor = GridBagConstraints.WEST;
      gbc.weightx = 0;
      JLabel aLabel = new JLabel("Show tabbing order");
      aLabel.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
          showTabOrderCheckBox.setSelected(!showTabOrderCheckBox.isSelected());
        }
      });
      aPanel.add(aLabel, gbc);
      gbc.gridx = 0;
      gbc.gridy = 1;
      gbc.fill = GridBagConstraints.NONE;
      gbc.anchor = GridBagConstraints.EAST;
      aPanel.add(new JLabel("Owning class:"), gbc);
      gbc.gridx = 1;
      gbc.anchor = GridBagConstraints.WEST;
      gbc.weightx = 1;
      aPanel.add(owningClassLabel, gbc);
      return aPanel;
    }
   
    @Override
    protected void processKeyEvent(KeyEvent e) {
      super.processKeyEvent(e);
      if (!e.isConsumed() && e.isShiftDown() && e.isControlDown() && e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_F2) {
        try {
              BeanInfo beanInfo = Introspector.getBeanInfo(this.currentNode.getClass());
              PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
             
              new TestWin().display(this.currentNode, properties);
        }
        catch (Exception ex) {}
      }
    }
}
TOP

Related Classes of DisplayProject.swingdisplayer.SwingDisplayer$TableData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.