001 /* 002 * LAPIS lightweight structured text processing system 003 * 004 * Copyright (C) 1998-2002 Carnegie Mellon University, 005 * Copyright (C) 2003 Massachusetts Institute of Technology. 006 * All rights reserved. 007 * 008 * This library is free software; you can redistribute it 009 * and/or modify it under the terms of the GNU General 010 * Public License as published by the Free Software 011 * Foundation, version 2. 012 * 013 * LAPIS homepage: http://graphics.lcs.mit.edu/lapis/ 014 */ 015 016 package lapisx.swing; 017 018 import java.awt.*; 019 import java.awt.event.*; 020 import javax.swing.*; 021 022 /** 023 * A popup menu that appears only after the mouse is held down for 024 * a certain period of time. 025 */ 026 public class DelayedPopupMenu { 027 Component frame; 028 Component trigger; 029 Timer timer; 030 JPopupMenu menu; 031 032 033 /** 034 * Make a delayed popup menu. 035 * @param frame Component in which the popup menu will appear (see 036 * {@link javax.swing.JPopupMenu#show}. This is often a JFrame. 037 * @param trigger Component which should trigger the menu. 038 * @param delay Delay before showing menu, in milliseconds. 039 * @effects Creates a DelayedPopupMenu and attaches a mouse listener 040 * to <i>trigger</i> so that when the mouse is pressed down <i>trigger</i> 041 * and held for more than <i>delay</i> msec, the menu appears. 042 */ 043 public DelayedPopupMenu (Component frame, Component trigger, int delay) { 044 this.frame = frame; 045 this.trigger = trigger; 046 047 trigger.addMouseListener (new MouseAdapter () { 048 public void mousePressed (MouseEvent event) { 049 timer.restart (); 050 } 051 public void mouseReleased (MouseEvent event) { 052 timer.stop (); 053 054 if (menu != null 055 && menu.isVisible () 056 && !menu.contains 057 (SwingUtilities.convertPoint ((Component) event.getSource (), 058 event.getPoint (), 059 menu))) 060 menu.setVisible (false); 061 } 062 }); 063 064 timer = new Timer (delay, new ActionListener () { 065 public void actionPerformed (ActionEvent event) { 066 menu = makeMenu (); 067 showMenu (menu); 068 } 069 }); 070 timer.setRepeats (false); 071 } 072 073 /** 074 * Test whether menu is popped up. 075 * @return true iff menu is showing 076 */ 077 public boolean isVisible () { 078 return menu != null && menu.isVisible (); 079 } 080 081 /** 082 * Callback that constructs the menu just before showing it. 083 * Default implementation just creates an empty JPopupMenu. 084 * A subclass should override this to populate the menu. 085 * @return menu, or null to prevent popping up the menu 086 */ 087 protected JPopupMenu makeMenu () { 088 return new JPopupMenu (); 089 } 090 091 /** 092 * Callback that shows the menu. 093 * Default implementation positions the menu just below the trigger 094 * that triggered it in the frame passed to the constructor. 095 * A subclass can override this for different placement. 096 * @param menu Menu about to be shown 097 */ 098 protected void showMenu (JPopupMenu menu) { 099 Point triggerLocation = 100 SwingUtilities.convertPoint (trigger.getParent (), 101 trigger.getLocation (), 102 frame); 103 Dimension triggerSize = trigger.getSize (); 104 105 int x = triggerLocation.x; 106 int y = triggerLocation.y + triggerSize.height; 107 108 menu.show (frame, x, y); 109 } 110 111 /** 112 * Get the component that triggers this menu. 113 * @return trigger component 114 */ 115 public Component getTrigger () { 116 return trigger; 117 } 118 119 /** 120 * Get the frame in which this menu will popup. 121 * @return frame component 122 */ 123 public Component getFrame () { 124 return frame; 125 } 126 }