2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.core.windows.view.ui.slides;
44
import java.awt.AWTEvent;
45
import java.awt.Component;
46
import java.awt.Point;
47
import java.awt.Rectangle;
48
import java.awt.Toolkit;
49
import java.awt.Window;
50
import java.awt.event.AWTEventListener;
51
import java.awt.event.ActionEvent;
52
import java.awt.event.ActionListener;
53
import java.awt.event.MouseAdapter;
54
import java.awt.event.MouseEvent;
55
import java.awt.event.MouseListener;
56
import java.awt.event.MouseMotionListener;
57
import java.beans.PropertyChangeEvent;
58
import java.beans.PropertyChangeListener;
59
import java.util.List;
60
import javax.swing.AbstractButton;
61
import javax.swing.SwingUtilities;
62
import javax.swing.Timer;
63
import org.netbeans.swing.tabcontrol.SlideBarDataModel;
64
import org.openide.util.WeakListeners;
65
import org.openide.windows.TopComponent;
67
/* Listens to user actions that trigger sliding operation such as slide in
68
* slide out or popup menu action to be invoked.
70
* @author Dafe Simonek
72
final class SlideGestureRecognizer implements ActionListener, MouseListener, MouseMotionListener {
73
/** container of sliding buttons */
74
private SlideBar slideBar;
75
/** button in which area mouse pointer is or null */
76
private Component mouseInButton = null;
77
/** current location of mouse pointer */
78
private int curMouseLocX, curMouseLocY;
80
/** Listsner to timer notifications */
81
private AutoSlideTrigger autoSlideTrigger = new AutoSlideTrigger();
82
private ResizeGestureRecognizer resizer;
83
private boolean pressingButton = false;
85
SlideGestureRecognizer(SlideBar slideBar, ResizeGestureRecognizer resize) {
86
this.slideBar = slideBar;
90
/** Attaches given button to this recognizer, it means starts listening
91
* on its various mouse and action events
93
public void attachButton (AbstractButton button) {
94
button.addActionListener(this);
95
button.addMouseListener(this);
96
button.addMouseMotionListener(this);
99
/** Detaches given button from this recognizer, it means stops listening
100
* on its various mouse and action events
102
public void detachButton (AbstractButton button) {
103
button.removeActionListener(this);
104
button.removeMouseListener(this);
105
button.addMouseMotionListener(this);
108
/** Reaction to user press on some of the slide buttons */
109
public void actionPerformed(ActionEvent e) {
110
slideBar.userClickedSlidingButton((Component)e.getSource());
113
/** Tracks mouse pointer location */
114
public void mouseMoved(MouseEvent e) {
115
if (autoSlideTrigger.isEnabled()) {
116
curMouseLocX = e.getX();
117
curMouseLocY = e.getY();
120
if (pressingButton && (e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0) {
121
pressingButton = false;
122
autoSlideTrigger.activateAutoSlideInGesture();
127
/** Activates automatic slide in system */
128
public void mouseEntered(MouseEvent e) {
129
if (!slideBar.isHoveringAllowed()) {
130
// don't even try to trigger automatic sliding when focused slide is active
133
mouseInButton = (Component)e.getSource();
134
curMouseLocX = e.getX();
135
curMouseLocY = e.getY();
136
pressingButton =false;
138
if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == MouseEvent.BUTTON1_DOWN_MASK) {
139
pressingButton = true;
143
autoSlideTrigger.activateAutoSlideInGesture();
146
/** Deactivates automatic slide in listening */
147
public void mouseExited(MouseEvent e) {
148
mouseInButton = null;
149
pressingButton = false;
150
autoSlideTrigger.deactivateAutoSlideInGesture();
153
/** Reacts to popup triggers on sliding buttons */
154
public void mousePressed(MouseEvent e) {
155
autoSlideTrigger.deactivateAutoSlideInGesture();
156
handlePopupRequests(e);
159
/** Reacts to popup triggers on sliding buttons */
160
public void mouseReleased(MouseEvent e) {
161
autoSlideTrigger.deactivateAutoSlideInGesture();
162
handlePopupRequests(e);
165
public void mouseDragged(MouseEvent e) {
169
public void mouseClicked(MouseEvent e) {
173
/** Sends message to show popup menu on button if conditions are met */
174
private void handlePopupRequests (MouseEvent e) {
175
// don't react on popup triggers on whole bar
176
if (e.getSource().equals(slideBar)) {
180
if (e.isPopupTrigger()) {
181
slideBar.userTriggeredPopup(e, (Component)e.getSource());
185
/** Listen to timer notifications and mouse AWT events to start/stop
186
* auto slide in/slide out operation */
187
private final class AutoSlideTrigger implements ActionListener, AWTEventListener {
189
/** timer for triggering slide in after mouse stops for a while */
190
private Timer slideInTimer;
191
/** location of mouse pointer in last timer cycle */
192
private int initialX, initialY;
193
/** true when auto slide-in was performed and is visible, false ootherwise */
194
private boolean autoSlideActive = false;
195
/** union of slide bar and slided component bounds;
196
escape of mouse pointer from this area means auto slide out to be triggered */
197
private Rectangle activeArea;
201
slideInTimer = new Timer(200, this);
202
slideInTimer.setRepeats(true);
203
slideInTimer.setCoalesce(true);
206
/** Starts listening to user events that may lead to automatic slide in */
207
public void activateAutoSlideInGesture() {
208
initialX = curMouseLocX;
209
initialY = curMouseLocY;
210
slideInTimer.start();
213
/** Stops listening to user events that may lead to automatic slide in */
214
public void deactivateAutoSlideInGesture() {
218
/** @return true when auto slide system is listening and active, false ootherwise */
219
public boolean isEnabled() {
220
return autoSlideActive || slideInTimer.isRunning();
223
/** Action listener implementation - reacts to timer notification, which
224
* means we should check conditions and perform auto slide in if appropriate
226
public void actionPerformed(ActionEvent evt) {
227
if (isSlideInGesture()) {
229
// multiple auto slide in requests, get rid of old one first
230
if (autoSlideActive) {
233
autoSlideActive = true;
234
// #45494 - rarely, mouseInButton value can be out of sync
235
// with SlideBar buttons array, and we don't slide in in such case
236
if (slideBar.userTriggeredAutoSlideIn(mouseInButton)) {
237
Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.MOUSE_MOTION_EVENT_MASK);
239
autoSlideActive = false;
242
initialX = curMouseLocX;
243
initialY = curMouseLocY;
247
/** AWTEventListener implementation. Analyzes incoming mouse motion
248
* and initiates automatic slide out when needed.
250
public void eventDispatched(AWTEvent event) {
251
autoSlideOutIfNeeded((MouseEvent)event);
254
/** Checks conditions and runs auto slide out if needed.
256
private void autoSlideOutIfNeeded(MouseEvent evt) {
257
if (!autoSlideActive) {
258
// ignore pending events that came later after cleanup
261
if (slideBar.isActive()) {
262
// if slide bar is active (focused), we should do no more automatic things
266
if (isSlideOutGesture(evt)) {
272
/** Actually performs slide out by notifying slide bar */
273
private void autoSlideOut() {
274
slideBar.userTriggeredAutoSlideOut();
277
/** Removea all attached listeners and generally stops to try run
278
* sliding automatically */
279
private void cleanup() {
280
Toolkit.getDefaultToolkit().removeAWTEventListener(this);
281
autoSlideActive = false;
285
/** @return true when conditions for auto slide IN were met, false otherwise */
286
private boolean isSlideInGesture () {
287
if (mouseInButton == null) {
291
int diffX = Math.abs(initialX - curMouseLocX);
292
int diffY = Math.abs(initialY - curMouseLocY);
294
return (diffX <= 2) && (diffY <= 2);
297
/** @return true when conditions for auto slide OUT were met, false otherwise */
298
private boolean isSlideOutGesture(MouseEvent evt) {
299
if (resizer.isDragging()) {
303
if (activeArea == null) {
304
activeArea = computeActiveArea();
305
// comps are not yet ready, so do nothing
306
if (activeArea == null) {
310
Point mouseLoc = evt.getPoint();
312
if (! (evt.getSource() instanceof Component)) {
316
SwingUtilities.convertPointToScreen(mouseLoc, (Component)evt.getSource());
318
return !activeArea.contains(mouseLoc);
321
/** @return Area in which automatic slide in is preserved. Can return
322
* null signalizing that components making active area bounds are not yet
325
private Rectangle computeActiveArea() {
326
Component slidedComp = slideBar.getSlidedComp();
327
if (slidedComp == null || !slidedComp.isShowing()) {
331
Point slideBarLoc = slideBar.getLocationOnScreen();
332
Rectangle actArea = new Rectangle(slideBarLoc.x - 1, slideBarLoc.y - 1,
333
slideBar.getWidth() - 1, slideBar.getHeight() - 1);
335
Point slidedCompLoc = slidedComp.getLocationOnScreen();
337
int slidex = slidedCompLoc.x;
338
int slidey = slidedCompLoc.y;
339
int slideh = slidedComp.getHeight();
340
int slidew = slidedComp.getWidth();
341
int orientation = slideBar.getModel().getOrientation();
342
if (orientation == SlideBarDataModel.WEST) {
343
slidew = slidew + ResizeGestureRecognizer.RESIZE_BUFFER;
345
if (orientation == SlideBarDataModel.EAST) {
346
slidew = slidew + ResizeGestureRecognizer.RESIZE_BUFFER;
347
slidex = slidex - ResizeGestureRecognizer.RESIZE_BUFFER;
349
if (orientation == SlideBarDataModel.SOUTH) {
350
slideh = slideh + ResizeGestureRecognizer.RESIZE_BUFFER;
351
slidey = slidey - ResizeGestureRecognizer.RESIZE_BUFFER;
353
actArea = SwingUtilities.computeUnion(
354
slidex, slidey, slidew,
361
} // AutoSlideTrigger
b'\\ No newline at end of file'