001: /*=============================================================================
002: * Copyright Texas Instruments, Inc., 2002. All Rights Reserved.
003: *
004: * This program is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package ti.chimera;
020:
021: import java.util.Iterator;
022: import javax.swing.*;
023: import java.awt.event.*;
024:
025: import ti.exceptions.ProgrammingErrorException;
026:
027: /**
028: * A utility <code>MouseListener</code> which can be used to trigger something,
029: * such as displaying a pop-up menu, in response to a particular mouse event,
030: * in particular clicking mouse button 2 or 3, or clicking and holding any
031: * button for a length of time. Any place that may display a popup menu should
032: * use this to preserve a consistant look and feel, and also to properly
033: * support single button mice.
034: * <p>
035: * Perhaps this should implement KeyListener or something like that... that
036: * way a certain key sequence could trigger a popup??
037: * <p>
038: * NOTE: netbeans has an interesting idea, using the mousePressed and
039: * mouseReleased events to determine when to display the pop-up; they
040: * claim it is more reliable that using mouseClicked. If there are
041: * problems with this, have a look at how they do it in the utility
042: * class org.openide.awt.MouseUtils.PopupMouseAdapter.
043: *
044: * @author Rob Clark
045: * @version 0.0
046: */
047: public class PopupTrigger extends MouseAdapter implements
048: MouseMotionListener {
049: private MouseDownTimer mouseDownTimer = null;
050: private PopupListener l;
051:
052: /**
053: * For the "click-and-hold" trigger, this is the threshold used to determine
054: * how much movement is permissible before the "click-and-hold" becomes a
055: * "click-and-drag".
056: */
057: private static final int CLICK_AND_HOLD_DISTANCE = 5;
058:
059: /**
060: * This interface should be implemented by the user of this utility mouse
061: * listener.
062: */
063: public interface PopupListener {
064: /**
065: * This method is called when it is determined that a popup menu should
066: * be displayed. It is called with the {@link MouseEvent} that triggers
067: * the popup to be shown, and it's x and y coordinates can be used as the
068: * position to display the popup.
069: *
070: * @param evt the event triggering the popup
071: */
072: public void showPopup(MouseEvent evt);
073: }
074:
075: /**
076: * Class Constructor.
077: *
078: * @param l the listener to call when popup trigger has occured
079: */
080: public PopupTrigger(PopupListener l) {
081: this .l = l;
082: }
083:
084: /* Everything below here is implementation...
085: */
086:
087: public synchronized void mouseClicked(MouseEvent evt) {
088: int mod = evt.getModifiers();
089:
090: if (((mod & InputEvent.BUTTON2_MASK) != 0)
091: || ((mod & InputEvent.BUTTON3_MASK) != 0)) {
092: l.showPopup(evt);
093: }
094:
095: cancelTimer();
096: }
097:
098: public synchronized void mousePressed(MouseEvent evt) {
099: if (mouseDownTimer == null) {
100: mouseDownTimer = new MouseDownTimer(evt);
101: mouseDownTimer.start();
102: }
103: }
104:
105: public synchronized void mouseReleased(MouseEvent evt) {
106: cancelTimer();
107: }
108:
109: public void mouseMoved(MouseEvent evt) {
110: if (mouseDownTimer != null) {
111: int dx = evt.getX() - mouseDownTimer.evt.getX();
112: int dy = evt.getY() - mouseDownTimer.evt.getY();
113:
114: if (((dx * dx) + (dy * dy)) > (CLICK_AND_HOLD_DISTANCE * CLICK_AND_HOLD_DISTANCE))
115: cancelTimer();
116:
117: evt.consume();
118: }
119: }
120:
121: public void mouseDragged(MouseEvent evt) {
122: mouseMoved(evt);
123: }
124:
125: private void cancelTimer() {
126: if (mouseDownTimer != null) {
127: mouseDownTimer.stop();
128: mouseDownTimer = null;
129: }
130: }
131:
132: private class MouseDownTimer extends Timer {
133: MouseEvent evt;
134:
135: MouseDownTimer(MouseEvent evt) {
136: super (500, null);
137:
138: this .evt = evt;
139:
140: addActionListener(new AbstractAction() {
141:
142: public void actionPerformed(ActionEvent e) {
143: stop();
144: l.showPopup(MouseDownTimer.this .evt);
145: }
146:
147: });
148: }
149: }
150: }
151:
152: /*
153: * Local Variables:
154: * tab-width: 2
155: * indent-tabs-mode: nil
156: * mode: java
157: * c-indentation-style: java
158: * c-basic-offset: 2
159: * eval: (c-set-offset 'substatement-open '0)
160: * eval: (c-set-offset 'case-label '+)
161: * eval: (c-set-offset 'inclass '+)
162: * eval: (c-set-offset 'inline-open '0)
163: * End:
164: */
|