IDEA-62531 "Choose color" intention (Java): allow to convert between decimal and hex colour representation implemented

This commit is contained in:
Danila Ponomarenko
2012-06-26 19:53:55 +04:00
parent 16d1250f9c
commit 6d8a78c66d
18 changed files with 560 additions and 65 deletions
@@ -0,0 +1,80 @@
/*
* Copyright 2000-2012 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.intention.impl;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.patterns.PlatformPatterns.psiElement;
/**
* @author Danila Ponomarenko
*/
public abstract class BaseColorIntentionAction extends PsiElementBaseIntentionAction implements HighPriorityAction {
protected static final String JAVA_AWT_COLOR = "java.awt.Color";
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
if (!psiElement().inside(psiElement(PsiNewExpression.class)).accepts(element)) {
return false;
}
final PsiNewExpression expression = PsiTreeUtil.getParentOfType(element, PsiNewExpression.class, false);
if (expression == null) {
return false;
}
return isJavaAwtColor(expression.getClassOrAnonymousClassReference()) && isValueArguments(expression.getArgumentList());
}
private static boolean isJavaAwtColor(@Nullable PsiJavaCodeReferenceElement ref) {
if (ref == null) {
return false;
}
final PsiReference reference = ref.getReference();
if (reference == null) {
return false;
}
final PsiElement psiElement = reference.resolve();
if (psiElement instanceof PsiClass && JAVA_AWT_COLOR.equals(((PsiClass)psiElement).getQualifiedName())) {
return true;
}
return false;
}
private static boolean isValueArguments(@Nullable PsiExpressionList arguments) {
if (arguments == null) {
return false;
}
for (PsiExpression argument : arguments.getExpressions()) {
if (argument instanceof PsiReferenceExpression) {
return false;
}
}
return true;
}
}
@@ -46,9 +46,7 @@ import static com.intellij.patterns.PlatformPatterns.psiElement;
* @author spleaner
* @author Konstantin Bulenkov
*/
public class ColorChooserIntentionAction extends PsiElementBaseIntentionAction {
private static final String JAVA_AWT_COLOR = "java.awt.Color";
public class ColorChooserIntentionAction extends BaseColorIntentionAction {
private static final PsiMethodPattern DECODE_METHOD = PsiJavaPatterns.psiMethod()
.definedInClass(JAVA_AWT_COLOR)
.withName("decode");
@@ -64,20 +62,7 @@ public class ColorChooserIntentionAction extends PsiElementBaseIntentionAction {
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) {
// new Color(...)
if (psiElement().inside(psiElement(PsiNewExpression.class)).accepts(element)) {
final PsiNewExpression expression = PsiTreeUtil.getParentOfType(element, PsiNewExpression.class, false);
if (expression != null) {
final PsiJavaCodeReferenceElement ref = PsiTreeUtil.getChildOfType(expression, PsiJavaCodeReferenceElement.class);
if (isJavaAwtColor(ref)) return true;
}
}
// Color.decode("...")
if (isInsideDecodeOrGetColorMethod(element)) {
return true;
}
return false;
return super.isAvailable(project, editor, element) || isInsideDecodeOrGetColorMethod(element);
}
public static boolean isInsideDecodeOrGetColorMethod(PsiElement element) {
@@ -85,24 +70,10 @@ public class ColorChooserIntentionAction extends PsiElementBaseIntentionAction {
element = element.getParent();
}
return PsiJavaPatterns.psiExpression().methodCallParameter(0, DECODE_METHOD).accepts(element)
||
return PsiJavaPatterns.psiExpression().methodCallParameter(0, DECODE_METHOD).accepts(element) ||
PsiJavaPatterns.psiExpression().methodCallParameter(0, GET_COLOR_METHOD).accepts(element);
}
private static boolean isJavaAwtColor(final PsiJavaCodeReferenceElement ref) {
if (ref != null) {
final PsiReference reference = ref.getReference();
if (reference != null) {
final PsiElement psiElement = reference.resolve();
if (psiElement instanceof PsiClass && JAVA_AWT_COLOR.equals(((PsiClass)psiElement).getQualifiedName())) {
return true;
}
}
}
return false;
}
@Override
@NotNull
public String getFamilyName() {
@@ -116,7 +87,8 @@ public class ColorChooserIntentionAction extends PsiElementBaseIntentionAction {
final JComponent editorComponent = editor.getComponent();
if (isInsideDecodeOrGetColorMethod(element)) {
invokeForMethodParam(editorComponent, element);
} else {
}
else {
invokeForConstructor(editorComponent, element);
}
}
@@ -139,9 +111,9 @@ public class ColorChooserIntentionAction extends PsiElementBaseIntentionAction {
if (color == null) return;
final int rgb = color.getRGB() - ((255 & 0xFF) << 24);
if (color != null && rgb != oldColor.getRGB()) {
final String newText = radix == 16 ? hexPrefix + String.format("%6s" ,Integer.toHexString(rgb)).replace(' ', '0')
: radix == 8 ? "0" + Integer.toOctalString(rgb)
: Integer.toString(rgb);
final String newText = radix == 16 ? hexPrefix + String.format("%6s", Integer.toHexString(rgb)).replace(' ', '0')
: radix == 8 ? "0" + Integer.toOctalString(rgb)
: Integer.toString(rgb);
final PsiManager manager = literal.getManager();
final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
final PsiExpression newLiteral = factory.createExpressionFromText("\"" + newText + "\"", literal);
@@ -221,12 +193,12 @@ public class ColorChooserIntentionAction extends PsiElementBaseIntentionAction {
final PsiManager manager = expression.getManager();
final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
final PsiExpression newCall = factory.createExpressionFromText(
"new " + JAVA_AWT_COLOR +"("
+ color.getRed() + ", "
+ color.getGreen() + ", "
+ color.getBlue()
+ (color.getAlpha() < 255 ? ", " + color.getAlpha() : "")
+")", expression);
"new " + JAVA_AWT_COLOR + "("
+ color.getRed() + ", "
+ color.getGreen() + ", "
+ color.getBlue()
+ (color.getAlpha() < 255 ? ", " + color.getAlpha() : "")
+ ")", expression);
final PsiElement insertedElement = expression.replace(newCall);
final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject());
codeStyleManager.reformat(insertedElement);
@@ -0,0 +1,226 @@
/*
* Copyright 2000-2012 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.intention.impl;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Danila Ponomarenko
*/
public class ConvertColorRepresentationIntentionAction extends BaseColorIntentionAction {
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
if (!super.isAvailable(project, editor, element)) {
return false;
}
final PsiNewExpression expression = PsiTreeUtil.getParentOfType(element, PsiNewExpression.class, false);
if (expression == null) {
return false;
}
final PsiExpressionList arguments = expression.getArgumentList();
if (arguments == null) {
return false;
}
final PsiMethod constructor = expression.resolveConstructor();
if (constructor == null) {
return false;
}
final PsiExpressionList newArguments = createNewArguments(JavaPsiFacade.getElementFactory(project), constructor.getParameterList().getParameters(), arguments.getExpressions());
if (newArguments == null) {
return false;
}
setText(CodeInsightBundle.message("intention.convert.color.representation.text", newArguments.getText()));
return true;
}
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
if (!CodeInsightUtilBase.preparePsiElementForWrite(element)) return;
final PsiNewExpression expression = PsiTreeUtil.getParentOfType(element, PsiNewExpression.class, false);
if (expression == null) {
return;
}
final PsiExpressionList arguments = expression.getArgumentList();
if (arguments == null) {
return;
}
final PsiMethod constructor = expression.resolveConstructor();
if (constructor == null) {
return;
}
final PsiExpressionList newArguments = createNewArguments(
JavaPsiFacade.getElementFactory(project),
constructor.getParameterList().getParameters(),
arguments.getExpressions()
);
if (newArguments == null) {
return;
}
arguments.replace(newArguments);
}
@Nullable
private static PsiExpressionList createNewArguments(@NotNull PsiElementFactory factory,
@NotNull PsiParameter[] parameters,
@NotNull PsiExpression[] arguments) {
final String[] newValues = createArguments(parameters, arguments);
if (newValues == null) {
return null;
}
final PsiExpressionList result = ((PsiNewExpression)factory.createExpressionFromText("new Object()", parameters[0])).getArgumentList();
if (result == null) {
return null;
}
for (String value : newValues) {
result.add(factory.createExpressionFromText(value, parameters[0]));
}
return result;
}
@Nullable
private static String[] createArguments(@NotNull PsiParameter[] parameters,
@NotNull PsiExpression[] arguments) {
if (parameters.length != arguments.length) {
return null;
}
switch (parameters.length) {
default:
return null;
case 1:
return createArguments(arguments[0]);
case 2:
return createArguments(arguments[0], arguments[1]);
case 3:
return createArguments(arguments[0], arguments[1], arguments[2]);
case 4:
return createArguments(arguments[0], arguments[1], arguments[2], arguments[3]);
}
}
@Nullable
private static String[] createArguments(@NotNull PsiExpression rgbExpression) {
return createArguments(rgbExpression, 3);
}
@Nullable
private static String[] createArguments(@NotNull PsiExpression rgbExpression,
@NotNull PsiExpression hasAlphaExpression) {
final Boolean hasAlpha = computeBoolean(hasAlphaExpression);
if (hasAlpha == null) {
return null;
}
return hasAlpha ? createArguments(rgbExpression, 4) : createArguments(rgbExpression);
}
@Nullable
private static String[] createArguments(@NotNull PsiExpression rExpression,
@NotNull PsiExpression gExpression,
@NotNull PsiExpression bExpression) {
final Integer value = createInt(computeInteger(rExpression), computeInteger(gExpression), computeInteger(bExpression));
return value != null ? new String[]{"0x" + Integer.toHexString(value)} : null;
}
@Nullable
private static String[] createArguments(@NotNull PsiExpression rExpression,
@NotNull PsiExpression gExpression,
@NotNull PsiExpression bExpression,
@NotNull PsiExpression aExpression) {
final Integer value = createInt(computeInteger(rExpression), computeInteger(gExpression), computeInteger(bExpression), computeInteger(aExpression));
if (value == null) {
return null;
}
return new String[]{
"0x" + Integer.toHexString(value),
"true",
};
}
@Nullable
private static String[] createArguments(@NotNull PsiExpression rgbExpression,
int parts) {
final Integer rgb = computeInteger(rgbExpression);
if (rgb == null) {
return null;
}
final String[] result = new String[parts];
for (int i = 0; i < result.length; i++) {
result[result.length - i - 1] = String.valueOf(rgb >> (i * Byte.SIZE) & 0xFF);
}
return result;
}
@Nullable
private static Integer createInt(Integer... ints) {
int result = 0;
for (Integer i : ints) {
if (i == null) {
return null;
}
result = result << Byte.SIZE | (i & 0xFF);
}
return result;
}
@Nullable
public static Integer computeInteger(@NotNull PsiExpression expr) {
final Object result = compute(expr);
return result instanceof Integer ? (Integer)result : null;
}
@Nullable
public static Boolean computeBoolean(@NotNull PsiExpression expr) {
final Object result = compute(expr);
return result instanceof Boolean ? (Boolean)result : null;
}
@Nullable
private static Object compute(@NotNull PsiExpression expr) {
return JavaConstantExpressionEvaluator.computeConstantExpression(expr, true);
}
@NotNull
@Override
public String getFamilyName() {
return CodeInsightBundle.message("intention.convert.color.representation.family");
}
}