Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ilya.Kazakevich
2015-01-30 21:29:04 +03:00
25 changed files with 429 additions and 169 deletions
@@ -18,10 +18,10 @@ package com.intellij.compiler.impl;
import com.intellij.compiler.ProblemsView;
import com.intellij.icons.AllIcons;
import com.intellij.ide.errorTreeView.ErrorTreeElement;
import com.intellij.ide.errorTreeView.ErrorTreeElementKind;
import com.intellij.ide.errorTreeView.ErrorViewStructure;
import com.intellij.ide.errorTreeView.GroupingElement;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
@@ -40,6 +40,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.ide.PooledThreadExecutor;
import javax.swing.*;
import java.util.EnumSet;
import java.util.UUID;
/**
@@ -48,7 +49,8 @@ import java.util.UUID;
*/
public class ProblemsViewImpl extends ProblemsView{
private static final String PROBLEMS_TOOLWINDOW_ID = "Problems";
private static final EnumSet<ErrorTreeElementKind> ALL_MESSAGE_KINDS = EnumSet.allOf(ErrorTreeElementKind.class);
private final ProblemsViewPanel myPanel;
private final SequentialTaskExecutor myViewUpdater = new SequentialTaskExecutor(PooledThreadExecutor.INSTANCE);
private final Icon myActiveIcon = AllIcons.Toolwindows.Problems;
@@ -70,7 +72,6 @@ public class ProblemsViewImpl extends ProblemsView{
return;
}
final ToolWindow tw = wm.registerToolWindow(PROBLEMS_TOOLWINDOW_ID, false, ToolWindowAnchor.BOTTOM, project, true);
updateIcon(false);
final Content content = ContentFactory.SERVICE.getInstance().createContent(myPanel, "", false);
// todo: setup content?
tw.getContentManager().addContent(content);
@@ -80,6 +81,7 @@ public class ProblemsViewImpl extends ProblemsView{
tw.getContentManager().removeAllContents(true);
}
});
updateIcon();
}
});
}
@@ -89,19 +91,16 @@ public class ProblemsViewImpl extends ProblemsView{
myViewUpdater.execute(new Runnable() {
@Override
public void run() {
updateIcon(!cleanupChildrenRecursively(myPanel.getErrorViewStructure().getRootElement(), scope, currentSessionId));
cleanupChildrenRecursively(myPanel.getErrorViewStructure().getRootElement(), scope, currentSessionId);
updateIcon();
myPanel.reload();
}
});
}
private boolean cleanupChildrenRecursively(@NotNull final Object fromElement, final @Nullable CompileScope scope, @NotNull UUID currentSessionId) {
private void cleanupChildrenRecursively(@NotNull final Object fromElement, final @Nullable CompileScope scope, @NotNull UUID currentSessionId) {
final ErrorViewStructure structure = myPanel.getErrorViewStructure();
ErrorTreeElement[] elements = structure.getChildElements(fromElement);
if (elements.length ==0) return true;
boolean result = false;
for (ErrorTreeElement element : elements) {
for (ErrorTreeElement element : structure.getChildElements(fromElement)) {
if (element instanceof GroupingElement) {
if (scope != null) {
final VirtualFile file = ((GroupingElement)element).getFile();
@@ -111,20 +110,17 @@ public class ProblemsViewImpl extends ProblemsView{
}
if (!currentSessionId.equals(element.getData())) {
structure.removeElement(element);
result = true;
}
else {
result |= cleanupChildrenRecursively(element, scope, currentSessionId);
cleanupChildrenRecursively(element, scope, currentSessionId);
}
}
else {
if (!currentSessionId.equals(element.getData())) {
structure.removeElement(element);
result = true;
}
}
}
return result;
}
@Override
@@ -139,7 +135,7 @@ public class ProblemsViewImpl extends ProblemsView{
public void run() {
final ErrorViewStructure structure = myPanel.getErrorViewStructure();
final GroupingElement group = structure.lookupGroupingElement(groupName);
if (group != null && !sessionId.equals(group.getData())) {
if (group != null && sessionId != null && !sessionId.equals(group.getData())) {
structure.removeElement(group);
}
if (navigatable != null) {
@@ -148,21 +144,24 @@ public class ProblemsViewImpl extends ProblemsView{
else {
myPanel.addMessage(type, text, null, -1, -1, sessionId);
}
updateIcon(true);
updateIcon();
}
});
}
private void updateIcon(final boolean active) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
private void updateIcon() {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
final ToolWindow tw = ToolWindowManager.getInstance(myProject).getToolWindow(PROBLEMS_TOOLWINDOW_ID);
if (tw != null) {
tw.setIcon(active ? myActiveIcon : myPassiveIcon);
if (!myProject.isDisposed()) {
final ToolWindow tw = ToolWindowManager.getInstance(myProject).getToolWindow(PROBLEMS_TOOLWINDOW_ID);
if (tw != null) {
final boolean active = myPanel.getErrorViewStructure().hasMessages(ALL_MESSAGE_KINDS);
tw.setIcon(active ? myActiveIcon : myPassiveIcon);
}
}
}
}, myProject.getDisposed());
});
}
@Override
@@ -21,7 +21,7 @@ import com.intellij.openapi.project.Project;
public class ProblemsViewPanel extends NewErrorTreeViewPanel {
public ProblemsViewPanel(Project project) {
super(project, null, false, true, null);
super(project, "reference.problems.tool.window", false, true, null);
myTree.getEmptyText().setText("No compilation problems found");
}
@@ -46,7 +46,9 @@ public abstract class LanguageLevelConfigurable implements UnnamedConfigurable {
});
myLanguageLevelCombo.insertItemAt(LanguageLevelCombo.USE_PROJECT_LANGUAGE_LEVEL, 0);
myPanel.add(new JLabel(ProjectBundle.message("module.module.language.level")),
JLabel label = new JLabel(ProjectBundle.message("module.module.language.level"));
label.setLabelFor(myLanguageLevelCombo);
myPanel.add(label,
new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(12, 6, 12, 0), 0, 0));
myPanel.add(myLanguageLevelCombo,
new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(6, 6, 12, 0), 0, 0));
@@ -27,6 +27,8 @@ import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JdkVersionUtil;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiFile;
@@ -96,6 +98,7 @@ public class IncreaseLanguageLevelFix implements IntentionAction {
}
else {
LanguageLevelProjectExtension.getInstance(project).setLanguageLevel(myLevel);
ProjectRootManagerEx.getInstanceEx(project).makeRootsChange(EmptyRunnable.INSTANCE, false, true);
}
}
@@ -0,0 +1,18 @@
package com.intellij.codeInspection;
import com.intellij.psi.PsiElement;
import com.intellij.util.ThreeState;
/**
* This kind of suppression fix allows to clients to specify whether the fix should
* be invoked on injected elements or on elements of host files.
* <p/>
* By default suppression fixes on injected elements are able to make suppression inside injection only.
* Whereas implementation of this interface will be provided for suppressing inside injection and in injection host.
* See {@link InspectionProfileEntry#getBatchSuppressActions(PsiElement)} for details.
*/
public interface InjectionAwareSuppressQuickFix extends SuppressQuickFix {
ThreeState isShouldBeAppliedToInjectionHost();
void setShouldBeAppliedToInjectionHost(ThreeState shouldBeAppliedToInjectionHost);
}
@@ -17,6 +17,7 @@ package com.intellij.codeInspection;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.lang.Language;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
@@ -24,8 +25,10 @@ import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider;
import com.intellij.util.ResourceUtil;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.SerializationFilter;
import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
@@ -44,14 +47,16 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* @author anna
* @since 28-Nov-2005
*/
@SuppressWarnings("JavadocReference")
public abstract class InspectionProfileEntry implements BatchSuppressableTool{
public abstract class InspectionProfileEntry implements BatchSuppressableTool {
public static final String GENERAL_GROUP_NAME = InspectionsBundle.message("inspection.general.tools.group.name");
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.InspectionProfileEntry");
@@ -93,22 +98,52 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
Set<SuppressQuickFix> fixes = new THashSet<SuppressQuickFix>(new TObjectHashingStrategy<SuppressQuickFix>() {
@Override
public int computeHashCode(SuppressQuickFix object) {
return object.getName().hashCode();
int result = object instanceof InjectionAwareSuppressQuickFix
? ((InjectionAwareSuppressQuickFix)object).isShouldBeAppliedToInjectionHost().hashCode()
: 0;
return 31 * result + object.getName().hashCode();
}
@Override
public boolean equals(SuppressQuickFix o1, SuppressQuickFix o2) {
if (o1 instanceof InjectionAwareSuppressQuickFix && o2 instanceof InjectionAwareSuppressQuickFix) {
if (((InjectionAwareSuppressQuickFix)o1).isShouldBeAppliedToInjectionHost() != ((InjectionAwareSuppressQuickFix)o2).isShouldBeAppliedToInjectionHost()) {
return false;
}
}
return o1.getName().equals(o2.getName());
}
});
Set<InspectionSuppressor> suppressors = getSuppressors(element);
final PsiLanguageInjectionHost injectionHost = InjectedLanguageManager.getInstance(element.getProject()).getInjectionHost(element);
if (injectionHost != null) {
Set<InspectionSuppressor> injectionHostSuppressors = getSuppressors(injectionHost);
for (InspectionSuppressor suppressor : injectionHostSuppressors) {
addAllSuppressActions(fixes, injectionHost, suppressor, ThreeState.YES, getShortName());
}
}
for (InspectionSuppressor suppressor : suppressors) {
SuppressQuickFix[] actions = suppressor.getSuppressActions(element, getShortName());
fixes.addAll(Arrays.asList(actions));
addAllSuppressActions(fixes, element, suppressor, injectionHost != null ? ThreeState.NO : ThreeState.UNSURE, getShortName());
}
return fixes.toArray(new SuppressQuickFix[fixes.size()]);
}
private static void addAllSuppressActions(Set<SuppressQuickFix> fixes,
PsiElement element,
InspectionSuppressor suppressor,
ThreeState appliedToInjectionHost,
String toolShortName) {
final SuppressQuickFix[] actions = suppressor.getSuppressActions(element, toolShortName);
for (SuppressQuickFix action : actions) {
if (action instanceof InjectionAwareSuppressQuickFix) {
((InjectionAwareSuppressQuickFix)action).setShouldBeAppliedToInjectionHost(appliedToInjectionHost);
}
fixes.add(action);
}
}
private boolean isSuppressed(@NotNull String toolId,
@NotNull InspectionSuppressor suppressor,
@NotNull PsiElement element) {
@@ -132,7 +167,9 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
ContainerUtil.addIfNotNull(suppressors, elementLanguageSuppressor);
return suppressors;
}
return elementLanguageSuppressor != null ? Collections.singleton(elementLanguageSuppressor) : Collections.<InspectionSuppressor>emptySet();
return elementLanguageSuppressor != null
? Collections.singleton(elementLanguageSuppressor)
: Collections.<InspectionSuppressor>emptySet();
}
public void cleanup(Project project) {
@@ -148,9 +185,9 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
protected volatile DefaultNameProvider myNameProvider = null;
/**
* @see com.intellij.codeInspection.InspectionEP#groupDisplayName
* @see com.intellij.codeInspection.InspectionEP#groupKey
* @see com.intellij.codeInspection.InspectionEP#groupBundle
* @see InspectionEP#groupDisplayName
* @see InspectionEP#groupKey
* @see InspectionEP#groupBundle
*/
@Nls
@NotNull
@@ -166,7 +203,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
}
/**
* @see com.intellij.codeInspection.InspectionEP#groupPath
* @see InspectionEP#groupPath
*/
@NotNull
public String[] getGroupPath() {
@@ -178,9 +215,9 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
}
/**
* @see com.intellij.codeInspection.InspectionEP#displayName
* @see com.intellij.codeInspection.InspectionEP#key
* @see com.intellij.codeInspection.InspectionEP#bundle
* @see InspectionEP#displayName
* @see InspectionEP#key
* @see InspectionEP#bundle
*/
@Nls
@NotNull
@@ -198,7 +235,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
/**
* DO NOT OVERRIDE this method.
*
* @see com.intellij.codeInspection.InspectionEP#shortName
* @see InspectionEP#shortName
*/
@NonNls
@NotNull
@@ -214,13 +251,13 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
@NotNull
public static String getShortName(@NotNull String className) {
return StringUtil.trimEnd(StringUtil.trimEnd(className, "Inspection"),"InspectionBase");
return StringUtil.trimEnd(StringUtil.trimEnd(className, "Inspection"), "InspectionBase");
}
/**
* DO NOT OVERRIDE this method.
*
* @see com.intellij.codeInspection.InspectionEP#level
* @see InspectionEP#level
*/
@NotNull
public HighlightDisplayLevel getDefaultLevel() {
@@ -230,7 +267,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
/**
* DO NOT OVERRIDE this method.
*
* @see com.intellij.codeInspection.InspectionEP#enabledByDefault
* @see InspectionEP#enabledByDefault
*/
public boolean isEnabledByDefault() {
return false;
@@ -238,6 +275,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
/**
* This method is called each time UI is shown.
*
* @return null if no UI options required.
*/
@Nullable
@@ -348,7 +386,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
* Initialize inspection with project. Is called on project opened for all profiles as well as on profile creation.
*
* @param project to be associated with this entry
* @deprecated this won't work for inspections configured via {@link com.intellij.codeInspection.InspectionEP}
* @deprecated this won't work for inspections configured via {@link InspectionEP}
*/
public void projectOpened(@NotNull Project project) {
}
@@ -357,7 +395,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
* Cleanup inspection settings corresponding to the project. Is called on project closed for all profiles as well as on profile deletion.
*
* @param project to be disassociated from this entry
* @deprecated this won't work for inspections configured via {@link com.intellij.codeInspection.InspectionEP}
* @deprecated this won't work for inspections configured via {@link InspectionEP}
*/
public void projectClosed(@NotNull Project project) {
}
@@ -411,7 +449,8 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
if (descriptionUrl == null) return null;
return ResourceUtil.loadText(descriptionUrl);
}
catch (IOException ignored) { }
catch (IOException ignored) {
}
return null;
}
@@ -17,9 +17,9 @@
package com.intellij.codeInsight.daemon.impl.actions;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInspection.InjectionAwareSuppressQuickFix;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.SuppressQuickFix;
import com.intellij.codeInspection.SuppressionUtil;
import com.intellij.icons.AllIcons;
import com.intellij.lang.Language;
@@ -32,6 +32,7 @@ import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -43,9 +44,10 @@ import java.util.List;
* @author Roman.Chernyatchik
* @date Aug 13, 2009
*/
public abstract class AbstractBatchSuppressByNoInspectionCommentFix implements SuppressQuickFix, Iconable {
public abstract class AbstractBatchSuppressByNoInspectionCommentFix implements InjectionAwareSuppressQuickFix, Iconable {
@NotNull protected final String myID;
private final boolean myReplaceOtherSuppressionIds;
private ThreeState myShouldBeAppliedToInjectionHost = ThreeState.UNSURE;
@Nullable
public abstract PsiElement getContainer(final PsiElement context);
@@ -60,6 +62,15 @@ public abstract class AbstractBatchSuppressByNoInspectionCommentFix implements S
myReplaceOtherSuppressionIds = replaceOtherSuppressionIds;
}
public void setShouldBeAppliedToInjectionHost(ThreeState shouldBeAppliedToInjectionHost) {
myShouldBeAppliedToInjectionHost = shouldBeAppliedToInjectionHost;
}
@Override
public ThreeState isShouldBeAppliedToInjectionHost() {
return myShouldBeAppliedToInjectionHost;
}
@NotNull
@Override
public String getName() {
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -59,9 +60,15 @@ public class SuppressIntentionActionFromFix extends SuppressIntentionAction {
}
}
public ThreeState isShouldBeAppliedToInjectionHost() {
return myFix instanceof InjectionAwareSuppressQuickFix
? ((InjectionAwareSuppressQuickFix)myFix).isShouldBeAppliedToInjectionHost()
: ThreeState.UNSURE;
}
public PsiElement getContainer(PsiElement element) {
return myFix instanceof AbstractBatchSuppressByNoInspectionCommentFix
? ((AbstractBatchSuppressByNoInspectionCommentFix )myFix).getContainer(element) : null;
? ((AbstractBatchSuppressByNoInspectionCommentFix)myFix).getContainer(element) : null;
}
@Override
@@ -72,7 +79,7 @@ public class SuppressIntentionActionFromFix extends SuppressIntentionAction {
@NotNull
@Override
public String getText() {
return myFix.getName();
return myFix.getName() + (isShouldBeAppliedToInjectionHost() == ThreeState.NO ? " in injection" : "");
}
@NotNull
@@ -143,7 +143,7 @@ public class EnvVariablesTable extends ListTableWithButtons<EnvironmentVariable>
public void actionPerformed(@NotNull AnActionEvent e) {
stopEditing();
StringBuilder sb = new StringBuilder();
List<EnvironmentVariable> variables = getEnvironmentVariables();
List<EnvironmentVariable> variables = getSelection();
for (EnvironmentVariable environmentVariable : variables) {
if (environmentVariable.getIsPredefined() || isEmpty(environmentVariable)) continue;
if (sb.length() > 0) sb.append('\n');
@@ -152,10 +152,16 @@ public class EnvVariablesTable extends ListTableWithButtons<EnvironmentVariable>
}
CopyPasteManager.getInstance().setContents(new StringSelection(sb.toString()));
}
@Override
public boolean isEnabled() {
return super.isEnabled() && !getSelection().isEmpty();
}
};
AnActionButton pasteButton = new AnActionButton(ActionsBundle.message("action.EditorPaste.text"), AllIcons.Actions.Menu_paste) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
removeSelected();
stopEditing();
String content = CopyPasteManager.getInstance().getContents(DataFlavor.stringFlavor);
if (content == null || !content.contains("=")) return;
@@ -172,13 +178,7 @@ public class EnvVariablesTable extends ListTableWithButtons<EnvironmentVariable>
StringUtil.unescapeStringCharacters(line.substring(pos + 1)),
false));
}
List<EnvironmentVariable> variables =
new ArrayList<EnvironmentVariable>(ContainerUtil.filter(getEnvironmentVariables(), new Condition<EnvironmentVariable>() {
@Override
public boolean value(EnvironmentVariable variable) {
return variable.getIsPredefined();
}
}));
List<EnvironmentVariable> variables = new ArrayList<EnvironmentVariable>(getEnvironmentVariables());
variables.addAll(parsed);
setValues(variables);
}
@@ -16,6 +16,7 @@
package com.intellij.execution.util;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.util.Condition;
import com.intellij.ui.*;
import com.intellij.ui.table.TableView;
import com.intellij.util.containers.ContainerUtil;
@@ -30,6 +31,7 @@ import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Observable;
@@ -110,31 +112,19 @@ public abstract class ListTableWithButtons<T> extends Observable {
}).setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
myTableView.stopEditing();
setModified();
T selected = getSelection();
if (selected != null) {
int selectedIndex = myElements.indexOf(selected);
myTableView.scrollRectToVisible(myTableView.getCellRect(selectedIndex, 0, true));
myElements.remove(selected);
myTableView.getTableViewModel().setItems(myElements);
int prev = selectedIndex - 1;
if (prev >= 0) {
myTableView.getComponent().getSelectionModel().setSelectionInterval(prev, prev);
}
else if (selectedIndex < myElements.size()) {
myTableView.getComponent().getSelectionModel().setSelectionInterval(selectedIndex, selectedIndex);
}
}
removeSelected();
}
}).disableUpDownActions().addExtraActions(createExtraActions()).createPanel();
ToolbarDecorator.findRemoveButton(myPanel).addCustomUpdater(new AnActionButtonUpdater() {
@Override
public boolean isEnabled(AnActionEvent e) {
T selection = getSelection();
return selection != null && myIsEnabled && canDeleteElement(selection);
List<T> selection = getSelection();
if (selection.isEmpty() || !myIsEnabled) return false;
for (T t : selection) {
if (!canDeleteElement(t)) return false;
}
return true;
}
});
ToolbarDecorator.findAddButton(myPanel).addCustomUpdater(new AnActionButtonUpdater() {
@@ -146,7 +136,33 @@ public abstract class ListTableWithButtons<T> extends Observable {
myActionsPanel = decorator.getActionsPanel();
myTableView.getComponent().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
myTableView.getComponent().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
}
protected void removeSelected() {
List<T> selected = getSelection();
if (!selected.isEmpty()) {
myTableView.stopEditing();
setModified();
int selectedIndex = myTableView.getSelectionModel().getLeadSelectionIndex();
myTableView.scrollRectToVisible(myTableView.getCellRect(selectedIndex, 0, true));
selected = ContainerUtil.filter(selected, new Condition<T>() {
@Override
public boolean value(T t) {
return canDeleteElement(t);
}
});
myElements.removeAll(selected);
myTableView.getTableViewModel().setItems(myElements);
int prev = selectedIndex - 1;
if (prev >= 0) {
myTableView.getComponent().getSelectionModel().setSelectionInterval(prev, prev);
}
else if (selectedIndex < myElements.size()) {
myTableView.getComponent().getSelectionModel().setSelectionInterval(selectedIndex, selectedIndex);
}
}
}
@NotNull
@@ -197,7 +213,9 @@ public abstract class ListTableWithButtons<T> extends Observable {
}
protected void editSelection(int column) {
int row = myElements.indexOf(getSelection());
List<T> selection = getSelection();
if (selection.size() != 1) return;
int row = myElements.indexOf(selection.get(0));
if (row != -1) {
TableUtil.editCellAt(myTableView, row, column);
}
@@ -213,13 +231,18 @@ public abstract class ListTableWithButtons<T> extends Observable {
}
protected T getSelection() {
int selIndex = myTableView.getComponent().getSelectionModel().getMinSelectionIndex();
if (selIndex < 0) {
return null;
@NotNull
protected List<T> getSelection() {
int[] selection = myTableView.getComponent().getSelectedRows();
if (selection.length == 0) {
return Collections.emptyList();
}
else {
return myElements.get(selIndex);
List<T> result = new ArrayList<T>(selection.length);
for (int row : selection) {
result.add(myElements.get(row));
}
return result;
}
}
@@ -28,10 +28,14 @@ import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.config.IntentionActionWrapper;
import com.intellij.codeInsight.intention.impl.config.IntentionManagerSettings;
import com.intellij.codeInsight.intention.impl.config.IntentionSettingsConfigurable;
import com.intellij.codeInsight.unwrap.ScopeHighlighter;
import com.intellij.codeInspection.SuppressIntentionActionFromFix;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
@@ -52,7 +56,9 @@ import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.refactoring.BaseRefactoringIntentionAction;
import com.intellij.ui.HintHint;
import com.intellij.ui.LightweightHint;
@@ -61,6 +67,7 @@ import com.intellij.ui.RowIcon;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Alarm;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.EmptyIcon;
import org.jetbrains.annotations.NotNull;
@@ -69,11 +76,14 @@ import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.List;
/**
@@ -441,12 +451,52 @@ public class IntentionHintComponent extends JPanel implements Disposable, Scroll
Disposer.dispose(myPopup);
}
myPopup = JBPopupFactory.getInstance().createListPopup(step);
final PsiFile injectedFile = InjectedLanguageUtil.findInjectedPsiNoCommit(myFile, myEditor.getCaretModel().getOffset());
final Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(myEditor, injectedFile);
final ScopeHighlighter highlighter = new ScopeHighlighter(myEditor);
final ScopeHighlighter injectionHighlighter = new ScopeHighlighter(injectedEditor);
myPopup.addListener(new JBPopupListener.Adapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
highlighter.dropHighlight();
injectionHighlighter.dropHighlight();
myPopupShown = false;
}
});
myPopup.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
final Object source = e.getSource();
highlighter.dropHighlight();
injectionHighlighter.dropHighlight();
if (source instanceof DataProvider) {
final Object selectedItem = PlatformDataKeys.SELECTED_ITEM.getData((DataProvider)source);
if (selectedItem instanceof IntentionActionWithTextCaching) {
final IntentionAction action = ((IntentionActionWithTextCaching)selectedItem).getAction();
if (action instanceof SuppressIntentionActionFromFix) {
if (injectedFile != null && ((SuppressIntentionActionFromFix)action).isShouldBeAppliedToInjectionHost() == ThreeState.NO) {
final PsiElement at = injectedFile.findElementAt(injectedEditor.getCaretModel().getOffset());
final PsiElement container = ((SuppressIntentionActionFromFix)action).getContainer(at);
if (container != null) {
injectionHighlighter.highlight(container, Collections.singletonList(container));
}
}
else {
final PsiElement at = myFile.findElementAt(myEditor.getCaretModel().getOffset());
final PsiElement container = ((SuppressIntentionActionFromFix)action).getContainer(at);
if (container != null) {
highlighter.highlight(container, Collections.singletonList(container));
}
}
}
}
}
}
});
if (myEditor.isOneLineMode()) {
// hide popup on combobox popup show
@@ -27,6 +27,7 @@ import com.intellij.codeInsight.intention.impl.config.IntentionActionWrapper;
import com.intellij.codeInsight.intention.impl.config.IntentionManagerSettings;
import com.intellij.codeInspection.IntentionWrapper;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.SuppressIntentionActionFromFix;
import com.intellij.codeInspection.ex.QuickFixWrapper;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.application.ApplicationManager;
@@ -39,6 +40,7 @@ import com.intellij.openapi.util.Iconable;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
@@ -321,6 +323,11 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
if (a instanceof LowPriorityAction) {
return group - 3;
}
if (a instanceof SuppressIntentionActionFromFix) {
if (((SuppressIntentionActionFromFix)a).isShouldBeAppliedToInjectionHost() == ThreeState.NO) {
return group - 1;
}
}
if (a instanceof QuickFixWrapper) {
final LocalQuickFix quickFix = ((QuickFixWrapper)a).getFix();
if (quickFix instanceof HighPriorityAction) {
@@ -27,6 +27,7 @@ import com.intellij.codeInsight.lookup.LookupEx;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.impl.TemplateState;
import com.intellij.codeInspection.SuppressIntentionActionFromFix;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.featureStatistics.FeatureUsageTrackerImpl;
import com.intellij.injected.editor.EditorWindow;
@@ -45,6 +46,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PairProcessor;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -107,6 +109,16 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
private static boolean isAvailableHere(Editor editor, PsiFile psiFile, PsiElement psiElement, boolean inProject, IntentionAction action) {
try {
Project project = psiFile.getProject();
if (action instanceof SuppressIntentionActionFromFix) {
final ThreeState shouldBeAppliedToInjectionHost = ((SuppressIntentionActionFromFix)action).isShouldBeAppliedToInjectionHost();
if (editor instanceof EditorWindow && shouldBeAppliedToInjectionHost == ThreeState.YES) {
return false;
}
if (!(editor instanceof EditorWindow) && shouldBeAppliedToInjectionHost == ThreeState.NO) {
return false;
}
}
if (action instanceof PsiElementBaseIntentionAction) {
if (!inProject || psiElement == null || !((PsiElementBaseIntentionAction)action).isAvailable(project, editor, psiElement)) return false;
}
@@ -30,9 +30,9 @@ import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
@@ -58,7 +58,7 @@ import java.util.Map;
/**
* @author gregsh
*/
public class RunIdeConsoleAction extends ActionGroup implements DumbAware {
public class RunIdeConsoleAction extends DumbAwareAction {
private static final String DEFAULT_FILE_NAME = "ide-scripting";
private static final Key<WeakReference<ConsoleView>> CONSOLE_VIEW_KEY = Key.create("CONSOLE_VIEW_KEY");
@@ -84,26 +84,23 @@ public class RunIdeConsoleAction extends ActionGroup implements DumbAware {
runConsole(e, ourEngines.values().iterator().next());
}
else {
super.actionPerformed(e);
}
}
@NotNull
@Override
public AnAction[] getChildren(@Nullable AnActionEvent e) {
if (e == null) return EMPTY_ARRAY;
return ContainerUtil.map2Array(ourEngines.values(), AnAction.class, new NotNullFunction<ScriptEngineFactory, AnAction>() {
@NotNull
@Override
public AnAction fun(final ScriptEngineFactory engine) {
return new AnAction(engine.getLanguageName()) {
DefaultActionGroup actions = new DefaultActionGroup(
ContainerUtil.map(ourEngines.values(), new NotNullFunction<ScriptEngineFactory, AnAction>() {
@NotNull
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
runConsole(e, engine);
public AnAction fun(final ScriptEngineFactory engine) {
return new AnAction(engine.getLanguageName()) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
runConsole(e, engine);
}
};
}
};
}
});
})
);
JBPopupFactory.getInstance().createActionGroupPopup("Script Engine", actions, e.getDataContext(), JBPopupFactory.ActionSelectionAid.NUMBERING, false).
showInBestPositionFor(e.getDataContext());
}
}
protected void runConsole(@NotNull AnActionEvent e, @NotNull ScriptEngineFactory engine) {
@@ -69,7 +69,7 @@ public final class ScratchRootType extends RootType {
}
}
private static class MyFileType extends LanguageFileType implements FileTypeIdentifiableByVirtualFile, InternalFileType {
private static class MyFileType extends LanguageFileType implements FileTypeIdentifiableByVirtualFile {
MyFileType() {
super(PlainTextLanguage.INSTANCE);
@@ -69,6 +69,30 @@ public class ErrorViewStructure extends AbstractTreeStructure {
return myRoot;
}
public boolean hasMessages(@NotNull Set<ErrorTreeElementKind> kinds) {
synchronized (myLock) {
for (Map.Entry<ErrorTreeElementKind, List<ErrorTreeElement>> entry : mySimpleMessages.entrySet()) {
if (kinds.contains(entry.getKey())) {
final List<ErrorTreeElement> messages = entry.getValue();
if (messages != null && !messages.isEmpty()) {
return true;
}
}
}
for (Map.Entry<String, List<NavigatableMessageElement>> entry : myGroupNameToMessagesMap.entrySet()) {
final List<NavigatableMessageElement> messages = entry.getValue();
if (messages != null && !messages.isEmpty()) {
for (NavigatableMessageElement message : messages) {
if (kinds.contains(message.getKind())) {
return true;
}
}
}
}
}
return false;
}
@Override
public ErrorTreeElement[] getChildElements(Object element) {
if (element == myRoot) {
@@ -267,6 +267,13 @@ public abstract class AbstractExpandableItemsHandler<KeyType, ComponentType exte
return;
}
myUpdateAlarm.cancelAllRequests();
if (selected == null) {
hideHint();
return;
}
if (!selected.equals(myKey)) {
hideHint();
}
myUpdateAlarm.addRequest(new Runnable() {
@Override
public void run() {
@@ -275,12 +282,8 @@ public abstract class AbstractExpandableItemsHandler<KeyType, ComponentType exte
}, 10);
}
private void doHandleSelectionChange(KeyType selected, boolean processIfUnfocused) {
Window window = SwingUtilities.getWindowAncestor(myComponent);
if (selected == null
|| window == null
|| !window.isActive()
|| !myEnabled
private void doHandleSelectionChange(@NotNull KeyType selected, boolean processIfUnfocused) {
if (!myEnabled
|| !myComponent.isEnabled()
|| !myComponent.isShowing()
|| !myComponent.getVisibleRect().intersects(getVisibleRect(selected))
@@ -300,6 +303,7 @@ public abstract class AbstractExpandableItemsHandler<KeyType, ComponentType exte
else {
Dimension size = myTipComponent.getPreferredSize();
myPopup.setBounds(location.x, location.y, size.width, size.height);
myPopup.setHeavyWeight(hasOwnedWindows());
if (!myPopup.isVisible()) {
myPopup.setVisible(true);
}
@@ -324,6 +328,17 @@ public abstract class AbstractExpandableItemsHandler<KeyType, ComponentType exte
return false;
}
private boolean hasOwnedWindows() {
Window owner = SwingUtilities.getWindowAncestor(myComponent);
Window popup = SwingUtilities.getWindowAncestor(myTipComponent);
for (Window other : owner.getOwnedWindows()) {
if (popup != other && other.isVisible()) {
return false;
}
}
return true;
}
private void hideHint() {
myUpdateAlarm.cancelAllRequests();
if (myPopup.isVisible()) {
@@ -210,6 +210,7 @@ public class MovablePopup implements Disposable {
myView.setBounds(location.x, location.y, size.width, size.height);
if (myView.isVisible()) {
myView.invalidate();
myView.validate();
myView.repaint();
}
}
@@ -104,13 +104,13 @@
<action id="EmmetNextEditPoint" class="com.intellij.codeInsight.template.emmet.actions.GoToEditPointAction$Forward"
text="Next Emmet Edit Point" description="Go to next Emmet edit point">
<keyboard-shortcut first-keystroke="alt shift OPEN_BRACKET" keymap="$default"/>
<keyboard-shortcut first-keystroke="alt shift CLOSE_BRACKET" keymap="$default"/>
<keyboard-shortcut first-keystroke="control alt RIGHT" keymap="Mac OS X 10.5+" replace-all="true"/>
</action>
<action id="EmmetPreviousEditPoint" class="com.intellij.codeInsight.template.emmet.actions.GoToEditPointAction$Backward"
text="Previous Emmet Edit Point" description="Go to previous Emmet edit point">
<keyboard-shortcut first-keystroke="alt shift CLOSE_BRACKET" keymap="$default"/>
<keyboard-shortcut first-keystroke="alt shift OPEN_BRACKET" keymap="$default"/>
<keyboard-shortcut first-keystroke="control alt LEFT" keymap="Mac OS X 10.5+" replace-all="true"/>
</action>
</group>
@@ -114,7 +114,7 @@ jdk.combo.box.project.item=<No Project SDK>
jdk.combo.box.none.item=<None>
jdk.combo.box.invalid.item={0} [Invalid]
module.libraries.target.jdk.project.radio=<html><b>&Project SDK:</b><br>This SDK is default for all project modules.<br>\
A module specific SDK can be configured for each of the modules as required</html>
A module specific SDK can be configured for each of the modules as required.</html>
module.libraries.target.jdk.module.radio=&Module SDK:
module.libraries.target.jdk.select.title=Select Project SDK
module.libraries.javadoc.url.button=Specify Documentation &URL...
@@ -263,11 +263,11 @@ project.inherit.compile.output.path=Inherit project compile output path
project.module.compile.output.path=Use module compile output path
project.compiler.output=<html><b>Project compiler output:</b><br>This path is used to store all project compilation results. <br>\
A directory corresponding to each module is created under this path. <br>This directory contains two subdirectories: Production and Test for production code and test sources, respectively.<br>\
A module specific compiler output path can be configured for each of the modules as required</html>
A module specific compiler output path can be configured for each of the modules as required.</html>
find.usages.action.text=Find Usages
dependencies.used.in.popup.title=Used in
project.language.level=<html><b>Project language level:</b><br>This language level is default for all project modules.<br>\
A module specific language level can be configured for each of the modules as required</html>
A module specific language level can be configured for each of the modules as required.</html>
classpath.panel.analyze=Analyze
classpath.panel.navigate.action.text=Navigate
output.tab.title=Output
@@ -1701,14 +1701,23 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
descriptors.addAll(intentions.inspectionFixesToShow);
descriptors.addAll(intentions.guttersToShow);
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
final int fileOffset = editor.getCaretModel().getOffset();
PsiElement hostElement = file.getViewProvider().findElementAt(fileOffset, file.getLanguage());
PsiElement injectedElement = InjectedLanguageUtil.findElementAtNoCommit(file, fileOffset);
PsiFile injectedFile = injectedElement != null ? injectedElement.getContainingFile() : null;
Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
List<IntentionAction> result = new ArrayList<IntentionAction>();
List<HighlightInfo> infos = DaemonCodeAnalyzerEx.getInstanceEx(file.getProject()).getFileLevelHighlights(file.getProject(), file);
for (HighlightInfo info : infos) {
for (Pair<HighlightInfo.IntentionActionDescriptor, TextRange> pair : info.quickFixActionRanges) {
HighlightInfo.IntentionActionDescriptor actionInGroup = pair.first;
if (actionInGroup.getAction().isAvailable(file.getProject(), editor, file)) {
final IntentionAction action = actionInGroup.getAction();
if (ShowIntentionActionsHandler.availableFor(file, editor, action)
|| (injectedElement != null && hostElement != injectedElement && ShowIntentionActionsHandler.availableFor(injectedFile, injectedEditor, action))) {
descriptors.add(actionInGroup);
}
}
@@ -1717,11 +1726,25 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
// add all intention options for simplicity
for (HighlightInfo.IntentionActionDescriptor descriptor : descriptors) {
result.add(descriptor.getAction());
List<IntentionAction> options = descriptor.getOptions(element,editor);
if (options != null) {
for (IntentionAction option : options) {
if (option.isAvailable(file.getProject(), editor, file)) {
result.add(option);
if (injectedElement != null && injectedElement != hostElement) {
List<IntentionAction> options = descriptor.getOptions(injectedElement, injectedEditor);
if (options != null) {
for (IntentionAction option : options) {
if (ShowIntentionActionsHandler.availableFor(injectedFile, injectedEditor, option)) {
result.add(option);
}
}
}
}
if (hostElement != null) {
List<IntentionAction> options = descriptor.getOptions(hostElement, editor);
if (options != null) {
for (IntentionAction option : options) {
if (ShowIntentionActionsHandler.availableFor(file, editor, option)) {
result.add(option);
}
}
}
}
@@ -219,6 +219,8 @@ public class RemoteUtil {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
if ("equals".equals(method.getName())) return proxy == args[0];
if ("hashCode".equals(method.getName())) return hashCode();
return method.invoke(myRemote, args);
}
else {
@@ -47,7 +47,7 @@ public class JiraIntegrationTest extends TaskManagerTestCase {
/**
* JIRA 4.4.5, REST API 2.0.alpha1
*/
@NonNls private static final String JIRA_4_TEST_SERVER_URL = "http://trackers-tests.labs.intellij.net:8014";
@NonNls private static final String JIRA_4_TEST_SERVER_URL = "http://idea-qa-task-2.labs.intellij.net:8014";
/**
* JIRA 5.0.6, REST API 2.0
*/
@@ -17,59 +17,74 @@ package com.intellij.codeInsight.template.emmet.actions;
import com.intellij.lang.Language;
import com.intellij.lang.xml.XMLLanguage;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlText;
import com.intellij.psi.xml.XmlTokenType;
import com.intellij.util.ObjectUtils;
/**
* @author Dennis.Ushakov
*/
public class EmmetEditPointUtil {
public static void moveForward(Editor editor, PsiFile file) {
public static void moveForward(final Editor editor, final PsiFile file) {
if (!isApplicableFile(file)) return;
moveToNextPoint(editor, file, editor.getCaretModel().getOffset(), 1);
}
public static void moveBackward(Editor editor, PsiFile file) {
public static void moveBackward(final Editor editor, final PsiFile file) {
if (!isApplicableFile(file)) return;
moveToNextPoint(editor, file, editor.getCaretModel().getOffset(), -1);
}
private static void moveToNextPoint(Editor editor, PsiFile file, int offset, int inc) {
final Document doc = editor.getDocument();
final TemplateLanguageFileViewProvider provider = ObjectUtils.tryCast(file.getViewProvider(), TemplateLanguageFileViewProvider.class);
final Language additionalLanguage = provider != null ? provider.getTemplateDataLanguage() : null;
PsiDocumentManager.getInstance(file.getProject()).commitDocument(doc);
for (int i = offset + inc; i < doc.getTextLength() && i >= 0; i += inc) {
PsiElement current = InjectedLanguageUtil.findElementAtNoCommit(file, i);
if (current == null) continue;
if (current.getParent() instanceof XmlText) {
final int line = doc.getLineNumber(i);
final int lineStart = doc.getLineStartOffset(line);
final int lineEnd = doc.getLineEndOffset(line);
if (lineEnd == offset) continue;
final CharSequence text = doc.getCharsSequence().subSequence(lineStart, lineEnd);
if (StringUtil.isEmptyOrSpaces(text) && moveCaret(editor, current, lineEnd)) {
return;
}
} else if (isEmptyEditPoint(current) && moveCaret(editor, current, current.getTextRange().getStartOffset())) {
return;
if (checkAndMove(editor, doc, i, current)) return;
if (additionalLanguage != null) {
current = provider.findElementAt(i, additionalLanguage);
if (checkAndMove(editor, doc, i, current)) return;
}
}
}
private static boolean checkAndMove(Editor editor, Document doc, int offset, PsiElement current) {
if (current == null) return false;
if (current.getParent() instanceof XmlText) {
final int line = doc.getLineNumber(offset);
final int lineStart = doc.getLineStartOffset(line);
final int lineEnd = doc.getLineEndOffset(line);
final CharSequence text = doc.getCharsSequence().subSequence(lineStart, lineEnd);
if (StringUtil.isEmptyOrSpaces(text) && moveCaret(editor, current, lineEnd)) {
return true;
}
} else if (isEmptyEditPoint(current) && moveCaret(editor, current, current.getTextRange().getStartOffset())) {
return true;
}
return false;
}
private static boolean moveCaret(Editor editor, PsiElement current, int offset) {
editor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, current.getContainingFile());
if (editor.getCaretModel().getOffset() == offset) return false;
editor.getCaretModel().moveToOffset(offset);
final CaretModel caretModel = editor.getCaretModel();
if (caretModel.getOffset() == offset) return false;
caretModel.moveToOffset(offset);
final Caret caret = caretModel.getCurrentCaret();
ScrollingModel scrollingModel = editor.getScrollingModel();
if (caret == caretModel.getPrimaryCaret()) {
scrollingModel.scrollToCaret(ScrollType.RELATIVE);
}
return true;
}
@@ -89,7 +104,7 @@ public class EmmetEditPointUtil {
static boolean isApplicableFile(PsiFile file) {
if (file == null) return false;
for (Language language : file.getViewProvider().getLanguages()) {
if (language.isKindOf(XMLLanguage.INSTANCE)) return true;
if (language.isKindOf(XMLLanguage.INSTANCE) || "JavaScript".equals(language.getID())) return true;
}
return false;
}
@@ -15,45 +15,57 @@
*/
package com.intellij.codeInsight.template.emmet.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
import com.intellij.openapi.project.DumbAware;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import org.jetbrains.annotations.Nullable;
/**
* @author Dennis.Ushakov
*/
public abstract class GoToEditPointAction extends DumbAwareAction {
public abstract class GoToEditPointAction extends EditorAction implements DumbAware {
protected GoToEditPointAction(EditorActionHandler defaultHandler) {
super(defaultHandler);
}
@Override
public void update(AnActionEvent e) {
final Editor editor = getEditor(e);
final PsiFile file = getFile(e);
final boolean isApplicable = editor != null && EmmetEditPointUtil.isApplicableFile(file);
e.getPresentation().setEnabledAndVisible(isApplicable);
public void update(Editor editor, Presentation presentation, DataContext dataContext) {
super.update(editor, presentation, dataContext);
final PsiFile file = getFile(dataContext);
if (!EmmetEditPointUtil.isApplicableFile(file)) {
presentation.setEnabledAndVisible(false);
}
}
private static PsiFile getFile(AnActionEvent e) {
return CommonDataKeys.PSI_FILE.getData(e.getDataContext());
}
private static Editor getEditor(AnActionEvent e) {
final Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
return editor != null ? InjectedLanguageUtil.getTopLevelEditor(editor) : null;
private static PsiFile getFile(DataContext context) {
return CommonDataKeys.PSI_FILE.getData(context);
}
public static class Forward extends GoToEditPointAction {
@Override
public void actionPerformed(AnActionEvent e) {
EmmetEditPointUtil.moveForward(getEditor(e), getFile(e));
public Forward() {
super(new EditorActionHandler(true) {
@Override
protected void doExecute(Editor editor, @Nullable Caret caret, DataContext dataContext) {
EmmetEditPointUtil.moveForward(editor, getFile(dataContext));
}
});
}
}
public static class Backward extends GoToEditPointAction {
@Override
public void actionPerformed(AnActionEvent e) {
EmmetEditPointUtil.moveBackward(getEditor(e), getFile(e));
public Backward() {
super(new EditorActionHandler(true) {
@Override
protected void doExecute(Editor editor, @Nullable Caret caret, DataContext dataContext) {
EmmetEditPointUtil.moveBackward(editor, getFile(dataContext));
}
});
}
}
}