IDEA-51739
[fedora-idea.git] / platform / platform-impl / src / com / intellij / openapi / editor / impl / ContextMenuImpl.java
blob708f5ef2808f532bfa4add6e23aead9faeccdad1
1 /*
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;
38 import javax.swing.*;
39 import java.awt.*;
40 import java.awt.event.ActionEvent;
41 import java.awt.event.ActionListener;
42 import java.awt.image.BufferedImage;
44 /**
45 * @author spleaner
47 public class ContextMenuImpl extends JPanel implements Disposable {
48 @NonNls
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));
64 myEditor = editor;
65 myLayeredPane = layeredPane;
67 final ActionManager actionManager = ActionManager.getInstance();
69 editor.addEditorMouseListener(new EditorMouseAdapter() {
70 @Override
71 public void mouseExited(final EditorMouseEvent e) {
72 if (!isInsideActivationArea(container, e.getMouseEvent().getPoint())) {
73 toggleContextToolbar(false);
76 });
78 editor.addEditorMouseMotionListener(new EditorMouseMotionAdapter() {
79 @Override
80 public void mouseMoved(final EditorMouseEvent e) {
81 toggleContextToolbar(isInsideActivationArea(container, e.getMouseEvent().getPoint()));
83 });
85 AnAction action = actionManager.getAction("EditorContextBarMenu");
86 if (action == null) {
87 action = new DefaultActionGroup();
88 actionManager.registerAction(ACTION_GROUP, action);
91 if (action instanceof ActionGroup) {
92 myActionGroup = (ActionGroup)action;
95 myComponent = createComponent();
96 add(myComponent);
98 setVisible(false);
99 setOpaque(false);
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();
114 if (count == 0) {
115 return;
118 if (myShow != show) {
119 myShow = show;
120 restartTimer();
124 private void restartTimer() {
125 if (myTimer != null && myTimer.isRunning()) {
126 myTimer.stop();
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) {
137 if (myShow) {
138 if (myVisible) {
139 scheduleHide();
140 return;
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;
153 myVisible = true;
154 myTimer.stop();
156 scheduleHide();
159 repaint();
160 } else {
161 if (!myVisible) {
162 if (myTimer != null && myTimer.isRunning()) myTimer.stop();
163 return;
166 myCurrentOpacity -= 20;
167 if (myCurrentOpacity < 0) {
168 myCurrentOpacity = 0;
169 myVisible = false;
170 myLayeredPane.remove(ContextMenuImpl.this);
171 myLayeredPane.revalidate();
174 repaint();
179 myTimer.setRepeats(true);
180 myTimer.start();
184 myTimer.setRepeats(false);
185 myTimer.start();
188 public void dispose() {
189 myDisposed = true;
190 myEditor = null;
192 if (myTimer != null) {
193 myTimer.stop();
194 myTimer = null;
199 public static boolean mayShowToolbar(@Nullable final Document document) {
200 if (document == null) {
201 return false;
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()) {
210 myTimer.stop();
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);
224 } else {
225 scheduleHide();
232 myTimer.setRepeats(false);
233 myTimer.start();
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()) {
241 @Override
242 public void paint(final Graphics g) {
243 if (myContextMenuPanel.isPaintChildren()) {
244 paintChildren(g);
248 @Override
249 protected void paintChildren(final Graphics g) {
250 if (myContextMenuPanel.isPaintChildren()) {
251 super.paintChildren(g);
255 @Override
256 public boolean isOpaque() {
257 return myContextMenuPanel.isPaintChildren();
260 @Override
261 public ActionButton createToolbarButton(final AnAction action,
262 final ActionButtonLook look,
263 final String place,
264 final Presentation presentation,
265 final Dimension minimumSize) {
266 final ActionButton result = new ActionButton(action, presentation, place, minimumSize) {
267 @Override
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());
281 @Override
282 public boolean isOpaque() {
283 return myContextMenuPanel.isPaintChildren() || getPopState() == ActionButton.POPPED;
286 @Override
287 public void paint(final Graphics g) {
288 final Graphics2D g2 = (Graphics2D)g;
289 paintComponent(g2);
293 result.setLook(look);
294 return result;
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));
323 setOpaque(false);
326 @Override
327 public void invalidate() {
328 super.invalidate();
330 myBufferedImage = null;
333 @Override
334 public void revalidate() {
335 super.revalidate();
337 myBufferedImage = null;
340 @Override
341 protected void paintChildren(final Graphics g) {
342 if (myPaintChildren) {
343 super.paintChildren(g);
347 public boolean isPaintChildren() {
348 return myPaintChildren;
351 @Override
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;
369 paintChildren(g2d2);
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;