2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.openapi
.wm
.impl
;
18 import com
.intellij
.ide
.IdeEventQueue
;
19 import com
.intellij
.openapi
.Disposable
;
20 import com
.intellij
.openapi
.ui
.Painter
;
21 import com
.intellij
.openapi
.ui
.impl
.GlassPaneDialogWrapperPeer
;
22 import com
.intellij
.openapi
.util
.Disposer
;
25 import javax
.swing
.event
.MenuDragMouseEvent
;
27 import java
.awt
.event
.MouseEvent
;
28 import java
.awt
.event
.MouseListener
;
29 import java
.awt
.event
.MouseMotionListener
;
30 import java
.awt
.event
.MouseWheelEvent
;
31 import java
.lang
.ref
.WeakReference
;
34 public class IdeGlassPaneImpl
extends JPanel
implements IdeGlassPaneEx
, IdeEventQueue
.EventDispatcher
, Painter
.Listener
{
36 private final Set
<EventListener
> myMouseListeners
= new LinkedHashSet
<EventListener
>();
37 private final JRootPane myRootPane
;
39 private final WeakReference
<Component
> myCurrentOverComponent
= new WeakReference
<Component
>(null);
40 private final WeakReference
<Component
> myMousePressedComponent
= new WeakReference
<Component
>(null);
42 private final Set
<Painter
> myPainters
= new LinkedHashSet
<Painter
>();
43 private final Map
<Painter
, Component
> myPainter2Component
= new LinkedHashMap
<Painter
, Component
>();
45 private boolean myPaintingActive
;
46 private boolean myPreprocessorActive
;
48 public IdeGlassPaneImpl(JRootPane rootPane
) {
49 myRootPane
= rootPane
;
55 public boolean dispatch(final AWTEvent e
) {
56 boolean dispatched
= false;
58 if (e
instanceof MouseEvent
) {
59 final MouseEvent me
= (MouseEvent
)e
;
60 Window eventWindow
= me
.getComponent() instanceof Window ?
((Window
)me
.getComponent()) : SwingUtilities
.getWindowAncestor(me
.getComponent());
61 final Window thisGlassWindow
= SwingUtilities
.getWindowAncestor(myRootPane
);
62 if (eventWindow
!= thisGlassWindow
) return false;
65 if (e
.getID() == MouseEvent
.MOUSE_PRESSED
|| e
.getID() == MouseEvent
.MOUSE_RELEASED
|| e
.getID() == MouseEvent
.MOUSE_CLICKED
) {
66 dispatched
= preprocess((MouseEvent
)e
, false);
67 } else if (e
.getID() == MouseEvent
.MOUSE_MOVED
|| e
.getID() == MouseEvent
.MOUSE_DRAGGED
) {
68 dispatched
= preprocess((MouseEvent
)e
, true);
69 } else if (e
.getID() == MouseEvent
.MOUSE_EXITED
|| e
.getID() == MouseEvent
.MOUSE_ENTERED
) {
70 dispatched
= preprocess((MouseEvent
)e
, false);
75 if (isVisible() && getComponentCount() == 0) {
76 boolean cursorSet
= false;
77 MouseEvent me
= (MouseEvent
)e
;
78 if (me
.getComponent() != null) {
79 final Point point
= SwingUtilities
.convertPoint(me
.getComponent(), me
.getPoint(), myRootPane
.getContentPane());
81 if (myRootPane
.getMenuBar() != null && myRootPane
.getMenuBar().isVisible()) {
82 point
.y
+= myRootPane
.getMenuBar().getHeight();
85 final Component target
=
86 SwingUtilities
.getDeepestComponentAt(myRootPane
.getContentPane().getParent(), point
.x
, point
.y
);
88 setCursor(target
.getCursor());
94 setCursor(Cursor
.getDefaultCursor());
101 private boolean preprocess(final MouseEvent e
, final boolean motion
) {
102 final MouseEvent event
= convertEvent(e
, myRootPane
);
103 for (EventListener each
: myMouseListeners
) {
104 if (motion
&& each
instanceof MouseMotionListener
) {
105 fireMouseMotion((MouseMotionListener
)each
, event
);
106 } else if (!motion
&& each
instanceof MouseListener
) {
107 fireMouseEvent((MouseListener
)each
, event
);
110 if (event
.isConsumed()) {
118 private MouseEvent
convertEvent(final MouseEvent e
, final Component target
) {
119 final Point point
= SwingUtilities
.convertPoint(e
.getComponent(), e
.getPoint(), target
);
120 if (e
instanceof MouseWheelEvent
) {
121 final MouseWheelEvent mwe
= (MouseWheelEvent
)e
;
122 return new MouseWheelEvent(target
, mwe
.getID(), mwe
.getWhen(), mwe
.getModifiersEx(), point
.x
, point
.y
, mwe
.getClickCount(),
123 mwe
.isPopupTrigger(), mwe
.getScrollType(), mwe
.getScrollAmount(), mwe
.getWheelRotation());
125 else if (e
instanceof MenuDragMouseEvent
) {
126 final MenuDragMouseEvent de
= (MenuDragMouseEvent
)e
;
127 return new MenuDragMouseEvent(target
, de
.getID(), de
.getWhen(), de
.getModifiersEx(), point
.x
, point
.y
, e
.getClickCount(),
128 e
.isPopupTrigger(), de
.getPath(), de
.getMenuSelectionManager());
132 return new MouseEvent(target
, e
.getID(), e
.getWhen(), e
.getModifiersEx(), point
.x
, point
.y
, e
.getClickCount(), e
.isPopupTrigger(),
137 private static void fireMouseEvent(final MouseListener listener
, final MouseEvent event
) {
138 switch (event
.getID()) {
139 case MouseEvent
.MOUSE_PRESSED
:
140 listener
.mousePressed(event
);
142 case MouseEvent
.MOUSE_RELEASED
:
143 listener
.mouseReleased(event
);
145 case MouseEvent
.MOUSE_ENTERED
:
146 listener
.mouseEntered(event
);
148 case MouseEvent
.MOUSE_EXITED
:
149 listener
.mouseExited(event
);
151 case MouseEvent
.MOUSE_CLICKED
:
152 listener
.mouseClicked(event
);
157 private static void fireMouseMotion(MouseMotionListener listener
, final MouseEvent event
) {
158 switch (event
.getID()) {
159 case MouseEvent
.MOUSE_DRAGGED
:
160 listener
.mouseDragged(event
);
161 case MouseEvent
.MOUSE_MOVED
:
162 listener
.mouseMoved(event
);
166 public void addMousePreprocessor(final MouseListener listener
, Disposable parent
) {
167 _addListener(listener
, parent
);
171 public void addMouseMotionPreprocessor(final MouseMotionListener listener
, final Disposable parent
) {
172 _addListener(listener
, parent
);
175 private void _addListener(final EventListener listener
, final Disposable parent
) {
176 myMouseListeners
.add(listener
);
178 Disposer
.register(parent
, new Disposable() {
179 public void dispose() {
180 SwingUtilities
.invokeLater(new Runnable() {
182 removeListener(listener
);
189 public void removeMousePreprocessor(final MouseListener listener
) {
190 removeListener(listener
);
193 public void removeMouseMotionPreprocessor(final MouseMotionListener listener
) {
194 removeListener(listener
);
197 private void removeListener(final EventListener listener
) {
198 myMouseListeners
.remove(listener
);
199 deactivateIfNeeded();
202 private void deactivateIfNeeded() {
203 if (myPaintingActive
) {
204 if (myPainters
.size() == 0 && getComponentCount() == 0) {
205 myPaintingActive
= false;
209 if (myPreprocessorActive
&& myMouseListeners
.size() == 0) {
210 myPreprocessorActive
= false;
213 applyActivationState();
216 private void activateIfNeeded() {
217 if (!myPaintingActive
) {
218 if (myPainters
.size() > 0 || getComponentCount() > 0) {
219 myPaintingActive
= true;
223 if (!myPreprocessorActive
&& myMouseListeners
.size() > 0) {
224 myPreprocessorActive
= true;
227 applyActivationState();
230 private void applyActivationState() {
231 if (isVisible() != myPaintingActive
) {
232 setVisible(myPaintingActive
);
235 IdeEventQueue queue
= IdeEventQueue
.getInstance();
236 if (!queue
.containsDispatcher(this) && myPreprocessorActive
) {
237 queue
.addDispatcher(this, null);
238 } else if (queue
.containsDispatcher(this) && !myPreprocessorActive
) {
239 queue
.removeDispatcher(this);
244 public void addPainter(final Component component
, final Painter painter
, final Disposable parent
) {
245 myPainters
.add(painter
);
246 myPainter2Component
.put(painter
, component
== null ?
this : component
);
247 painter
.addListener(this);
249 Disposer
.register(parent
, new Disposable() {
250 public void dispose() {
251 SwingUtilities
.invokeLater(new Runnable() {
253 removePainter(painter
);
260 public void removePainter(final Painter painter
) {
261 myPainters
.remove(painter
);
262 myPainter2Component
.remove(painter
);
263 painter
.removeListener(this);
264 deactivateIfNeeded();
268 public Component
add(final Component comp
) {
269 final Component result
= super.add(comp
);
275 public void remove(final Component comp
) {
277 deactivateIfNeeded();
280 public boolean isInModalContext() {
281 final Component
[] components
= getComponents();
282 for (Component component
: components
) {
283 if (component
instanceof GlassPaneDialogWrapperPeer
.TransparentLayeredPane
) {
291 protected void paintComponent(final Graphics g
) {
292 if (myPainters
.size() == 0) return;
294 Graphics2D g2d
= (Graphics2D
)g
;
295 for (Painter painter
: myPainters
) {
296 final Rectangle clip
= g
.getClipBounds();
298 final Component component
= myPainter2Component
.get(painter
);
299 if (component
.getParent() == null) continue;
300 final Rectangle componentBounds
= SwingUtilities
.convertRectangle(component
.getParent(), component
.getBounds(), this);
302 if (!painter
.needsRepaint()) continue;
304 if (clip
.contains(componentBounds
) || clip
.intersects(componentBounds
)) {
305 final Point targetPoint
= SwingUtilities
.convertPoint(this, 0, 0, component
);
306 final Rectangle targetRect
= new Rectangle(targetPoint
, component
.getSize());
307 g2d
.translate(-targetRect
.x
, -targetRect
.y
);
308 painter
.paint(component
, g2d
);
309 g2d
.translate(targetRect
.x
, targetRect
.y
);
314 public boolean hasPainters() {
315 return myPainters
.size() > 0;
318 public void onNeedsRepaint(final Painter painter
, final JComponent dirtyComponent
) {
319 if (dirtyComponent
!= null && dirtyComponent
.isShowing()) {
320 final Rectangle rec
= SwingUtilities
.convertRectangle(dirtyComponent
, dirtyComponent
.getBounds(), this);
330 public Component
getTargetComponentFor(MouseEvent e
) {
331 Component candidate
= findComponent(e
, myRootPane
.getLayeredPane());
332 if (candidate
!= null) return candidate
;
333 candidate
= findComponent(e
, myRootPane
.getContentPane());
334 if (candidate
!= null) return candidate
;
335 return e
.getComponent();
338 private Component
findComponent(final MouseEvent e
, final Container container
) {
339 final Point lpPoint
= SwingUtilities
.convertPoint(e
.getComponent(), e
.getPoint(), container
);
340 final Component lpComponent
= SwingUtilities
.getDeepestComponentAt(container
, lpPoint
.x
, lpPoint
.y
);