9684b88e5efcb9b0cd9d40587480f97d42a69993
[idea/community.git] / platform / xdebugger-impl / src / com / intellij / xdebugger / impl / evaluate / quick / common / ValueLookupManager.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /*
18  * Class ValueLookupManager
19  * @author Jeka
20  */
21 package com.intellij.xdebugger.impl.evaluate.quick.common;
22
23 import com.intellij.openapi.components.ServiceManager;
24 import com.intellij.openapi.editor.Editor;
25 import com.intellij.openapi.editor.EditorFactory;
26 import com.intellij.openapi.editor.event.*;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.util.Key;
29 import com.intellij.openapi.util.registry.Registry;
30 import com.intellij.util.Alarm;
31 import com.intellij.xdebugger.impl.DebuggerSupport;
32 import org.jetbrains.annotations.NotNull;
33
34 import java.awt.*;
35
36 public class ValueLookupManager extends EditorMouseAdapter implements EditorMouseMotionListener {
37   /**
38    * @see com.intellij.xdebugger.XDebuggerUtil#disableValueLookup(com.intellij.openapi.editor.Editor)
39    */
40   public static final Key<Boolean> DISABLE_VALUE_LOOKUP = Key.create("DISABLE_VALUE_LOOKUP");
41
42   private final Project myProject;
43   private final Alarm myAlarm;
44   private AbstractValueHint myRequest = null;
45   private final DebuggerSupport[] mySupports;
46   private boolean myListening;
47
48   public ValueLookupManager(Project project) {
49     myProject = project;
50     mySupports = DebuggerSupport.getDebuggerSupports();
51     myAlarm = new Alarm(project);
52   }
53
54   public void startListening() {
55     if (!myListening) {
56       myListening = true;
57       EditorFactory.getInstance().getEventMulticaster().addEditorMouseMotionListener(this, myProject);
58       EditorFactory.getInstance().getEventMulticaster().addEditorMouseListener(this, myProject);
59     }
60   }
61
62   @Override
63   public void mouseDragged(EditorMouseEvent e) {
64   }
65
66   @Override
67   public void mouseExited(EditorMouseEvent e) {
68     myAlarm.cancelAllRequests();
69   }
70
71   @Override
72   public void mouseMoved(EditorMouseEvent e) {
73     if (e.isConsumed()) {
74       return;
75     }
76
77     Editor editor = e.getEditor();
78     if (editor.getProject() != null && editor.getProject() != myProject) {
79       return;
80     }
81
82     ValueHintType type = AbstractValueHint.getHintType(e);
83     if (e.getArea() != EditorMouseEventArea.EDITING_AREA ||
84         DISABLE_VALUE_LOOKUP.get(editor) == Boolean.TRUE ||
85         type == null) {
86       myAlarm.cancelAllRequests();
87       return;
88     }
89
90     Point point = e.getMouseEvent().getPoint();
91     if (myRequest != null && !myRequest.isKeepHint(editor, point)) {
92       hideHint();
93     }
94
95     for (DebuggerSupport support : mySupports) {
96       QuickEvaluateHandler handler = support.getQuickEvaluateHandler();
97       if (handler.isEnabled(myProject)) {
98         requestHint(handler, editor, point, type);
99         break;
100       }
101     }
102   }
103
104   private void requestHint(final QuickEvaluateHandler handler, final Editor editor, final Point point, @NotNull final ValueHintType type) {
105     final Rectangle area = editor.getScrollingModel().getVisibleArea();
106     myAlarm.cancelAllRequests();
107     if (type == ValueHintType.MOUSE_OVER_HINT) {
108       if (Registry.is("debugger.valueTooltipAutoShow")) {
109         myAlarm.addRequest(new Runnable() {
110           @Override
111           public void run() {
112             if (area.equals(editor.getScrollingModel().getVisibleArea())) {
113               showHint(handler, editor, point, type);
114             }
115           }
116         }, handler.getValueLookupDelay(myProject));
117       }
118     }
119     else {
120       showHint(handler, editor, point, type);
121     }
122   }
123
124   public void hideHint() {
125     if (myRequest != null) {
126       myRequest.hideHint();
127       myRequest = null;
128     }
129   }
130
131   public void showHint(@NotNull QuickEvaluateHandler handler, @NotNull Editor editor, @NotNull Point point, @NotNull ValueHintType type) {
132     myAlarm.cancelAllRequests();
133     if (editor.isDisposed() || !handler.canShowHint(myProject)) {
134       return;
135     }
136
137     final AbstractValueHint request = handler.createValueHint(myProject, editor, point, type);
138     if (request != null) {
139       if (myRequest != null && myRequest.equals(request)) {
140         return;
141       }
142
143       if (!request.canShowHint()) {
144         return;
145       }
146       if (myRequest != null && myRequest.isInsideHint(editor, point)) {
147         return;
148       }
149
150       hideHint();
151
152       myRequest = request;
153       myRequest.invokeHint(new Runnable() {
154         @Override
155         public void run() {
156           if (myRequest != null && myRequest == request) {
157             myRequest = null;
158           }
159         }
160       });
161     }
162   }
163
164   public static ValueLookupManager getInstance(Project project) {
165     return ServiceManager.getService(project, ValueLookupManager.class);
166   }
167 }