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
.editor
.impl
;
18 import com
.intellij
.ide
.DataManager
;
19 import com
.intellij
.openapi
.Disposable
;
20 import com
.intellij
.openapi
.actionSystem
.*;
21 import com
.intellij
.openapi
.actionSystem
.ex
.ActionButtonLook
;
22 import com
.intellij
.openapi
.actionSystem
.ex
.ActionManagerEx
;
23 import com
.intellij
.openapi
.actionSystem
.impl
.ActionButton
;
24 import com
.intellij
.openapi
.actionSystem
.impl
.ActionToolbarImpl
;
25 import com
.intellij
.openapi
.editor
.Document
;
26 import com
.intellij
.openapi
.editor
.event
.EditorMouseAdapter
;
27 import com
.intellij
.openapi
.editor
.event
.EditorMouseEvent
;
28 import com
.intellij
.openapi
.editor
.event
.EditorMouseMotionAdapter
;
29 import com
.intellij
.openapi
.fileEditor
.FileDocumentManager
;
30 import com
.intellij
.openapi
.keymap
.ex
.KeymapManagerEx
;
31 import com
.intellij
.openapi
.vfs
.LocalFileSystem
;
32 import com
.intellij
.openapi
.vfs
.VirtualFile
;
33 import com
.intellij
.openapi
.vfs
.impl
.http
.HttpVirtualFile
;
34 import org
.jetbrains
.annotations
.NonNls
;
35 import org
.jetbrains
.annotations
.NotNull
;
36 import org
.jetbrains
.annotations
.Nullable
;
40 import java
.awt
.event
.ActionEvent
;
41 import java
.awt
.event
.ActionListener
;
42 import java
.awt
.image
.BufferedImage
;
47 public class ContextMenuImpl
extends JPanel
implements Disposable
{
49 public static final String ACTION_GROUP
= "EditorContextBarMenu";
51 private ActionGroup myActionGroup
;
52 private final JComponent myComponent
;
53 private boolean myVisible
= false;
54 private boolean myShow
= false;
55 private int myCurrentOpacity
;
56 private Timer myTimer
;
57 private EditorImpl myEditor
;
58 private ContextMenuPanel myContextMenuPanel
;
59 private boolean myDisposed
;
60 private JLayeredPane myLayeredPane
;
62 public ContextMenuImpl(JLayeredPane layeredPane
, @NotNull final JScrollPane container
, @NotNull final EditorImpl editor
) {
63 setLayout(new BorderLayout(0, 0));
65 myLayeredPane
= layeredPane
;
67 final ActionManager actionManager
= ActionManager
.getInstance();
69 editor
.addEditorMouseListener(new EditorMouseAdapter() {
71 public void mouseExited(final EditorMouseEvent e
) {
72 if (!isInsideActivationArea(container
, e
.getMouseEvent().getPoint())) {
73 toggleContextToolbar(false);
78 editor
.addEditorMouseMotionListener(new EditorMouseMotionAdapter() {
80 public void mouseMoved(final EditorMouseEvent e
) {
81 toggleContextToolbar(isInsideActivationArea(container
, e
.getMouseEvent().getPoint()));
85 AnAction action
= actionManager
.getAction("EditorContextBarMenu");
87 action
= new DefaultActionGroup();
88 actionManager
.registerAction(ACTION_GROUP
, action
);
91 if (action
instanceof ActionGroup
) {
92 myActionGroup
= (ActionGroup
)action
;
95 myComponent
= createComponent();
102 private static boolean isInsideActivationArea(JScrollPane container
, Point p
) {
103 final JViewport viewport
= container
.getViewport();
104 final Rectangle r
= viewport
.getBounds();
105 final Point viewPosition
= viewport
.getViewPosition();
107 final Rectangle activationArea
= new Rectangle(0, 0, r
.width
, 150);
108 return activationArea
.contains(p
.x
, p
.y
- viewPosition
.y
);
111 private void toggleContextToolbar(final boolean show
) {
112 final Component toolbar
= myComponent
.getComponent(0);
113 final int count
= ((Container
)toolbar
).getComponentCount();
118 if (myShow
!= show
) {
124 private void restartTimer() {
125 if (myTimer
!= null && myTimer
.isRunning()) {
129 myTimer
= new Timer(500, new ActionListener() {
130 public void actionPerformed(ActionEvent e
) {
131 if (myDisposed
) return;
133 if (myTimer
!= null && myTimer
.isRunning()) myTimer
.stop();
135 myTimer
= new Timer(50, new ActionListener() {
136 public void actionPerformed(ActionEvent e
) {
143 if (myLayeredPane
.getIndexOf(ContextMenuImpl
.this) == -1) {
144 myCurrentOpacity
= 0;
145 myLayeredPane
.add(ContextMenuImpl
.this, JLayeredPane
.POPUP_LAYER
);
146 ContextMenuImpl
.this.setVisible(true);
147 myLayeredPane
.revalidate();
150 myCurrentOpacity
+= 20;
151 if (myCurrentOpacity
> 100) {
152 myCurrentOpacity
= 100;
162 if (myTimer
!= null && myTimer
.isRunning()) myTimer
.stop();
166 myCurrentOpacity
-= 20;
167 if (myCurrentOpacity
< 0) {
168 myCurrentOpacity
= 0;
170 myLayeredPane
.remove(ContextMenuImpl
.this);
171 myLayeredPane
.revalidate();
179 myTimer
.setRepeats(true);
184 myTimer
.setRepeats(false);
188 public void dispose() {
192 if (myTimer
!= null) {
199 public static boolean mayShowToolbar(@Nullable final Document document
) {
200 if (document
== null) {
204 final VirtualFile file
= FileDocumentManager
.getInstance().getFile(document
);
205 return file
!= null && file
.isValid() && (file
.getFileSystem() == LocalFileSystem
.getInstance() || file
instanceof HttpVirtualFile
);
208 private void scheduleHide() {
209 if (myTimer
!= null && myTimer
.isRunning()) {
213 myTimer
= new Timer(1500, new ActionListener() {
214 public void actionPerformed(final ActionEvent e
) {
215 if (myDisposed
) return;
217 if (myComponent
.isVisible()) {
218 final PointerInfo pointerInfo
= MouseInfo
.getPointerInfo();
219 if (pointerInfo
!= null) {
220 final Point location
= pointerInfo
.getLocation();
221 SwingUtilities
.convertPointFromScreen(location
, myComponent
);
222 if (!myComponent
.getBounds().contains(location
)) {
223 toggleContextToolbar(false);
232 myTimer
.setRepeats(false);
236 private ActionToolbar
createToolbar(final ActionGroup group
) {
237 final ActionToolbarImpl actionToolbar
=
238 new ActionToolbarImpl(ActionPlaces
.CONTEXT_TOOLBAR
, group
, true, DataManager
.getInstance(), ActionManagerEx
.getInstanceEx(),
239 KeymapManagerEx
.getInstanceEx()) {
242 public void paint(final Graphics g
) {
243 if (myContextMenuPanel
.isPaintChildren()) {
249 protected void paintChildren(final Graphics g
) {
250 if (myContextMenuPanel
.isPaintChildren()) {
251 super.paintChildren(g
);
256 public boolean isOpaque() {
257 return myContextMenuPanel
.isPaintChildren();
261 public ActionButton
createToolbarButton(final AnAction action
,
262 final ActionButtonLook look
,
264 final Presentation presentation
,
265 final Dimension minimumSize
) {
266 final ActionButton result
= new ActionButton(action
, presentation
, place
, minimumSize
) {
268 public void paintComponent(final Graphics g
) {
269 if (myContextMenuPanel
.isPaintChildren()) {
270 final ActionButtonLook look
= getButtonLook();
271 look
.paintIcon(g
, this, getIcon());
274 if (myContextMenuPanel
.isShown() && getPopState() == ActionButton
.POPPED
) {
275 final ActionButtonLook look
= getButtonLook();
276 look
.paintBackground(g
, this);
277 look
.paintIcon(g
, this, getIcon());
282 public boolean isOpaque() {
283 return myContextMenuPanel
.isPaintChildren() || getPopState() == ActionButton
.POPPED
;
287 public void paint(final Graphics g
) {
288 final Graphics2D g2
= (Graphics2D
)g
;
293 result
.setLook(look
);
298 actionToolbar
.setTargetComponent(myEditor
.getContentComponent());
300 return actionToolbar
;
303 private JComponent
createComponent() {
304 final ActionToolbar toolbar
= createToolbar(myActionGroup
);
305 toolbar
.setMinimumButtonSize(new Dimension(20, 20));
306 toolbar
.setReservePlaceAutoPopupIcon(false);
308 myContextMenuPanel
= new ContextMenuPanel(this);
309 myContextMenuPanel
.setLayout(new BorderLayout(0, 0));
310 myContextMenuPanel
.add(toolbar
.getComponent());
312 return myContextMenuPanel
;
315 private static class ContextMenuPanel
extends JPanel
{
316 private final ContextMenuImpl myContextMenu
;
317 private BufferedImage myBufferedImage
;
318 private boolean myPaintChildren
= false;
320 private ContextMenuPanel(final ContextMenuImpl contextMenu
) {
321 myContextMenu
= contextMenu
;
322 setBorder(BorderFactory
.createEmptyBorder(2, 2, 2, 2));
327 public void invalidate() {
330 myBufferedImage
= null;
334 public void revalidate() {
337 myBufferedImage
= null;
341 protected void paintChildren(final Graphics g
) {
342 if (myPaintChildren
) {
343 super.paintChildren(g
);
347 public boolean isPaintChildren() {
348 return myPaintChildren
;
352 public void paint(final Graphics g
) {
353 final Rectangle r
= getBounds();
354 if (myBufferedImage
== null) {
355 myBufferedImage
= new BufferedImage(r
.width
, r
.height
, BufferedImage
.TYPE_INT_ARGB
);
357 final Graphics graphics
= myBufferedImage
.getGraphics();
358 final Graphics2D g2d2
= (Graphics2D
)graphics
;
359 final Composite old
= g2d2
.getComposite();
361 g2d2
.setComposite(AlphaComposite
.getInstance(AlphaComposite
.SRC_OVER
, 0.2f
));
363 g2d2
.setColor(Color
.GRAY
);
364 g2d2
.fillRoundRect(0, 0, r
.width
- 1, r
.height
- 1, 6, 6);
366 g2d2
.setComposite(old
);
368 myPaintChildren
= true;
370 myPaintChildren
= false;
373 final Graphics2D g2
= (Graphics2D
)g
;
374 final Composite old
= g2
.getComposite();
376 g2
.setComposite(AlphaComposite
.getInstance(AlphaComposite
.SRC_ATOP
, myContextMenu
.myCurrentOpacity
/ 100.0f
));
377 g2
.drawImage(myBufferedImage
, 0, 0, myBufferedImage
.getWidth(null), myBufferedImage
.getHeight(null), null);
379 g2
.setComposite(old
);
382 public boolean isShown() {
383 return myContextMenu
.myCurrentOpacity
== 100;