2 * Copyright 2000-2010 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
.execution
.console
;
18 import com
.intellij
.execution
.ui
.ConsoleViewContentType
;
19 import com
.intellij
.ide
.DataManager
;
20 import com
.intellij
.ide
.impl
.TypeSafeDataProviderAdapter
;
21 import com
.intellij
.lang
.Language
;
22 import com
.intellij
.openapi
.Disposable
;
23 import com
.intellij
.openapi
.actionSystem
.*;
24 import com
.intellij
.openapi
.application
.ApplicationManager
;
25 import com
.intellij
.openapi
.editor
.*;
26 import com
.intellij
.openapi
.editor
.actions
.EditorActionUtil
;
27 import com
.intellij
.openapi
.editor
.colors
.EditorColors
;
28 import com
.intellij
.openapi
.editor
.event
.*;
29 import com
.intellij
.openapi
.editor
.ex
.EditorEx
;
30 import com
.intellij
.openapi
.editor
.ex
.RangeHighlighterEx
;
31 import com
.intellij
.openapi
.editor
.ex
.util
.EditorUtil
;
32 import com
.intellij
.openapi
.editor
.highlighter
.EditorHighlighterFactory
;
33 import com
.intellij
.openapi
.editor
.highlighter
.HighlighterIterator
;
34 import com
.intellij
.openapi
.editor
.impl
.DocumentImpl
;
35 import com
.intellij
.openapi
.editor
.impl
.EditorFactoryImpl
;
36 import com
.intellij
.openapi
.editor
.impl
.EditorImpl
;
37 import com
.intellij
.openapi
.editor
.markup
.HighlighterLayer
;
38 import com
.intellij
.openapi
.editor
.markup
.HighlighterTargetArea
;
39 import com
.intellij
.openapi
.editor
.markup
.MarkupModel
;
40 import com
.intellij
.openapi
.editor
.markup
.RangeHighlighter
;
41 import com
.intellij
.openapi
.fileEditor
.FileEditor
;
42 import com
.intellij
.openapi
.fileEditor
.FileEditorManager
;
43 import com
.intellij
.openapi
.fileEditor
.OpenFileDescriptor
;
44 import com
.intellij
.openapi
.fileEditor
.TextEditor
;
45 import com
.intellij
.openapi
.fileEditor
.impl
.FileDocumentManagerImpl
;
46 import com
.intellij
.openapi
.fileEditor
.impl
.FileEditorManagerImpl
;
47 import com
.intellij
.openapi
.fileTypes
.FileType
;
48 import com
.intellij
.openapi
.fileTypes
.StdFileTypes
;
49 import com
.intellij
.openapi
.project
.DumbAwareAction
;
50 import com
.intellij
.openapi
.project
.Project
;
51 import com
.intellij
.openapi
.ui
.DialogBuilder
;
52 import com
.intellij
.openapi
.util
.Disposer
;
53 import com
.intellij
.openapi
.util
.Ref
;
54 import com
.intellij
.openapi
.util
.TextRange
;
55 import com
.intellij
.openapi
.vfs
.VirtualFile
;
56 import com
.intellij
.psi
.PsiFile
;
57 import com
.intellij
.psi
.PsiFileFactory
;
58 import com
.intellij
.psi
.impl
.PsiDocumentManagerImpl
;
59 import com
.intellij
.psi
.impl
.PsiFileFactoryImpl
;
60 import com
.intellij
.psi
.impl
.PsiManagerEx
;
61 import com
.intellij
.testFramework
.LightVirtualFile
;
62 import com
.intellij
.ui
.SideBorder
;
63 import com
.intellij
.util
.FileContentUtil
;
64 import com
.intellij
.util
.ui
.UIUtil
;
65 import com
.intellij
.util
.ui
.update
.MergingUpdateQueue
;
66 import com
.intellij
.util
.ui
.update
.Update
;
67 import org
.jetbrains
.annotations
.NonNls
;
69 import javax
.swing
.FocusManager
;
72 import java
.awt
.event
.*;
73 import java
.util
.ArrayList
;
74 import java
.util
.Collections
;
75 import java
.util
.concurrent
.atomic
.AtomicBoolean
;
78 * @author Gregory.Shrago
80 public class LanguageConsoleImpl
implements Disposable
, TypeSafeDataProvider
{
81 private static int SEPARATOR_THICKNESS
= 1;
83 private final Project myProject
;
85 private final EditorEx myConsoleEditor
;
86 private final EditorEx myHistoryViewer
;
87 private final Document myEditorDocument
;
88 private PsiFile myFile
;
90 private final JPanel myPanel
= new JPanel(new BorderLayout());
92 private String myTitle
;
93 private String myPrompt
= "> ";
94 private LightVirtualFile myHistoryFile
;
96 private Editor myCurrentEditor
;
98 private final AtomicBoolean myForceScrollToEnd
= new AtomicBoolean(false);
99 private final MergingUpdateQueue myUpdateQueue
;
100 private Runnable myUiUpdateRunnable
;
103 public LanguageConsoleImpl(final Project project
, String title
, final Language language
) {
106 installEditorFactoryListener();
107 final EditorFactory editorFactory
= EditorFactory
.getInstance();
108 myHistoryFile
= new LightVirtualFile(getTitle() + ".history.txt", StdFileTypes
.PLAIN_TEXT
, "");
109 myEditorDocument
= editorFactory
.createDocument("");
110 setLanguage(language
);
111 myConsoleEditor
= (EditorEx
)editorFactory
.createEditor(myEditorDocument
, myProject
);
112 myCurrentEditor
= myConsoleEditor
;
113 myHistoryViewer
= (EditorEx
)editorFactory
.createViewer(((EditorFactoryImpl
)editorFactory
).createDocument(true), myProject
);
114 myPanel
.add(myHistoryViewer
.getComponent(), BorderLayout
.NORTH
);
115 myPanel
.add(myConsoleEditor
.getComponent(), BorderLayout
.CENTER
);
117 myPanel
.putClientProperty(DataManager
.CLIENT_PROPERTY_DATA_PROVIDER
, new TypeSafeDataProviderAdapter(this));
118 myUpdateQueue
= new MergingUpdateQueue("ConsoleUpdateQueue", 300, true, null);
119 Disposer
.register(this, myUpdateQueue
);
120 myPanel
.addComponentListener(new ComponentAdapter() {
121 public void componentResized(ComponentEvent e
) {
123 myHistoryViewer
.getScrollingModel().disableAnimation();
127 myHistoryViewer
.getScrollingModel().enableAnimation();
131 public void componentShown(ComponentEvent e
) {
137 private void setupComponents() {
138 setupEditorDefault(myConsoleEditor
);
139 setupEditorDefault(myHistoryViewer
);
141 myConsoleEditor
.addEditorMouseListener(EditorActionUtil
.createEditorPopupHandler(IdeActions
.GROUP_CUT_COPY_PASTE
));
142 if (SEPARATOR_THICKNESS
> 0) {
143 myHistoryViewer
.getComponent().setBorder(new SideBorder(Color
.LIGHT_GRAY
, SideBorder
.BOTTOM
));
145 myHistoryViewer
.getComponent().setMinimumSize(new Dimension(0, 0));
146 myHistoryViewer
.getComponent().setPreferredSize(new Dimension(0, 0));
147 myConsoleEditor
.getSettings().setAdditionalLinesCount(2);
148 myConsoleEditor
.setHighlighter(EditorHighlighterFactory
.getInstance().createEditorHighlighter(myProject
, myFile
.getVirtualFile()));
149 myHistoryViewer
.setCaretEnabled(false);
150 myConsoleEditor
.setHorizontalScrollbarVisible(true);
151 final VisibleAreaListener areaListener
= new VisibleAreaListener() {
152 public void visibleAreaChanged(VisibleAreaEvent e
) {
153 final int offset
= myConsoleEditor
.getScrollingModel().getHorizontalScrollOffset();
154 final ScrollingModel model
= myHistoryViewer
.getScrollingModel();
155 final int historyOffset
= model
.getHorizontalScrollOffset();
156 if (historyOffset
!= offset
) {
158 model
.disableAnimation();
159 model
.scrollHorizontally(offset
);
162 model
.enableAnimation();
167 myConsoleEditor
.getScrollingModel().addVisibleAreaListener(areaListener
);
168 final DocumentAdapter docListener
= new DocumentAdapter() {
170 public void documentChanged(final DocumentEvent e
) {
171 queueUiUpdate(false);
174 myEditorDocument
.addDocumentListener(docListener
, this);
175 myHistoryViewer
.getDocument().addDocumentListener(docListener
, this);
177 myHistoryViewer
.getContentComponent().addKeyListener(new KeyAdapter() {
178 public void keyTyped(KeyEvent event
) {
179 if (UIUtil
.isReallyTypedEvent(event
)) {
180 myConsoleEditor
.getContentComponent().requestFocus();
181 myConsoleEditor
.processKeyTyped(event
);
185 for (AnAction action
: createActions()) {
186 action
.registerCustomShortcutSet(action
.getShortcutSet(), myConsoleEditor
.getComponent());
188 registerActionShortcuts(myHistoryViewer
.getComponent());
191 protected AnAction
[] createActions() {
192 return new AnAction
[]{
193 new MyOpenInEditorAction()
197 private static void setupEditorDefault(EditorEx editor
) {
198 editor
.getContentComponent().setFocusCycleRoot(false);
199 editor
.setHorizontalScrollbarVisible(false);
200 editor
.setVerticalScrollbarVisible(true);
201 editor
.getColorsScheme().setColor(EditorColors
.CARET_ROW_COLOR
, null);
202 editor
.getScrollPane().setBorder(null);
203 editor
.getContentComponent().setFocusCycleRoot(false);
205 final EditorSettings editorSettings
= editor
.getSettings();
206 editorSettings
.setAdditionalLinesCount(0);
207 editorSettings
.setAdditionalColumnsCount(1);
208 editorSettings
.setRightMarginShown(false);
209 editorSettings
.setFoldingOutlineShown(false);
210 editorSettings
.setLineNumbersShown(false);
211 editorSettings
.setLineMarkerAreaShown(false);
212 editorSettings
.setVirtualSpace(false);
213 editorSettings
.setLineCursorWidth(1);
216 public void setUiUpdateRunnable(Runnable uiUpdateRunnable
) {
217 assert myUiUpdateRunnable
== null : "can be set only once";
218 myUiUpdateRunnable
= uiUpdateRunnable
;
221 public LightVirtualFile
getHistoryFile() {
222 return myHistoryFile
;
225 public String
getPrompt() {
229 public void setPrompt(String prompt
) {
231 ((EditorImpl
)myConsoleEditor
).setPrefixTextAndAttributes(myPrompt
, ConsoleViewContentType
.USER_INPUT
.getAttributes());
234 public PsiFile
getFile() {
238 public EditorEx
getHistoryViewer() {
239 return myHistoryViewer
;
242 public Document
getEditorDocument() {
243 return myEditorDocument
;
246 public EditorEx
getConsoleEditor() {
247 return myConsoleEditor
;
250 public Project
getProject() {
254 public String
getTitle() {
258 public void setTitle(String title
) {
259 this.myTitle
= title
;
262 public void addToHistory(final String text
, final ConsoleViewContentType contentType
) {
263 final boolean scrollToEnd
= shouldScrollHistoryToEnd();
264 final Document history
= myHistoryViewer
.getDocument();
265 final MarkupModel markupModel
= history
.getMarkupModel(myProject
);
266 final int offset
= history
.getTextLength();
267 history
.insertString(offset
, text
);
268 if (!text
.endsWith("\n")) history
.insertString(history
.getTextLength(), "\n");
269 markupModel
.addRangeHighlighter(offset
, history
.getTextLength(), HighlighterLayer
.SYNTAX
, contentType
.getAttributes(),
270 HighlighterTargetArea
.EXACT_RANGE
);
271 queueUiUpdate(scrollToEnd
);
275 public String
addCurrentToHistory(final TextRange textRange
, final boolean erase
) {
276 final Ref
<String
> ref
= Ref
.create("");
277 final boolean scrollToEnd
= shouldScrollHistoryToEnd();
278 ApplicationManager
.getApplication().runWriteAction(new Runnable() {
280 ref
.set(addTextRangeToHistory(textRange
));
282 myConsoleEditor
.getDocument().deleteString(textRange
.getStartOffset(), textRange
.getEndOffset());
286 queueUiUpdate(scrollToEnd
);
290 private boolean shouldScrollHistoryToEnd() {
291 final Rectangle visibleArea
= myHistoryViewer
.getScrollingModel().getVisibleArea();
292 final int lineNum
= (visibleArea
.y
+ visibleArea
.height
+ myHistoryViewer
.getLineHeight()) / myHistoryViewer
.getLineHeight();
293 final int lineCount
= myHistoryViewer
.getDocument().getLineCount();
294 return lineNum
== lineCount
;
297 private void scrollHistoryToEnd() {
298 final int lineCount
= myHistoryViewer
.getDocument().getLineCount();
299 if (lineCount
== 0) return;
300 myHistoryViewer
.getCaretModel().moveToOffset(myHistoryViewer
.getDocument().getLineStartOffset(lineCount
- 1));
301 myHistoryViewer
.getScrollingModel().scrollToCaret(ScrollType
.MAKE_VISIBLE
);
304 private String
addTextRangeToHistory(TextRange textRange
) {
305 final DocumentImpl history
= (DocumentImpl
)myHistoryViewer
.getDocument();
306 final MarkupModel markupModel
= history
.getMarkupModel(myProject
);
307 final int promptOffset
= history
.getTextLength();
308 history
.insertString(history
.getTextLength(), myPrompt
);
309 markupModel
.addRangeHighlighter(promptOffset
, history
.getTextLength(), HighlighterLayer
.SYNTAX
, ConsoleViewContentType
.USER_INPUT
.getAttributes(),
310 HighlighterTargetArea
.EXACT_RANGE
);
312 final int offset
= history
.getTextLength();
313 final String text
= textRange
.substring(myConsoleEditor
.getDocument().getText());
314 history
.insertString(offset
, text
);
315 final HighlighterIterator iterator
= myConsoleEditor
.getHighlighter().createIterator(0);
316 while (!iterator
.atEnd()) {
317 final int localOffset
= textRange
.getStartOffset();
318 final int start
= Math
.max(iterator
.getStart(), localOffset
) - localOffset
;
319 final int end
= Math
.min(iterator
.getEnd(), textRange
.getEndOffset()) - localOffset
;
321 markupModel
.addRangeHighlighter(start
+ offset
, end
+ offset
, HighlighterLayer
.SYNTAX
, iterator
.getTextAttributes(),
322 HighlighterTargetArea
.EXACT_RANGE
);
326 duplicateHighlighters(markupModel
, myConsoleEditor
.getDocument().getMarkupModel(myProject
), offset
, textRange
);
327 duplicateHighlighters(markupModel
, myConsoleEditor
.getMarkupModel(), offset
, textRange
);
328 if (!text
.endsWith("\n")) history
.insertString(history
.getTextLength(), "\n");
332 private static void duplicateHighlighters(MarkupModel to
, MarkupModel from
, int offset
, TextRange textRange
) {
333 for (RangeHighlighter rangeHighlighter
: from
.getAllHighlighters()) {
334 final int localOffset
= textRange
.getStartOffset();
335 final int start
= Math
.max(rangeHighlighter
.getStartOffset(), localOffset
) - localOffset
;
336 final int end
= Math
.min(rangeHighlighter
.getEndOffset(), textRange
.getEndOffset()) - localOffset
;
337 if (start
> end
) continue;
338 final RangeHighlighter h
= to
.addRangeHighlighter(
339 start
+ offset
, end
+ offset
, rangeHighlighter
.getLayer(), rangeHighlighter
.getTextAttributes(), rangeHighlighter
.getTargetArea());
340 ((RangeHighlighterEx
)h
).setAfterEndOfLine(((RangeHighlighterEx
)rangeHighlighter
).isAfterEndOfLine());
344 public JComponent
getComponent() {
348 private void queueUiUpdate(final boolean forceScrollToEnd
) {
349 myForceScrollToEnd
.compareAndSet(false, forceScrollToEnd
);
350 myUpdateQueue
.queue(new Update("UpdateUi") {
352 if (Disposer
.isDisposed(LanguageConsoleImpl
.this)) return;
353 updateSizes(myForceScrollToEnd
.getAndSet(false));
354 if (myUiUpdateRunnable
!= null) {
355 ApplicationManager
.getApplication().runReadAction(myUiUpdateRunnable
);
361 private void updateSizes(boolean forceScrollToEnd
) {
362 final Dimension panelSize
= myPanel
.getSize();
363 final Dimension historyContentSize
= myHistoryViewer
.getContentSize();
364 final Dimension contentSize
= myConsoleEditor
.getContentSize();
365 final Dimension newEditorSize
= new Dimension();
366 final int minHistorySize
= historyContentSize
.height
> 0 ?
2 * myHistoryViewer
.getLineHeight() + SEPARATOR_THICKNESS
: 0;
367 final int width
= Math
.max(contentSize
.width
, historyContentSize
.width
);
368 newEditorSize
.height
= Math
.min(Math
.max(panelSize
.height
- minHistorySize
, 2 * myConsoleEditor
.getLineHeight()),
369 contentSize
.height
+ myConsoleEditor
.getScrollPane().getHorizontalScrollBar().getHeight());
370 newEditorSize
.width
= width
+ myConsoleEditor
.getScrollPane().getHorizontalScrollBar().getHeight();
371 myConsoleEditor
.getSettings().setAdditionalColumnsCount(2 + (width
- contentSize
.width
) / EditorUtil
.getSpaceWidth(Font
.PLAIN
, myConsoleEditor
));
372 myHistoryViewer
.getSettings().setAdditionalColumnsCount(2 + (width
- historyContentSize
.width
) / EditorUtil
.getSpaceWidth(Font
.PLAIN
, myHistoryViewer
));
374 final Dimension editorSize
= myConsoleEditor
.getComponent().getSize();
375 if (!editorSize
.equals(newEditorSize
)) {
376 myConsoleEditor
.getComponent().setPreferredSize(newEditorSize
);
378 final boolean scrollToEnd
= forceScrollToEnd
|| shouldScrollHistoryToEnd();
379 final Dimension newHistorySize
= new Dimension(
380 width
, Math
.max(0, Math
.min(minHistorySize
== 0?
0 : historyContentSize
.height
+ SEPARATOR_THICKNESS
,
381 panelSize
.height
- newEditorSize
.height
)));
382 final Dimension historySize
= myHistoryViewer
.getComponent().getSize();
383 if (!historySize
.equals(newHistorySize
)) {
384 myHistoryViewer
.getComponent().setPreferredSize(newHistorySize
);
387 if (scrollToEnd
) scrollHistoryToEnd();
390 public void dispose() {
391 final EditorFactory editorFactory
= EditorFactory
.getInstance();
392 editorFactory
.releaseEditor(myConsoleEditor
);
393 editorFactory
.releaseEditor(myHistoryViewer
);
395 final VirtualFile virtualFile
= myFile
.getVirtualFile();
396 assert virtualFile
!= null;
397 final FileEditorManager editorManager
= FileEditorManager
.getInstance(getProject());
398 final boolean isOpen
= editorManager
.isFileOpen(virtualFile
);
400 editorManager
.closeFile(virtualFile
);
404 public void calcData(DataKey key
, DataSink sink
) {
405 if (OpenFileDescriptor
.NAVIGATE_IN_EDITOR
== key
) {
406 sink
.put(OpenFileDescriptor
.NAVIGATE_IN_EDITOR
, myConsoleEditor
);
410 ((FileEditorManagerImpl
)FileEditorManager
.getInstance(getProject())).getData(key
.getName(), myConsoleEditor
, myFile
.getVirtualFile());
414 public void openInEditor() {
415 final VirtualFile virtualFile
= myFile
.getVirtualFile();
416 assert virtualFile
!= null;
417 FileEditorManager
.getInstance(getProject()).openTextEditor(
418 new OpenFileDescriptor(getProject(), virtualFile
, myConsoleEditor
.getCaretModel().getOffset()), true);
421 private void installEditorFactoryListener() {
422 final EditorFactoryListener factoryListener
= new EditorFactoryListener() {
423 public void editorCreated(final EditorFactoryEvent event
) {
424 final Editor editor
= event
.getEditor();
425 if (editor
.getDocument() == myEditorDocument
) {
426 if (myConsoleEditor
!= null) {
427 // i.e. if console is initialized
428 queueUiUpdate(false);
429 registerActionShortcuts(editor
.getComponent());
431 editor
.getCaretModel().addCaretListener(new CaretListener() {
432 public void caretPositionChanged(CaretEvent e
) {
433 queueUiUpdate(false);
436 editor
.getContentComponent().addFocusListener(new FocusListener() {
437 public void focusGained(final FocusEvent e
) {
438 myCurrentEditor
= editor
;
441 public void focusLost(final FocusEvent e
) {
447 public void editorReleased(final EditorFactoryEvent event
) {
450 EditorFactory
.getInstance().addEditorFactoryListener(factoryListener
);
451 Disposer
.register(this, new Disposable() {
452 public void dispose() {
453 EditorFactory
.getInstance().removeEditorFactoryListener(factoryListener
);
458 protected void registerActionShortcuts(JComponent component
) {
459 final ArrayList
<AnAction
> actionList
= (ArrayList
<AnAction
>)myConsoleEditor
.getComponent().getClientProperty(AnAction
.ourClientProperty
);
460 if (actionList
!= null) {
461 for (AnAction anAction
: actionList
) {
462 anAction
.registerCustomShortcutSet(anAction
.getShortcutSet(), component
);
467 public Editor
getCurrentEditor() {
468 return myCurrentEditor
;
471 public void setLanguage(Language language
) {
472 final PsiFile prevFile
= myFile
;
473 if (prevFile
!= null) {
474 final VirtualFile file
= prevFile
.getVirtualFile();
475 assert file
instanceof LightVirtualFile
;
476 ((LightVirtualFile
)file
).setValid(false);
477 ((PsiManagerEx
)prevFile
.getManager()).getFileManager().setViewProvider(file
, null);
480 final FileType type
= language
.getAssociatedFileType();
481 @NonNls final String name
= getTitle() + "." + (type
== null ?
"txt" : type
.getDefaultExtension());
482 final LightVirtualFile newVFile
= new LightVirtualFile(name
, language
, myEditorDocument
.getText());
483 FileDocumentManagerImpl
.registerDocument(myEditorDocument
, newVFile
);
484 myFile
= ((PsiFileFactoryImpl
)PsiFileFactory
.getInstance(myProject
)).trySetupPsiForFile(newVFile
, language
, true, false);
485 if (myFile
== null) {
486 throw new AssertionError("file=null, name=" + name
+ ", language=" + language
.getDisplayName());
488 PsiDocumentManagerImpl
.cachePsi(myEditorDocument
, myFile
);
489 FileContentUtil
.reparseFiles(myProject
, Collections
.<VirtualFile
>singletonList(newVFile
), false);
491 if (prevFile
!= null) {
492 final FileEditorManager editorManager
= FileEditorManager
.getInstance(getProject());
493 final VirtualFile file
= prevFile
.getVirtualFile();
494 if (file
!= null && editorManager
.isFileOpen(file
)) {
495 final FileEditor prevEditor
= editorManager
.getSelectedEditor(file
);
496 final boolean focusEditor
;
498 if (prevEditor
!= null) {
499 offset
= prevEditor
instanceof TextEditor ?
((TextEditor
)prevEditor
).getEditor().getCaretModel().getOffset() : 0;
500 final Component owner
= FocusManager
.getCurrentManager().getFocusOwner();
501 focusEditor
= owner
!= null && SwingUtilities
.isDescendingFrom(owner
, prevEditor
.getComponent());
507 editorManager
.closeFile(file
);
508 assert newVFile
!= null;
509 editorManager
.openTextEditor(new OpenFileDescriptor(getProject(), newVFile
, offset
), focusEditor
);
514 public void setInputText(final String query
) {
515 ApplicationManager
.getApplication().runWriteAction(new Runnable() {
517 myConsoleEditor
.getDocument().setText(query
);
522 private class MyOpenInEditorAction
extends DumbAwareAction
{
524 protected MyOpenInEditorAction() {
525 super("Open In Editor", null, null);
526 setShortcutSet(new CustomShortcutSet(KeyStroke
.getKeyStroke(KeyEvent
.VK_F4
, InputEvent
.CTRL_MASK
| InputEvent
.ALT_MASK
)));
530 public void actionPerformed(AnActionEvent e
) {
535 public void update(AnActionEvent e
) {