Package org.beryl.gui.swing.plaf

Source Code of org.beryl.gui.swing.plaf.IconViewUI

/*
* Beryl - A web platform based on XML, XSLT and Java
* This file is part of the Beryl XML GUI
*
* Copyright (C) 2004 Wenzel Jakob <wazlaf@tigris.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.

* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-3107  USA
*/

package org.beryl.gui.swing.plaf;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.IllegalComponentStateException;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.ListModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalLookAndFeel;

import org.beryl.gui.swing.IconElement;
import org.beryl.gui.swing.JIconView;

/**
* JIconView - A simple Java icon view widget
* Portable look and feel implementation
* @version 2.0
* @author Wenzel Jakob
*/

public class IconViewUI extends ComponentUI {
  private static final int UP = 1;
  private static final int DOWN = 2;
  private static final int LEFT = 3;
  private static final int RIGHT = 4;
  private JIconView view = null;
  private MouseInputListener mouseListener = null;
  private MouseMotionListener motionListener = null;
  private FocusListener focusListener = null;
  private ListSelectionListener selectionListener = null;
  private ListDataListener dataListener = null;
  private PropertyChangeListener changeListener = null;
  private int oldIndex = -1, textHeight = 0;
  private FontMetrics metrics = null;

  private class DirectionAction extends AbstractAction {
    private int direction = -1;

    public DirectionAction(int direction, String name) {
      super(name);
      this.direction = direction;
    }

    public void actionPerformed(ActionEvent evt) {
      int xcols = view.getSize().width / view.getXCellSize();
     
      if (direction == RIGHT) {
        view.setSelectedIndex(view.getSelectedIndex() + 1);
      } else if (direction == LEFT) {
        if (view.getSelectedIndex() != 0)
          view.setSelectedIndex(view.getSelectedIndex() - 1);
      } else if (direction == UP) {
        if (view.getSelectedIndex() != xcols - 1)
          view.setSelectedIndex(view.getSelectedIndex() - xcols);
      } else if (direction == DOWN) {
        view.setSelectedIndex(view.getSelectedIndex() + xcols);
      }
    }
  }

  /* ========== Handlers ========== */

  private class MouseInputHandler extends MouseInputAdapter {
    public void mousePressed(MouseEvent e) {
      if (view.getModel() == null || !SwingUtilities.isLeftMouseButton(e))
        return;
      if (!view.hasFocus())
        view.requestFocus();

      int index = getIndexForRowColumn(convertYToRow(e.getY()), convertXToColumn(e.getX()));
      if (index != -1 && checkBoundingBox(e.getX(), e.getY(), index))
        view.setSelectedIndex(index);
      else
        view.setSelectedIndex(-1);
    }
  }
 
  private class MouseMotionHandler extends MouseMotionAdapter {   
    public void mouseMoved(MouseEvent e) {
      if (view.getModel() == null || (!view.getHandCursorEnabled()))
        return;

      int index = getIndexForRowColumn(convertYToRow(e.getY()), convertXToColumn(e.getX()));
      if (index != -1 && checkBoundingBox(e.getX(), e.getY(), index))
        view.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
      else
        view.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    }
  }


  private class FocusHandler implements FocusListener {
    protected void repaintFocused() {
      int index = view.getSelectedIndex();
      if (index != -1)
        view.repaint(getBounds(index, index));
    }
    public void focusGained(FocusEvent e) {
      repaintFocused();
    }

    public void focusLost(FocusEvent e) {
      repaintFocused();
    }
  }

  private class ListSelectionHandler implements ListSelectionListener {
    public void valueChanged(ListSelectionEvent e) {
      int index = view.getSelectedIndex();
      if (oldIndex != -1) {
        view.repaint(getBounds(oldIndex, oldIndex));
      }
      if (index != -1) {
        view.repaint(getBounds(index, index));
      }
      oldIndex = index;
    }
  }

  private class ListDataHandler implements ListDataListener {
    public void intervalAdded(ListDataEvent e) {
      contentsChanged(e);
    }

    public void intervalRemoved(ListDataEvent e) {
      contentsChanged(e);
    }

    public void contentsChanged(ListDataEvent e) {
      int index = view.getSelectedIndex();
      if (index != -1 && view.getModel().getSize() >= index) {
        view.setSelectedIndex(-1);
      }
      view.repaint();
    }
  };

  private class PropertyChangeHandler implements PropertyChangeListener {
    public void propertyChange(PropertyChangeEvent event) {
      String name = event.getPropertyName();
      if (name.equals(JIconView.MODEL_PROPERTY)) {
        ListModel model = (ListModel) event.getOldValue();
        if (model != null)
          model.removeListDataListener(dataListener);
        model = (ListModel) event.getNewValue();
        if (model != null) {
          dataListener = new ListDataHandler();
          model.addListDataListener(dataListener);
        }
      } else if (
        name.equals(JIconView.XCELLSIZE_PROPERTY)
          || name.equals(JIconView.YCELLSIZE_PROPERTY)
          || name.equals(JIconView.ICONTEXTSPACING_PROPERTY)) {
        view.repaint();
      }
    }
  }

  /* ========== UI functions ========== */

  public IconViewUI() {
    super();
  }

  public static ComponentUI createUI(JComponent c) {
    return new IconViewUI();
  }

  public void installUI(JComponent component) {
    view = (JIconView) component;
    ListModel model = view.getModel();
    if (model != null) {
      dataListener = new ListDataHandler();
      model.addListDataListener(dataListener);
    }
    changeListener = new PropertyChangeHandler();
    mouseListener = new MouseInputHandler();
    focusListener = new FocusHandler();
    selectionListener = new ListSelectionHandler();
    motionListener = new MouseMotionHandler();
    view.addPropertyChangeListener(changeListener);
    view.addMouseListener(mouseListener);
    view.addFocusListener(focusListener);
    view.addListSelectionListener(selectionListener);
    view.addMouseMotionListener(motionListener);
    view.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "UP");
    view.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "DOWN");
    view.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "LEFT");
    view.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "RIGHT");
    view.getActionMap().put("UP", new DirectionAction(UP, "UP"));
    view.getActionMap().put("DOWN", new DirectionAction(DOWN, "DOWN"));
    view.getActionMap().put("LEFT", new DirectionAction(LEFT, "LEFT"));
    view.getActionMap().put("RIGHT", new DirectionAction(RIGHT, "RIGHT"));
  }

  public void uninstallUI(JComponent component) {
    if (view != component)
      throw new IllegalComponentStateException("could not uninstall component");
    view.removePropertyChangeListener(changeListener);
    view.removeFocusListener(focusListener);
    view.removeMouseListener(mouseListener);
    view.removeListSelectionListener(selectionListener);
    view.removeMouseMotionListener(motionListener);
    ListModel model = view.getModel();
    if (model != null)
      model.removeListDataListener(dataListener);
    view.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0));
    view.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0));
    view.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0));
    view.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
  }

  /* ========== Calculation functions ========== */

  private int convertRowToY(int row) {
    return view.getYCellSize() * row + view.getInsets().top;
  }

  private int convertColumnToX(int column) {
    return view.getXCellSize() * column + view.getInsets().left;
  }

  private int getColumns() {
    return (int) Math.floor(
      (view.getSize().width - view.getInsets().left - view.getInsets().right) / (float) view.getXCellSize());
  }

  private int convertXToColumn(int x) {
    return (int) Math.floor((x - view.getInsets().left) / (float) view.getXCellSize());
  }

  private int convertYToRow(int y) {
    return (int) Math.floor((y - view.getInsets().top) / (float) view.getYCellSize());
  }

  private int getIndexForRowColumn(int row, int column) {
    int xcols = getColumns();
    int index = xcols * row + column;
    if (column >= xcols || index >= view.getModel().getSize())
      return -1;
    return index;
  }

  private int getIndexForXY(int x, int y) {
    return getIndexForRowColumn(convertYToRow(y), convertXToColumn(x));
  }

  private int[] getRowColumnForIndex(int index) {
    int value[] = new int[2];
    int xcols = getColumns();
    value[0] = (int) Math.floor(index / (float) xcols);
    value[1] = index - value[0] * xcols;
    return value;
  }

  private Rectangle getBounds(int index1, int index2) {
    int rc1[] = getRowColumnForIndex(Math.min(index1, index2));
    int rc2[] = getRowColumnForIndex(Math.max(index1, index2));
    int y1 = convertRowToY(rc1[0]), y2 = convertRowToY(rc2[0]);
    int x1 = convertColumnToX(rc1[1]), x2 = convertColumnToX(rc2[1]);

    if (y1 != y2) {
      x1 = view.getInsets().left;
      x2 = view.getSize().width - view.getInsets().right;
    }
    x2 += view.getXCellSize();
    y2 += view.getYCellSize();
    return new Rectangle(x1, y1, x2, y2);
  }

  private boolean checkBoundingBox(int x, int y, int index) {
    IconElement icon = (IconElement) view.getModel().getElementAt(index);
    int xcell = view.getXCellSize(), ycell = view.getYCellSize();
    int iconWidth = icon.getIcon().getIconWidth();
    int iconHeight = icon.getIcon().getIconHeight();
    int spacing = view.getIconTextSpacing();
    int stringWidth = metrics.stringWidth(icon.getText());
    int center = ycell / 2 - (textHeight + iconHeight + spacing) / 2;
    x = x % xcell;
    y = y % ycell;

    if (x > (xcell / 2 - iconWidth / 2)
      && x <= (xcell / 2 + iconWidth / 2)
      && y > center
      && y <= center + iconHeight + spacing + 1)
      return true;
    if (x > ((xcell - stringWidth) / 2)
      && x <= ((xcell + stringWidth) / 2 + 1)
      && y > (iconHeight + spacing + center + 1)
      && y <= textHeight + iconHeight + spacing + center + 3)
      return true;
    return false;
  }

  /* ========== Size functions ========== */

  public Dimension getMinimumSize(JComponent component) {
    return new Dimension(view.getXCellSize(), view.getYCellSize());
  }

  public Dimension getPreferredSize(JComponent component) {
    /* Relations between width and height are not yet possible in
     * swing, this is a functioning workaround */
    Dimension dimension = new Dimension();
    Dimension current = view.getSize();
    Insets insets = view.getInsets();
    if (view.getModel() != null) {
      if (current.width == 0) {
        int length = (int) Math.sqrt(view.getModel().getSize());

        dimension.width = length * view.getXCellSize() + insets.left + insets.right;
        dimension.height = length * view.getYCellSize() + insets.top + insets.bottom;
      } else {
        int width = view.getSize().width;
        int xcells = (int) Math.floor((float) width / (float) view.getXCellSize());
        if (xcells == 0)
          xcells = 1;
        int ycells = (int) Math.ceil((float) view.getModel().getSize() / (float) xcells);

        int parentHeight = view.getParent().getSize().height;
        dimension.width = xcells * view.getXCellSize() + insets.left + insets.right;
        dimension.height = ycells * view.getYCellSize() + insets.top + insets.bottom;
        if (parentHeight > dimension.height)
          dimension.height = parentHeight;
      }
    } else {
      return getMinimumSize(component);
    }
    return dimension;
  }

  /* ========== Paint ========== */

  public void paint(Graphics g, JComponent component) {
    if (component != view || view.getModel() == null)
      return;
    Graphics2D g2 = (Graphics2D) g;

    ListModel model = view.getModel();
    Rectangle paintBounds = g.getClipBounds();
    Insets insets = view.getInsets();
    Dimension size = view.getSize();
    int modelSize = model.getSize();
    int xcell = view.getXCellSize(), ycell = view.getYCellSize(), counter = 0;
    metrics = g.getFontMetrics(view.getFont());
   
    if (metrics == null) {
      throw new RuntimeException("Could not resolve font metrics");
    }

    textHeight = metrics.getHeight();

    /* Fix sizes */
    if (paintBounds.x < insets.left)
      paintBounds.x = insets.left;
    if (paintBounds.width > size.width - insets.left - insets.right)
      paintBounds.width = size.width - insets.left - insets.right;
    if (paintBounds.y < insets.top)
      paintBounds.y = insets.top;
    if (view.getParent() instanceof JViewport) {
      paintBounds.height += 2 * ycell;
      if (paintBounds.height > size.height - insets.top - insets.bottom + ycell)
        paintBounds.height = size.height - insets.top - insets.bottom + ycell;
    } else {
      if (paintBounds.height > size.height - insets.top - insets.bottom)
        paintBounds.height = size.height - insets.top - insets.bottom;
    }

    /* Clear background */
    g.setColor(view.getBackground());
    g.fillRect(paintBounds.x, paintBounds.y, paintBounds.width, paintBounds.height);
    g.setColor(view.getForeground());

    int result[] = new int[(paintBounds.width / xcell) * (paintBounds.height / ycell)];
    for (int y = paintBounds.y; y < paintBounds.y + paintBounds.height; y += ycell) {
      for (int x = paintBounds.x; x <= paintBounds.x + paintBounds.width; x += xcell) {
        int index = getIndexForXY(x, y);
        if (index == -1)
          continue;
        int pos[] = getRowColumnForIndex(index);
        int xpos = convertColumnToX(pos[1]);
        int ypos = convertRowToY(pos[0]);
        IconElement element = (IconElement) model.getElementAt(index);
        ImageIcon icon = element.getIcon();
        String name = element.getText();
        int stringWidth = metrics.stringWidth(name);
        int iconHeight = icon.getIconHeight();
        int spacing = view.getIconTextSpacing();
        int center = ycell / 2 - (textHeight + iconHeight + spacing) / 2;

        if (stringWidth > xcell) {
          while (stringWidth > xcell) {
            name = name.substring(0, name.length() - 1);
            stringWidth = metrics.stringWidth(name + "..");
          }
          name += "..";
        }

        g.drawImage(icon.getImage(), xpos + (xcell - icon.getIconWidth()) / 2, ypos + center, null);
        if (view.getSelectedIndex() == index) {
          if (view.hasFocus()) {
            g2.setColor(Color.darkGray);
            g2.setStroke(
              new BasicStroke(
                1.0f,
                BasicStroke.CAP_BUTT,
                BasicStroke.JOIN_MITER,
                1.0f,
                new float[] { 1.0f },
                0.0f));
            g2.draw(
              new Rectangle2D.Double(
                xpos + (xcell - icon.getIconWidth()) / 2 - 1,
                ypos + center - 2,
                icon.getIconWidth() + 2,
                iconHeight + 2));
            g.setColor(MetalLookAndFeel.getTextHighlightColor());
          } else {
            g.setColor(MetalLookAndFeel.getControlDisabled());
          }
          g.fillRect(
            xpos + (xcell - stringWidth) / 2,
            ypos + iconHeight + 3 + center,
            stringWidth + 2,
            textHeight + 2);
        }
        g.setColor(view.getForeground());
        g.drawString(name, xpos + (xcell - stringWidth) / 2, ypos + textHeight + iconHeight + spacing + center);
      }
    }
  }
}
TOP

Related Classes of org.beryl.gui.swing.plaf.IconViewUI

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.