blob: 9ff6f75ce643ab4448ca0dca9b1d6c3e473c3144 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.lookup.impl;
import com.intellij.codeInsight.completion.CodeCompletionFeatures;
import com.intellij.codeInsight.completion.CompletionProgressIndicator;
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl;
import com.intellij.codeInsight.lookup.CharFilter;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.ui.ListScrollingUtil;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public abstract class LookupActionHandler extends EditorActionHandler {
protected final EditorActionHandler myOriginalHandler;
private final boolean myRequireFocusedLookup;
public LookupActionHandler(EditorActionHandler originalHandler, boolean requireFocusedLookup) {
myOriginalHandler = originalHandler;
myRequireFocusedLookup = requireFocusedLookup;
}
@Override
public boolean executeInCommand(Editor editor, DataContext dataContext) {
return LookupManager.getActiveLookup(editor) == null;
}
@Override
public void doExecute(Editor editor, Caret caret, DataContext dataContext){
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor);
if (lookup == null || !lookup.isAvailableToUser() || myRequireFocusedLookup && !lookup.isFocused()) {
Project project = editor.getProject();
if (project != null) {
LookupManager.getInstance(project).hideActiveLookup();
}
myOriginalHandler.execute(editor, caret, dataContext);
return;
}
lookup.markSelectionTouched();
executeInLookup(lookup, dataContext, caret);
}
protected abstract void executeInLookup(LookupImpl lookup, DataContext context, @Nullable Caret caret);
@Override
public boolean isEnabled(Editor editor, DataContext dataContext) {
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor);
return lookup != null || myOriginalHandler.isEnabled(editor, dataContext);
}
private static void executeUpOrDown(LookupImpl lookup, boolean up) {
if (!lookup.isFocused()) {
boolean semiFocused = lookup.getFocusDegree() == LookupImpl.FocusDegree.SEMI_FOCUSED;
lookup.setFocusDegree(LookupImpl.FocusDegree.FOCUSED);
if (!up && !semiFocused) {
return;
}
}
if (up) {
ListScrollingUtil.moveUp(lookup.getList(), 0);
} else {
ListScrollingUtil.moveDown(lookup.getList(), 0);
}
lookup.markSelectionTouched();
lookup.refreshUi(false, true);
}
public static class DownHandler extends LookupActionHandler {
public DownHandler(EditorActionHandler originalHandler){
super(originalHandler, false);
}
@Override
protected void executeInLookup(final LookupImpl lookup, DataContext context, Caret caret) {
executeUpOrDown(lookup, false);
}
}
public static class UpAction extends DumbAwareAction {
@Override
public void actionPerformed(AnActionEvent e) {
FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_CONTROL_ARROWS);
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(CommonDataKeys.EDITOR.getData(e.getDataContext()));
assert lookup != null;
lookup.hide();
ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_MOVE_CARET_UP).actionPerformed(e);
}
@Override
public void update(AnActionEvent e) {
Lookup lookup = LookupManager.getActiveLookup(CommonDataKeys.EDITOR.getData(e.getDataContext()));
e.getPresentation().setEnabled(lookup != null);
}
}
public static class DownAction extends DumbAwareAction {
@Override
public void actionPerformed(AnActionEvent e) {
FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_CONTROL_ARROWS);
LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(CommonDataKeys.EDITOR.getData(e.getDataContext()));
assert lookup != null;
lookup.hide();
ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN).actionPerformed(e);
}
@Override
public void update(AnActionEvent e) {
Lookup lookup = LookupManager.getActiveLookup(CommonDataKeys.EDITOR.getData(e.getDataContext()));
e.getPresentation().setEnabled(lookup != null);
}
}
public static class UpHandler extends LookupActionHandler {
public UpHandler(EditorActionHandler originalHandler){
super(originalHandler, false);
}
@Override
protected void executeInLookup(final LookupImpl lookup, DataContext context, Caret caret) {
if (!UISettings.getInstance().CYCLE_SCROLLING && !lookup.isFocused() && lookup.getList().getSelectedIndex() == 0) {
myOriginalHandler.execute(lookup.getEditor(), caret, context);
return;
}
executeUpOrDown(lookup, true);
}
}
public static class PageDownHandler extends LookupActionHandler {
public PageDownHandler(final EditorActionHandler originalHandler) {
super(originalHandler, false);
}
@Override
protected void executeInLookup(final LookupImpl lookup, DataContext context, Caret caret) {
lookup.setFocusDegree(LookupImpl.FocusDegree.FOCUSED);
ListScrollingUtil.movePageDown(lookup.getList());
}
}
public static class PageUpHandler extends LookupActionHandler {
public PageUpHandler(EditorActionHandler originalHandler){
super(originalHandler, false);
}
@Override
protected void executeInLookup(final LookupImpl lookup, DataContext context, Caret caret) {
lookup.setFocusDegree(LookupImpl.FocusDegree.FOCUSED);
ListScrollingUtil.movePageUp(lookup.getList());
}
}
public static class LeftHandler extends LookupActionHandler {
public LeftHandler(EditorActionHandler originalHandler) {
super(originalHandler, false);
}
@Override
protected void executeInLookup(final LookupImpl lookup, DataContext context, Caret caret) {
if (!lookup.isCompletion()) {
myOriginalHandler.execute(lookup.getEditor(), caret, context);
return;
}
if (!lookup.performGuardedChange(new Runnable() {
@Override
public void run() {
lookup.getEditor().getSelectionModel().removeSelection();
}
})) {
return;
}
BackspaceHandler.truncatePrefix(context, lookup, myOriginalHandler, lookup.getLookupStart() - 1, caret);
}
}
public static class RightHandler extends LookupActionHandler {
public RightHandler(EditorActionHandler originalHandler) {
super(originalHandler, false);
}
@Override
protected void executeInLookup(LookupImpl lookup, DataContext context, Caret caret) {
final Editor editor = lookup.getEditor();
final int offset = editor.getCaretModel().getOffset();
CharSequence seq = editor.getDocument().getCharsSequence();
if (seq.length() <= offset || !lookup.isCompletion()) {
myOriginalHandler.execute(editor, caret, context);
return;
}
char c = seq.charAt(offset);
CharFilter.Result lookupAction = LookupTypedHandler.getLookupAction(c, lookup);
if (lookupAction != CharFilter.Result.ADD_TO_PREFIX || Character.isWhitespace(c)) {
myOriginalHandler.execute(editor, caret, context);
return;
}
if (!lookup.performGuardedChange(new Runnable() {
@Override
public void run() {
editor.getSelectionModel().removeSelection();
editor.getCaretModel().moveToOffset(offset + 1);
}
})) {
return;
}
lookup.appendPrefix(c);
final CompletionProgressIndicator completion = CompletionServiceImpl.getCompletionService().getCurrentCompletion();
if (completion != null) {
completion.prefixUpdated();
}
}
}
}