// Near Infinity - An Infinity Engine Browser and Editor // Copyright (C) 2001 - 2005 Jon Olav Hauglid // See LICENSE.txt for license information package org.infinity.gui.layeritem; import java.awt.Cursor; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.Vector; import javax.swing.JComponent; import org.infinity.gui.ViewFrame; import org.infinity.resource.Viewable; /** * Common base class for visual components, representing parts of a game resource */ public abstract class AbstractLayerItem extends JComponent implements MouseListener, MouseMotionListener { /** * Represents the possible visual states of the component */ public enum ItemState { NORMAL, HIGHLIGHTED } private Vector<ActionListener> actionListener; private Vector<LayerItemListener> itemStateListener; private String actionCommand; private Viewable viewable; private Object objData; private String message; private ItemState itemState; private Point location; private Point center; /** * Initialize object with default settings. */ public AbstractLayerItem() { this(null); } /** * Initialize object with the specified map location. * @param location Map location */ public AbstractLayerItem(Point location) { this(location, null); } /** * Initialize object with a specific map location and an associated viewable object. * @param location Map location * @param viewable Associated Viewable object */ public AbstractLayerItem(Point location, Viewable viewable) { this(location, viewable, null); } /** * Initialize object with a specific map location, associated Viewable and an additional text message. * @param location Map location * @param viewable Associated Viewable object * @param msg An arbitrary text message */ public AbstractLayerItem(Point location, Viewable viewable, String msg) { this.actionListener = new Vector<ActionListener>(); this.itemStateListener = new Vector<LayerItemListener>(); this.viewable = viewable; this.itemState = ItemState.NORMAL; this.center = new Point(); setMapLocation(location); setMessage(msg); setActionCommand(null); addMouseListener(this); addMouseMotionListener(this); } public String getActionCommand() { return actionCommand; } public void setActionCommand(String cmd) { if (cmd != null) { actionCommand = cmd; } else { actionCommand = new String(); } } public void addActionListener(ActionListener l) { if (l != null) { actionListener.add(l); } } public ActionListener[] getActionListeners() { ActionListener[] array = new ActionListener[actionListener.size()]; for (int i = 0; i < actionListener.size(); i++) { array[i] = actionListener.get(i); } return array; } public void removeActionListener(ActionListener l) { if (l != null) { actionListener.remove(l); } } public void addLayerItemListener(LayerItemListener l) { if (l != null) { itemStateListener.add(l); } } public LayerItemListener[] getLayerItemListeners() { LayerItemListener[] array = new LayerItemListener[itemStateListener.size()]; for (int i = 0; i < itemStateListener.size(); i++) { array[i] = itemStateListener.get(i); } return array; } public void removeLayerItemListener(LayerItemListener l) { if (l != null) { itemStateListener.remove(l); } } /** * Moves this component to the specified location. Takes item-specific corrections into account. * @param x New x coordinate * @param y New y coordinate */ public void setItemLocation(int x, int y) { setLocation(x - center.x, y - center.y); } /** * Moves this component to the specified location. Takes item-specific corrections into account. * @param p New location */ public void setItemLocation(Point p) { if (p == null) { p = new Point(0, 0); } setLocation(new Point(p.x - center.x, p.y - center.y)); } /** * Returns the map location of the item. * @return Map location of the item. */ public Point getMapLocation() { return location; } /** * Sets a new map location of the item. * @param location New map location of the item. */ public void setMapLocation(Point location) { if (location != null) { this.location = location; } else { location = new Point(0, 0); } } /** * Set a simple text message which can be queried at a given time * @param msg The text message */ public void setMessage(String msg) { if (msg != null) { message = new String(msg); } else { message = new String(); } } /** * Returns a simple text message associated with the component. * @return A text message. */ public String getMessage() { return message; } /** * Returns a String representation of this object. */ @Override public String toString() { return getMessage(); } /** * Returns the item's current visual state. * @return The item's current visual state. */ public ItemState getItemState() { return itemState; } /** * Attaches a custom data object to this layer item. * @param data The data item to attach. */ public void setData(Object data) { objData = data; } /** * Returns the custom data object that has been attached to this layer item. * @return The custom data object attached to this layer item. */ public Object getData() { return objData; } /** * Associates a new Viewable object with the component * @param v The new viewable. */ public void setViewable(Viewable v) { viewable = v; } /** * Returns the current Viewable object associated with the component. * @return The current Viewable object associated with the component. */ public Viewable getViewable() { return viewable; } /** * Opens the current Viewable object associated with the component, if any. */ public void showViewable() { if (viewable != null && getTopLevelAncestor() != null) { new ViewFrame(getTopLevelAncestor(), (Viewable)viewable); } } //--------------------- Begin Interface MouseListener --------------------- @Override public void mouseClicked(MouseEvent event) { } @Override public void mouseEntered(MouseEvent event) { if (isMouseOver(event.getPoint())) { setItemState(ItemState.HIGHLIGHTED); } } @Override public void mouseExited(MouseEvent event) { setItemState(ItemState.NORMAL); } @Override public void mousePressed(MouseEvent event) { if (isMouseOver(event.getPoint())) { setMouseClicked(event.getButton()); } } @Override public void mouseReleased(MouseEvent event) { if (isMouseOver(event.getPoint())) { setItemState(ItemState.HIGHLIGHTED); } else { setItemState(ItemState.NORMAL); } } //--------------------- End Interface MouseListener --------------------- //--------------------- Begin Interface MouseMotionListener --------------------- @Override public void mouseDragged(MouseEvent event) { } @Override public void mouseMoved(MouseEvent event) { if (isMouseOver(event.getPoint())) { setItemState(ItemState.HIGHLIGHTED); } else { setItemState(ItemState.NORMAL); } } //--------------------- End Interface MouseMotionListener --------------------- @Override public String getToolTipText(MouseEvent event) { // Tooltip is only displayed over visible areas of this component if (isMouseOver(event.getPoint())) { return message; } else { return null; } } @Override public boolean contains(int x, int y) { // Non-visible parts of the component are disregarded by mouse events return isMouseOver(new Point(x, y)); } // Returns whether the mouse cursor is over the relevant part of the component protected boolean isMouseOver(Point pt) { if (pt != null) { return getBounds().contains(pt); } else { return false; } } // Adds an offset to the component's position protected void setLocationOffset(Point ofs) { if (ofs != null) { center.x = ofs.x; center.y = ofs.y; } } // Returns the offset to the component's position protected Point getLocationOffset() { return center; } private void setItemState(ItemState newState) { if (itemState != newState) { itemState = newState; if (!itemStateListener.isEmpty()) { LayerItemEvent ise = new LayerItemEvent(this, actionCommand); for (final LayerItemListener l: itemStateListener) l.layerItemChanged(ise); } if (itemState == ItemState.HIGHLIGHTED) { setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } else { setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } } } private void setMouseClicked(int button) { if ((button == MouseEvent.BUTTON1) && !actionListener.isEmpty()) { // processing left mouse click event ActionEvent ae = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, actionCommand); for (final ActionListener l: actionListener) { l.actionPerformed(ae); } } else if (button == MouseEvent.BUTTON2) { // processing right mouse click event } else if (button == MouseEvent.BUTTON3) { // processing middle mouse click event } } }