~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to core/windows/src/org/netbeans/core/windows/view/ui/slides/SlideGestureRecognizer.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
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]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
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.
 
29
 *
 
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.
 
40
 */
 
41
 
 
42
package org.netbeans.core.windows.view.ui.slides;
 
43
 
 
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;
 
66
 
 
67
/* Listens to user actions that trigger sliding operation such as slide in
 
68
 * slide out or popup menu action to be invoked.
 
69
 *
 
70
 * @author Dafe Simonek
 
71
 */
 
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;
 
79
    
 
80
    /** Listsner to timer notifications */
 
81
    private AutoSlideTrigger autoSlideTrigger = new AutoSlideTrigger();
 
82
    private ResizeGestureRecognizer resizer;
 
83
    private boolean pressingButton = false;
 
84
 
 
85
    SlideGestureRecognizer(SlideBar slideBar, ResizeGestureRecognizer resize) {
 
86
        this.slideBar = slideBar;
 
87
        resizer = resize;
 
88
    }
 
89
 
 
90
    /** Attaches given button to this recognizer, it means starts listening
 
91
     * on its various mouse and action events
 
92
     */
 
93
    public void attachButton (AbstractButton button) {
 
94
        button.addActionListener(this);
 
95
        button.addMouseListener(this);
 
96
        button.addMouseMotionListener(this);
 
97
    }
 
98
    
 
99
    /** Detaches given button from this recognizer, it means stops listening
 
100
     * on its various mouse and action events
 
101
     */
 
102
    public void detachButton (AbstractButton button) {
 
103
        button.removeActionListener(this);
 
104
        button.removeMouseListener(this);
 
105
        button.addMouseMotionListener(this);
 
106
    }
 
107
 
 
108
    /** Reaction to user press on some of the slide buttons */
 
109
    public void actionPerformed(ActionEvent e) {
 
110
        slideBar.userClickedSlidingButton((Component)e.getSource());
 
111
    }
 
112
 
 
113
    /** Tracks mouse pointer location */
 
114
    public void mouseMoved(MouseEvent e) {
 
115
        if (autoSlideTrigger.isEnabled()) {
 
116
            curMouseLocX = e.getX();
 
117
            curMouseLocY = e.getY();
 
118
        }
 
119
        // #54764 - start
 
120
        if (pressingButton && (e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0) {
 
121
            pressingButton = false;
 
122
            autoSlideTrigger.activateAutoSlideInGesture(); 
 
123
        }
 
124
        // #54764 - end
 
125
    }
 
126
 
 
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
 
131
            return;
 
132
        }
 
133
        mouseInButton = (Component)e.getSource();
 
134
        curMouseLocX = e.getX();
 
135
        curMouseLocY = e.getY();
 
136
        pressingButton =false;
 
137
        // #54764 - start
 
138
        if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == MouseEvent.BUTTON1_DOWN_MASK) {
 
139
            pressingButton = true;
 
140
            return;
 
141
        }
 
142
        // #54764 - end
 
143
        autoSlideTrigger.activateAutoSlideInGesture();
 
144
    }
 
145
 
 
146
    /** Deactivates automatic slide in listening */
 
147
    public void mouseExited(MouseEvent e) {
 
148
        mouseInButton = null;
 
149
        pressingButton = false;
 
150
        autoSlideTrigger.deactivateAutoSlideInGesture();
 
151
    }
 
152
    
 
153
    /** Reacts to popup triggers on sliding buttons */
 
154
    public void mousePressed(MouseEvent e) {
 
155
        autoSlideTrigger.deactivateAutoSlideInGesture();
 
156
        handlePopupRequests(e);
 
157
    }
 
158
    
 
159
    /** Reacts to popup triggers on sliding buttons */
 
160
    public void mouseReleased(MouseEvent e) {
 
161
        autoSlideTrigger.deactivateAutoSlideInGesture();
 
162
        handlePopupRequests(e);
 
163
    }
 
164
    
 
165
    public void mouseDragged(MouseEvent e) {
 
166
        // no operation
 
167
    }
 
168
    
 
169
    public void mouseClicked(MouseEvent e) {
 
170
        // no operation
 
171
    }
 
172
    
 
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)) {
 
177
            return;
 
178
        }
 
179
        
 
180
        if (e.isPopupTrigger()) {
 
181
            slideBar.userTriggeredPopup(e, (Component)e.getSource());
 
182
        }
 
183
    }
 
184
 
 
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 {
 
188
        
 
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;
 
198
        
 
199
        AutoSlideTrigger() {
 
200
            super();
 
201
            slideInTimer = new Timer(200, this);
 
202
            slideInTimer.setRepeats(true);
 
203
            slideInTimer.setCoalesce(true);
 
204
        }
 
205
 
 
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();
 
211
        }
 
212
        
 
213
        /** Stops listening to user events that may lead to automatic slide in */
 
214
        public void deactivateAutoSlideInGesture() {
 
215
            slideInTimer.stop();
 
216
        }
 
217
 
 
218
        /** @return true when auto slide system is listening and active, false ootherwise */
 
219
        public boolean isEnabled() {
 
220
            return autoSlideActive || slideInTimer.isRunning();
 
221
        }
 
222
 
 
223
        /** Action listener implementation - reacts to timer notification, which
 
224
         * means we should check conditions and perform auto slide in if appropriate
 
225
         */
 
226
        public void actionPerformed(ActionEvent evt) {
 
227
            if (isSlideInGesture()) {
 
228
                slideInTimer.stop();
 
229
                // multiple auto slide in requests, get rid of old one first
 
230
                if (autoSlideActive) {
 
231
                    autoSlideOut();
 
232
                }
 
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);
 
238
                } else {
 
239
                    autoSlideActive = false;
 
240
                }
 
241
            } else {
 
242
                initialX = curMouseLocX;
 
243
                initialY = curMouseLocY;
 
244
            }
 
245
        }
 
246
 
 
247
        /** AWTEventListener implementation. Analyzes incoming mouse motion
 
248
         * and initiates automatic slide out when needed.
 
249
         */
 
250
        public void eventDispatched(AWTEvent event) {
 
251
            autoSlideOutIfNeeded((MouseEvent)event);
 
252
        }
 
253
        
 
254
        /** Checks conditions and runs auto slide out if needed.
 
255
         */
 
256
        private void autoSlideOutIfNeeded(MouseEvent evt) {
 
257
            if (!autoSlideActive) {
 
258
                // ignore pending events that came later after cleanup
 
259
                return;
 
260
            }
 
261
            if (slideBar.isActive()) {
 
262
                // if slide bar is active (focused), we should do no more automatic things
 
263
                cleanup();
 
264
                return;
 
265
            }
 
266
            if (isSlideOutGesture(evt)) {
 
267
                cleanup();
 
268
                autoSlideOut();
 
269
            }
 
270
        }
 
271
 
 
272
        /** Actually performs slide out by notifying slide bar */
 
273
        private void autoSlideOut() {
 
274
            slideBar.userTriggeredAutoSlideOut();
 
275
        }
 
276
 
 
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;
 
282
            activeArea = null;
 
283
        }
 
284
        
 
285
        /** @return true when conditions for auto slide IN were met, false otherwise */
 
286
        private boolean isSlideInGesture () {
 
287
            if (mouseInButton == null) {
 
288
                return false;
 
289
            }
 
290
            
 
291
            int diffX = Math.abs(initialX - curMouseLocX);
 
292
            int diffY = Math.abs(initialY - curMouseLocY);
 
293
            
 
294
            return (diffX <= 2) && (diffY <= 2);
 
295
        }
 
296
        
 
297
        /** @return true when conditions for auto slide OUT were met, false otherwise */
 
298
        private boolean isSlideOutGesture(MouseEvent evt) {
 
299
            if (resizer.isDragging()) {
 
300
                activeArea = null;
 
301
                return false;
 
302
            }
 
303
            if (activeArea == null) {
 
304
                activeArea = computeActiveArea();
 
305
                // comps are not yet ready, so do nothing
 
306
                if (activeArea == null) {
 
307
                    return false;
 
308
                }
 
309
            }
 
310
            Point mouseLoc = evt.getPoint();
 
311
            //#118828
 
312
            if (! (evt.getSource() instanceof Component)) {
 
313
                return false;
 
314
            }
 
315
            
 
316
            SwingUtilities.convertPointToScreen(mouseLoc, (Component)evt.getSource());
 
317
 
 
318
            return !activeArea.contains(mouseLoc);
 
319
        }
 
320
 
 
321
        /** @return Area in which automatic slide in is preserved. Can return
 
322
         * null signalizing that components making active area bounds are not yet 
 
323
         * ready or showing.
 
324
         */
 
325
        private Rectangle computeActiveArea() {
 
326
            Component slidedComp = slideBar.getSlidedComp();
 
327
            if (slidedComp == null || !slidedComp.isShowing()) {
 
328
                return null;
 
329
            }
 
330
            
 
331
            Point slideBarLoc = slideBar.getLocationOnScreen();
 
332
            Rectangle actArea = new Rectangle(slideBarLoc.x - 1, slideBarLoc.y - 1,
 
333
                                    slideBar.getWidth() - 1, slideBar.getHeight() - 1);
 
334
            
 
335
            Point slidedCompLoc = slidedComp.getLocationOnScreen();
 
336
            
 
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;
 
344
            }
 
345
            if (orientation == SlideBarDataModel.EAST) {
 
346
                slidew = slidew + ResizeGestureRecognizer.RESIZE_BUFFER;
 
347
                slidex = slidex - ResizeGestureRecognizer.RESIZE_BUFFER;
 
348
            }
 
349
            if (orientation == SlideBarDataModel.SOUTH) {
 
350
                slideh = slideh + ResizeGestureRecognizer.RESIZE_BUFFER;
 
351
                slidey = slidey - ResizeGestureRecognizer.RESIZE_BUFFER;
 
352
            }
 
353
            actArea = SwingUtilities.computeUnion(
 
354
                slidex, slidey, slidew,
 
355
                slideh, actArea);
 
356
            
 
357
            return actArea;
 
358
        }
 
359
        
 
360
        
 
361
    } // AutoSlideTrigger
 
362
    
 
363
}
 
 
b'\\ No newline at end of file'