/*
* Copyright (C) 2013 The Android Open Source Project
*
* 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.android.tools.idea.editors.navigation;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.io.File;
public class Utilities {
public static final Dimension ZERO_SIZE = new Dimension(0, 0);
public static Point add(Point p1, Point p2) {
return new Point(p1.x + p2.x, p1.y + p2.y);
}
public static Point diff(Point p1, Point p2) {
return new Point(p1.x - p2.x, p1.y - p2.y);
}
public static double length(Point p) {
return Math.sqrt(p.x * p.x + p.y * p.y);
}
public static Point max(Point p1, Point p2) {
return new Point(Math.max(p1.x, p2.x), Math.max(p1.y, p2.y));
}
public static Point scale(Point p, float k) {
return new Point((int)(k * p.x), (int)(k * p.y));
}
public static Dimension scale(Dimension d, float k) {
return new Dimension((int)(k * d.width), (int)(k * d.height));
}
private static int snap(int i, int d) {
return ((int)Math.round((double)i / d)) * d;
}
public static Point snap(Point p, Dimension gridSize) {
return new Point(snap(p.x, gridSize.width), snap(p.y, gridSize.height));
}
public static Point midPoint(Point p1, Point p2) {
return scale(add(p1, p2), 0.5f);
}
public static Point midPoint(Dimension size) {
return point(scale(size, 0.5f));
}
public static Point point(Dimension d) {
return new Point(d.width, d.height);
}
public static Dimension dimension(Point p) {
return new Dimension(Math.abs(p.x), Math.abs(p.y));
}
public static Point project(Point p, Rectangle r) {
Point centre = centre(r);
Point diff = diff(p, centre);
boolean horizontal = Math.abs((float)diff.y / diff.x) < Math.abs((float)r.height / r.width);
float scale = horizontal ? (float)r.width / 2 / diff.x : (float)r.height / 2 / diff.y;
return add(centre, scale(diff, Math.abs(scale)));
}
public static Point centre(@NotNull Rectangle r) {
return new Point(r.x + r.width / 2, r.y + r.height / 2);
}
/**
* Translates a Java file name to a XML file name according
* to Android naming convention.
* <p/>
* Doesn't append .xml extension
*
* @return XML file name associated with Java file name
*/
public static String getXmlFileNameFromJavaFileName(String javaFileName) {
if (javaFileName.endsWith(".java")) {
// cut off ".java"
javaFileName = javaFileName.substring(0, javaFileName.length() - 5);
}
char[] charsJava = javaFileName.toCharArray();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < charsJava.length; i++) {
char currentChar = charsJava[i];
if (Character.isUpperCase(currentChar) && i != 0) {
stringBuilder.append('_');
}
stringBuilder.append(Character.toLowerCase(currentChar));
}
return stringBuilder.toString();
}
/**
* Translates a XML file name to a Java file name according
* to Android naming convention.
* <p/>
* Doesn't append .java extension
*
* @return Java file name associated with XML file name
*/
@SuppressWarnings("AssignmentToForLoopParameter")
public static String getJavaFileNameFromXmlFileName(String xmlFileName) {
if (xmlFileName.endsWith(".xml")) {
// cut off ".xm"
xmlFileName = xmlFileName.substring(0, xmlFileName.length() - 4);
}
char[] charsXml = xmlFileName.toCharArray();
StringBuilder stringBuilder = new StringBuilder();
// make the first char upper case
stringBuilder.append(Character.toUpperCase(charsXml[0]));
// start looking for '_' at the second char
for (int i = 1; i < charsXml.length; i++) {
char currentChar = charsXml[i];
if (currentChar == '_') {
// skip '_' and add the next char as upper case
char toAppend = Character.toUpperCase(charsXml[++i]);
stringBuilder.append(toAppend);
}
else {
stringBuilder.append(currentChar);
}
}
return stringBuilder.toString();
}
static void drawArrow(Graphics g1, int x1, int y1, int x2, int y2, int lineWidth) {
// x1 and y1 are coordinates of circle or rectangle
// x2 and y2 are coordinates of circle or rectangle, to this point is directed the arrow
Graphics2D g = (Graphics2D)g1.create();
double dx = x2 - x1;
double dy = y2 - y1;
double angle = Math.atan2(dy, dx);
int len = (int)Math.sqrt(dx * dx + dy * dy);
AffineTransform t = AffineTransform.getTranslateInstance(x1, y1);
t.concatenate(AffineTransform.getRotateInstance(angle));
g.transform(t);
g.drawLine(0, 0, len, 0);
Dimension arrowHeadSize = new Dimension(lineWidth * 6, lineWidth * 3);
int basePosition = len - arrowHeadSize.width;
int height = arrowHeadSize.height;
g.fillPolygon(new int[]{len, basePosition, basePosition, len}, new int[]{0, -height, height, 0}, 4);
}
static <T> Condition<T> not(final Condition<T> condition) {
return new Condition<T>() {
@Override
public boolean value(T t) {
return !condition.value(t);
}
};
}
static <T> Condition<T> instanceOf(final Class<?> type) {
return new Condition<T>() {
@Override
public boolean value(Object o) {
return type.isAssignableFrom(o.getClass());
}
};
}
static int sign(int x) {
return x > 0 ? 1 : x < 0 ? -1 : 0;
}
static Dimension notNull(@Nullable Dimension d) {
return d == null ? ZERO_SIZE : d;
}
@Nullable
public static PsiClass getPsiClass(Module module, String className) {
JavaPsiFacade facade = JavaPsiFacade.getInstance(module.getProject());
GlobalSearchScope scope = module.getModuleWithDependenciesAndLibrariesScope(false);
return facade.findClass(className, scope);
}
@Nullable
public static PsiMethod findMethodBySignature(Module module, String className, String signature) {
PsiClass psiClass = getPsiClass(module, className);
return psiClass == null ? null : findMethodBySignature(psiClass, signature);
}
@Nullable
public static PsiMethod findMethodBySignature(@NotNull PsiClass psiClass, @NotNull String signature) {
PsiMethod template = createMethodFromText(psiClass, signature);
return psiClass.findMethodBySignature(template, false);
}
public static PsiMethod createMethodFromText(PsiClass psiClass, String text) {
return createMethodFromText(psiClass.getProject(), text, psiClass);
}
public static PsiMethod createMethodFromText(Project project, String text, @Nullable PsiElement context) {
return JavaPsiFacade.getInstance(project).getElementFactory().createMethodFromText(text, context);
}
public static PsiMethod createMethodFromText(Project project, String text) {
return createMethodFromText(project, text, null);
}
@Nullable
public static VirtualFile virtualFile(File file) {
return LocalFileSystem.getInstance().findFileByIoFile(file);
}
}