mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote branch 'origin/master'
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
package com.intellij.find.findUsages;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User: Andrey.Vokin
|
||||
* Date: 7/26/12
|
||||
*/
|
||||
public interface CustomJavaFindUsagesHandler {
|
||||
public void processElementUsages(@NotNull final PsiElement element, @NotNull final Processor<UsageInfo> processor, @NotNull final FindUsagesOptions options);
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.intellij.find.findUsages;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
|
||||
/**
|
||||
* User: Andrey.Vokin
|
||||
* Date: 7/26/12
|
||||
*/
|
||||
public abstract class CustomJavaFindUsagesHandlerProvider {
|
||||
public static final ExtensionPointName<CustomJavaFindUsagesHandlerProvider> EP_NAME = ExtensionPointName.create("com.intellij.findUsages.java.customJavaFindUsagesHandlerProvider");
|
||||
|
||||
public abstract CustomJavaFindUsagesHandler getHandler();
|
||||
}
|
||||
@@ -384,6 +384,11 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
|
||||
// todo add to fastTrack
|
||||
processUsagesInText(element, processor, (GlobalSearchScope)options.searchScope);
|
||||
}
|
||||
|
||||
final CustomJavaFindUsagesHandlerProvider[] customJavaFindUsagesHandlerProviders = Extensions.getExtensions(CustomJavaFindUsagesHandlerProvider.EP_NAME);
|
||||
for (CustomJavaFindUsagesHandlerProvider provider : customJavaFindUsagesHandlerProviders) {
|
||||
provider.getHandler().processElementUsages(element, processor, options);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addAliasingUsages(PomTarget pomTarget, final Processor<UsageInfo> processor, final FindUsagesOptions options) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import java.io.File;
|
||||
|
||||
public class Foo {
|
||||
void foo(boolean flag) {
|
||||
if ('\\' == File.separach<caret>)
|
||||
if ('\\' == File.separaCh<caret>)
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -45,10 +45,7 @@ public abstract class TemplateLanguageErrorFilter extends HighlightErrorFilter {
|
||||
if (!(viewProvider.getClass() == myTemplateFileViewProviderClass)) {
|
||||
return true;
|
||||
}
|
||||
final Language parentLanguage = element.getParent().getLanguage();
|
||||
final Language javaScript = Language.findLanguageByID("JavaScript");
|
||||
final Language css = Language.findLanguageByID("CSS");
|
||||
if (javaScript != null && parentLanguage.is(javaScript) || css != null && parentLanguage.is(css)) {
|
||||
if (isKnownSubLanguage(element.getParent().getLanguage())) {
|
||||
final PsiElement next = viewProvider.findElementAt(element.getTextOffset() + 1, viewProvider.getBaseLanguage());
|
||||
if (next != null && myTemplateExpressionStartTokens.contains(next.getNode().getElementType())) {
|
||||
return false;
|
||||
@@ -56,4 +53,10 @@ public abstract class TemplateLanguageErrorFilter extends HighlightErrorFilter {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isKnownSubLanguage(final @NotNull Language language) {
|
||||
final Language javaScript = Language.findLanguageByID("JavaScript");
|
||||
final Language css = Language.findLanguageByID("CSS");
|
||||
return javaScript != null && language.is(javaScript) || css != null && language.is(css);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -16,6 +16,7 @@
|
||||
package com.intellij.execution.runners;
|
||||
|
||||
import com.intellij.execution.console.LanguageConsoleImpl;
|
||||
import com.intellij.execution.process.BaseOSProcessHandler;
|
||||
import com.intellij.execution.process.ConsoleHistoryModel;
|
||||
import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.openapi.command.impl.UndoManagerImpl;
|
||||
@@ -28,6 +29,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* @author traff
|
||||
@@ -91,14 +93,14 @@ public class ConsoleExecuteActionHandler {
|
||||
}
|
||||
|
||||
public void sendText(String line) {
|
||||
//final Charset charset = myProcessHandler.getCharset();
|
||||
final Charset charset = myProcessHandler instanceof BaseOSProcessHandler ?
|
||||
((BaseOSProcessHandler)myProcessHandler).getCharset() : null;
|
||||
final ProcessHandler handler = getProcessHandler();
|
||||
assert handler != null : "process handler is null";
|
||||
final OutputStream outputStream = handler.getProcessInput();
|
||||
assert outputStream != null : "output stream is null";
|
||||
try {
|
||||
//byte[] bytes = (line + "\n").getBytes(charset.name());
|
||||
byte[] bytes = line.getBytes();
|
||||
byte[] bytes = charset != null ? (line + "\n").getBytes(charset) : line.getBytes();
|
||||
outputStream.write(bytes);
|
||||
outputStream.flush();
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.intellij.lang.PsiParser;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
@@ -38,7 +39,7 @@ public abstract class IndentationParser implements PsiParser {
|
||||
final PsiBuilder.Marker documentMarker = builder.mark();
|
||||
|
||||
final Stack<BlockInfo> stack = new Stack<BlockInfo>();
|
||||
stack.push(new BlockInfo(0, builder.mark()));
|
||||
stack.push(new BlockInfo(0, builder.mark(), builder.getTokenType()));
|
||||
|
||||
PsiBuilder.Marker startLineMarker = null;
|
||||
int currentIndent = 0;
|
||||
@@ -71,17 +72,19 @@ public abstract class IndentationParser implements PsiParser {
|
||||
}
|
||||
// Close indentation blocks
|
||||
while (!stack.isEmpty() && currentIndent < stack.peek().getIndent()) {
|
||||
closeBlock(builder, stack.pop().getMarker());
|
||||
final BlockInfo blockInfo = stack.pop();
|
||||
closeBlock(builder, blockInfo.getMarker(), blockInfo.getStartTokenType());
|
||||
}
|
||||
|
||||
if (!stack.isEmpty()) {
|
||||
final BlockInfo blockInfo = stack.peek();
|
||||
if (currentIndent >= blockInfo.getIndent()) {
|
||||
if (currentIndent == blockInfo.getIndent()) {
|
||||
closeBlock(builder, stack.pop().getMarker());
|
||||
final BlockInfo info = stack.pop();
|
||||
closeBlock(builder, info.getMarker(), info.getStartTokenType());
|
||||
}
|
||||
passEOLsAndIndents(builder);
|
||||
stack.push(new BlockInfo(currentIndent, builder.mark()));
|
||||
stack.push(new BlockInfo(currentIndent, builder.mark(), type));
|
||||
}
|
||||
}
|
||||
eolSeen = false;
|
||||
@@ -97,7 +100,8 @@ public abstract class IndentationParser implements PsiParser {
|
||||
startLineMarker.drop();
|
||||
}
|
||||
while (!stack.isEmpty()){
|
||||
closeBlock(builder, stack.pop().getMarker());
|
||||
final BlockInfo blockInfo = stack.pop();
|
||||
closeBlock(builder, blockInfo.getMarker(), blockInfo.getStartTokenType());
|
||||
}
|
||||
|
||||
documentMarker.done(myDocumentType);
|
||||
@@ -105,7 +109,10 @@ public abstract class IndentationParser implements PsiParser {
|
||||
return builder.getTreeBuilt();
|
||||
}
|
||||
|
||||
protected void closeBlock(@NotNull PsiBuilder builder, @NotNull PsiBuilder.Marker marker) {
|
||||
protected void closeBlock(final @NotNull PsiBuilder builder,
|
||||
final @NotNull PsiBuilder.Marker marker,
|
||||
final @Nullable IElementType startTokenType)
|
||||
{
|
||||
marker.done(myBlockElementType);
|
||||
}
|
||||
|
||||
@@ -125,10 +132,13 @@ public abstract class IndentationParser implements PsiParser {
|
||||
private final int myIndent;
|
||||
@NotNull
|
||||
private final PsiBuilder.Marker myMarker;
|
||||
@Nullable
|
||||
private final IElementType myStartTokenType;
|
||||
|
||||
private BlockInfo(final int indent, final @NotNull PsiBuilder.Marker marker) {
|
||||
this.myIndent = indent;
|
||||
this.myMarker = marker;
|
||||
private BlockInfo(final int indent, final @NotNull PsiBuilder.Marker marker, final @Nullable IElementType type) {
|
||||
myIndent = indent;
|
||||
myMarker = marker;
|
||||
myStartTokenType = type;
|
||||
}
|
||||
|
||||
public int getIndent() {
|
||||
@@ -139,5 +149,10 @@ public abstract class IndentationParser implements PsiParser {
|
||||
public PsiBuilder.Marker getMarker() {
|
||||
return myMarker;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public IElementType getStartTokenType() {
|
||||
return myStartTokenType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-12
@@ -35,7 +35,6 @@ public class ColoredProcessHandler extends OSProcessHandler {
|
||||
private static final String TEXT_ATTRS_PATTERN = "m" + TEXT_ATTRS_PREFIX_CH + "\\[";
|
||||
|
||||
private Key myCurrentColor;
|
||||
@Nullable private final Charset myCharset;
|
||||
|
||||
public static TextAttributes getByKey(final TextAttributesKey key){
|
||||
return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(key);
|
||||
@@ -56,17 +55,7 @@ public class ColoredProcessHandler extends OSProcessHandler {
|
||||
public ColoredProcessHandler(final Process process,
|
||||
final String commandLine,
|
||||
@Nullable final Charset charset) {
|
||||
super(process, commandLine);
|
||||
myCharset = charset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Charset getCharset() {
|
||||
if (myCharset != null) {
|
||||
return myCharset;
|
||||
}
|
||||
// Charset wasn't specified - use default one
|
||||
return super.getCharset();
|
||||
super(process, commandLine, charset);
|
||||
}
|
||||
|
||||
public final void notifyTextAvailable(final String text, final Key outputType) {
|
||||
|
||||
+54
-11
@@ -35,10 +35,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.*;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
||||
@@ -101,6 +98,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
|
||||
private boolean myForcePressed = false;
|
||||
private PropertyChangeListener myButtonSynchronizer;
|
||||
private boolean myMouseInside = false;
|
||||
private JBPopup myPopup;
|
||||
|
||||
public ComboBoxButton(Presentation presentation) {
|
||||
myPresentation = presentation;
|
||||
@@ -143,7 +141,56 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
|
||||
myMouseInside = false;
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(final MouseEvent e) {
|
||||
if (SwingUtilities.isLeftMouseButton(e)) {
|
||||
e.consume();
|
||||
doClick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
dispatchEventToPopup(e);
|
||||
}
|
||||
});
|
||||
addMouseMotionListener(new MouseMotionListener() {
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
mouseMoved(new MouseEvent(e.getComponent(),
|
||||
MouseEvent.MOUSE_MOVED,
|
||||
e.getWhen(),
|
||||
e.getModifiers(),
|
||||
e.getX(),
|
||||
e.getY(),
|
||||
e.getClickCount(),
|
||||
e.isPopupTrigger(),
|
||||
e.getButton()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
dispatchEventToPopup(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Event forwarding. We need it if user does press-and-drag gesture for opening popup and choosing item there.
|
||||
// It works in JComboBox, here we provide the same behavior
|
||||
private void dispatchEventToPopup(MouseEvent e) {
|
||||
if (myPopup != null && myPopup.isVisible()) {
|
||||
JComponent content = myPopup.getContent();
|
||||
Rectangle rectangle = content.getBounds();
|
||||
Point location = rectangle.getLocation();
|
||||
SwingUtilities.convertPointToScreen(location, content);
|
||||
Point eventPoint = e.getLocationOnScreen();
|
||||
rectangle.setLocation(location);
|
||||
if (rectangle.contains(eventPoint)) {
|
||||
MouseEvent event = SwingUtilities.convertMouseEvent(e.getComponent(), e, myPopup.getContent());
|
||||
Component component = SwingUtilities.getDeepestComponentAt(content, event.getX(), event.getY());
|
||||
component.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void showPopup() {
|
||||
@@ -156,15 +203,15 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
public void run() {
|
||||
myForcePressed = false;
|
||||
myPopup = null;
|
||||
}
|
||||
});
|
||||
repaint();
|
||||
}
|
||||
};
|
||||
|
||||
JBPopup popup = createPopup(onDispose);
|
||||
|
||||
popup.show(new RelativePoint(this, new Point(0, this.getHeight() - 1)));
|
||||
myPopup = createPopup(onDispose);
|
||||
myPopup.show(new RelativePoint(this, new Point(0, this.getHeight() - 1)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -372,10 +419,6 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
|
||||
g.setPaintMode();
|
||||
}
|
||||
|
||||
private boolean isGlowSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void updateButtonSize() {
|
||||
invalidate();
|
||||
repaint();
|
||||
|
||||
@@ -96,7 +96,7 @@ public class Tree extends JTree implements ComponentWithEmptyText, ComponentWith
|
||||
public void setUI(final TreeUI ui) {
|
||||
TreeUI actualUI = ui;
|
||||
if (!isCustomUI()) {
|
||||
if (!(ui instanceof WideSelectionTreeUI) && isWideSelection()) {
|
||||
if (!(ui instanceof WideSelectionTreeUI) && isWideSelection() && !UIUtil.isUnderGTKLookAndFeel()) {
|
||||
actualUI = new WideSelectionTreeUI(isWideSelection(), !SystemInfo.isMac);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,7 +487,9 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo
|
||||
uiDefaults.put("TextField.selectionBackground", bg);
|
||||
uiDefaults.put("RadioButtonMenuItem.selectionBackground", bg);
|
||||
uiDefaults.put("CheckBoxMenuItem.selectionBackground", bg);
|
||||
} if (UIUtil.isUnderMetalLookAndFeel()) {
|
||||
}
|
||||
|
||||
if (UIUtil.isUnderMetalLookAndFeel()) {
|
||||
uiDefaults.put("Tree.hash", new ColorUIResource(117, 117, 117));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,6 +226,12 @@ public class NameUtilTest extends UsefulTestCase {
|
||||
assertMatches("text*:sh", "textField:shouldChangeCharactersInRange:replacementString:");
|
||||
}
|
||||
|
||||
public void testFileStructure() {
|
||||
assertMatches("hint", "height:int");
|
||||
assertDoesntMatch("Hint", "Height:int");
|
||||
assertMatches("getColor", "getBackground():Color");
|
||||
}
|
||||
|
||||
public void testMiddleMatchingMinimumTwoConsecutiveLettersInWordMiddle() {
|
||||
assertMatches("*fo", "reformat");
|
||||
assertMatches("*f", "reFormat");
|
||||
@@ -254,7 +260,7 @@ public class NameUtilTest extends UsefulTestCase {
|
||||
assertMatches("*Git", "BlaGitBla");
|
||||
assertFalse(firstLetterMatcher("*Git").matches("BlagitBla"));
|
||||
assertMatches("*git", "BlagitBla");
|
||||
assertMatches("*Git*", "AtpGenerationItem");
|
||||
assertDoesntMatch("*Git*", "AtpGenerationItem");
|
||||
assertMatches("Collec*Util*", "CollectionUtils");
|
||||
assertMatches("Collec*Util*", "CollectionUtilsTest");
|
||||
assertTrue(caseInsensitiveMatcher("*us").matches("usage"));
|
||||
@@ -307,7 +313,7 @@ public class NameUtilTest extends UsefulTestCase {
|
||||
assertMatches("foo", "fxOo");
|
||||
assertMatches("foo", "fXOo");
|
||||
assertMatches("fOo", "foo");
|
||||
assertMatches("fOo", "FaOaOaXXXX");
|
||||
assertDoesntMatch("fOo", "FaOaOaXXXX");
|
||||
assertMatches("ncdfoe", "NoClassDefFoundException");
|
||||
assertMatches("fob", "FOO_BAR");
|
||||
assertMatches("fo_b", "FOO_BAR");
|
||||
@@ -330,7 +336,7 @@ public class NameUtilTest extends UsefulTestCase {
|
||||
|
||||
public void testFinalSpace() {
|
||||
assertMatches("GrDebT ", "GroovyDebuggerTest");
|
||||
assertMatches("grdebT ", "GroovyDebuggerTest");
|
||||
assertDoesntMatch("grdebT ", "GroovyDebuggerTest");
|
||||
assertDoesntMatch("grdebt ", "GroovyDebuggerTest");
|
||||
assertMatches("Foo ", "Foo");
|
||||
assertDoesntMatch("Foo ", "FooBar");
|
||||
@@ -441,6 +447,7 @@ public class NameUtilTest extends UsefulTestCase {
|
||||
assertPreference("*ap", "add_profile", "application", NameUtil.MatchingCaseSensitivity.NONE);
|
||||
assertPreference("*les", "configureByFiles", "getLookupElementStrings", NameUtil.MatchingCaseSensitivity.FIRST_LETTER);
|
||||
assertPreference("*les", "configureByFiles", "getLookupElementStrings", NameUtil.MatchingCaseSensitivity.NONE);
|
||||
assertPreference("*ea", "LEADING", "NORTH_EAST", NameUtil.MatchingCaseSensitivity.NONE);
|
||||
}
|
||||
|
||||
public void testPreferEarlyMatching() {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.intellij.testFramework;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture;
|
||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
@@ -14,12 +12,6 @@ import org.jetbrains.annotations.NonNls;
|
||||
public class CodeInsightTestCase extends LightPlatformCodeInsightFixtureTestCase {
|
||||
@NonNls protected static final String CARET_STR = "<caret>";
|
||||
|
||||
protected CodeInsightTestFixture myFixture;
|
||||
|
||||
protected Project getProject() {
|
||||
return myFixture.getProject();
|
||||
}
|
||||
|
||||
protected int findOffsetBySignature(String signature) {
|
||||
return findOffsetBySignature(signature, myFixture.getFile());
|
||||
}
|
||||
|
||||
@@ -33,10 +33,19 @@ import static com.intellij.psi.codeStyle.NameUtil.MatchingCaseSensitivity.*;
|
||||
public class MinusculeMatcher implements Matcher {
|
||||
private final char[] myPattern;
|
||||
private final NameUtil.MatchingCaseSensitivity myOptions;
|
||||
private final boolean myHasHumps;
|
||||
|
||||
public MinusculeMatcher(String pattern, NameUtil.MatchingCaseSensitivity options) {
|
||||
myOptions = options;
|
||||
myPattern = StringUtil.trimEnd(pattern, "* ").toCharArray();
|
||||
for (int i = 0; i < myPattern.length; i++) {
|
||||
char c = myPattern[i];
|
||||
if (Character.isUpperCase(c)) {
|
||||
myHasHumps = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
myHasHumps = false;
|
||||
}
|
||||
|
||||
private static FList<TextRange> prependRange(FList<TextRange> ranges, int from, int length) {
|
||||
@@ -92,9 +101,9 @@ public class MinusculeMatcher implements Matcher {
|
||||
|
||||
int startIndex = first.getStartOffset();
|
||||
boolean prefixMatching = isStartMatch(name, startIndex);
|
||||
boolean middleWordStart = !prefixMatching && NameUtil.isWordStart(name, first.getStartOffset());
|
||||
boolean middleWordStart = !prefixMatching && startIndex > 0 && NameUtil.isWordStart(name, startIndex) && !NameUtil.isWordStart(name, startIndex - 1);
|
||||
|
||||
return -fragmentCount + matchingCase * 20 + commonStart * 30 - startIndex + (prefixMatching ? 2 : middleWordStart ? 1 : 0) * 100 - integral;
|
||||
return -fragmentCount + matchingCase * 20 + commonStart * 30 - startIndex + (prefixMatching ? 2 : middleWordStart ? 1 : 0) * 1000 - integral;
|
||||
}
|
||||
|
||||
public boolean isStartMatch(String name) {
|
||||
@@ -159,7 +168,7 @@ public class MinusculeMatcher implements Matcher {
|
||||
|
||||
char p = myPattern[patternIndex];
|
||||
while (true) {
|
||||
nameIndex = space ? indexOfWordStart(name, p, nameIndex) : StringUtil.indexOfIgnoreCase(name, p, nameIndex + 1);
|
||||
nameIndex = space ? indexOfWordStart(name, patternIndex, nameIndex) : StringUtil.indexOfIgnoreCase(name, p, nameIndex + 1);
|
||||
if (nameIndex < 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -188,7 +197,7 @@ public class MinusculeMatcher implements Matcher {
|
||||
return null;
|
||||
}
|
||||
if (myPattern[patternIndex + i] != name.charAt(nameIndex + i)) {
|
||||
int nextWordStart = indexOfWordStart(name, myPattern[patternIndex + i], nameIndex + i);
|
||||
int nextWordStart = indexOfWordStart(name, patternIndex + i, nameIndex + i);
|
||||
FList<TextRange> ranges = matchWildcards(name, patternIndex + i, nextWordStart);
|
||||
if (ranges != null) {
|
||||
return prependRange(ranges, nameIndex, i);
|
||||
@@ -202,7 +211,7 @@ public class MinusculeMatcher implements Matcher {
|
||||
return i >= minFragment ? FList.<TextRange>emptyList().prepend(TextRange.from(nameIndex, i)) : null;
|
||||
}
|
||||
while (i >= minFragment) {
|
||||
int nextWordStart = isWildcard(patternIndex + i) ? nameIndex + i : indexOfWordStart(name, myPattern[patternIndex + i], nameIndex + i);
|
||||
int nextWordStart = isWildcard(patternIndex + i) ? nameIndex + i : indexOfWordStart(name, patternIndex + i, nameIndex + i);
|
||||
FList<TextRange> ranges = matchWildcards(name, patternIndex + i, nextWordStart);
|
||||
if (ranges != null) {
|
||||
return prependRange(ranges, nameIndex, i);
|
||||
@@ -225,11 +234,13 @@ public class MinusculeMatcher implements Matcher {
|
||||
return myPattern[patternIndex] == c;
|
||||
}
|
||||
|
||||
private static int indexOfWordStart(String name, char p, int startFrom) {
|
||||
private int indexOfWordStart(String name, int patternIndex, int startFrom) {
|
||||
char p = myPattern[patternIndex];
|
||||
if (p == '.' || NameUtil.isWordSeparator(p)) {
|
||||
return StringUtil.indexOfIgnoreCase(name, p, startFrom + 1);
|
||||
}
|
||||
if (startFrom >= name.length()) {
|
||||
if (startFrom >= name.length() ||
|
||||
myHasHumps && Character.isLowerCase(p) && !(patternIndex > 0 && NameUtil.isWordSeparator(myPattern[patternIndex - 1]))) {
|
||||
return -1;
|
||||
}
|
||||
int nextWordStart = startFrom;
|
||||
|
||||
@@ -947,7 +947,7 @@ public class UIUtil {
|
||||
}
|
||||
|
||||
public static boolean isFullRowSelectionLAF() {
|
||||
return isUnderQuaquaLookAndFeel();
|
||||
return isUnderGTKLookAndFeel() || isUnderQuaquaLookAndFeel();
|
||||
}
|
||||
|
||||
public static boolean isUnderNativeMacLookAndFeel() {
|
||||
|
||||
@@ -40,17 +40,19 @@ public class WideSelectionTreeUI extends BasicTreeUI {
|
||||
@NonNls public static final String SOURCE_LIST_CLIENT_PROPERTY = "mac.ui.source.list";
|
||||
@NonNls public static final String STRIPED_CLIENT_PROPERTY = "mac.ui.striped";
|
||||
|
||||
private static final Icon TREE_COLLAPSED_ICON = UIUtil.getTreeCollapsedIcon();
|
||||
private static final Icon TREE_EXPANDED_ICON = UIUtil.getTreeExpandedIcon();
|
||||
private static final Icon TREE_SELECTED_COLLAPSED_ICON = UIUtil.isUnderAquaBasedLookAndFeel() || UIUtil.isUnderNimbusLookAndFeel()
|
||||
? AllIcons.Mac.Tree_white_right_arrow : TREE_COLLAPSED_ICON;
|
||||
private static final Icon TREE_SELECTED_EXPANDED_ICON = UIUtil.isUnderAquaBasedLookAndFeel() || UIUtil.isUnderNimbusLookAndFeel()
|
||||
? AllIcons.Mac.Tree_white_down_arrow : TREE_EXPANDED_ICON;
|
||||
private static Icon getTreeSelectedCollapsedIcon() {
|
||||
return UIUtil.isUnderAquaBasedLookAndFeel() || UIUtil.isUnderNimbusLookAndFeel() || UIUtil.isUnderGTKLookAndFeel()
|
||||
? AllIcons.Mac.Tree_white_right_arrow : UIUtil.getTreeCollapsedIcon();
|
||||
}
|
||||
|
||||
private static final Border LIST_BACKGROUND_PAINTER = (Border)UIManager.get("List.sourceListBackgroundPainter");
|
||||
private static final Border LIST_SELECTION_BACKGROUND_PAINTER = (Border)UIManager.get("List.sourceListSelectionBackgroundPainter");
|
||||
private static final Border LIST_FOCUSED_SELECTION_BACKGROUND_PAINTER =
|
||||
(Border)UIManager.get("List.sourceListFocusedSelectionBackgroundPainter");
|
||||
private static Icon getTreeSelectedExpandedIcon() {
|
||||
return UIUtil.isUnderAquaBasedLookAndFeel() || UIUtil.isUnderNimbusLookAndFeel() || UIUtil.isUnderGTKLookAndFeel()
|
||||
? AllIcons.Mac.Tree_white_down_arrow : UIUtil.getTreeExpandedIcon();
|
||||
}
|
||||
|
||||
private static final Border LIST_BACKGROUND_PAINTER = UIManager.getBorder("List.sourceListBackgroundPainter");
|
||||
private static final Border LIST_SELECTION_BACKGROUND_PAINTER = UIManager.getBorder("List.sourceListSelectionBackgroundPainter");
|
||||
private static final Border LIST_FOCUSED_SELECTION_BACKGROUND_PAINTER = UIManager.getBorder("List.sourceListFocusedSelectionBackgroundPainter");
|
||||
|
||||
private boolean myWideSelection;
|
||||
private boolean myAlwaysPaintRowBackground;
|
||||
@@ -106,9 +108,6 @@ public class WideSelectionTreeUI extends BasicTreeUI {
|
||||
|
||||
tree.setShowsRootHandles(true);
|
||||
tree.addMouseListener(mySelectionListener);
|
||||
|
||||
//final InputMap inputMap = tree.getInputMap(JComponent.WHEN_FOCUSED);
|
||||
//inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "clearSelection");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -407,10 +406,10 @@ public class WideSelectionTreeUI extends BasicTreeUI {
|
||||
boolean isPathSelected = tree.getSelectionModel().isPathSelected(path);
|
||||
boolean dark = UIUtil.isUnderDarcula();
|
||||
|
||||
Icon expandIcon = (isPathSelected && tree.hasFocus()) || dark ? TREE_SELECTED_EXPANDED_ICON
|
||||
: TREE_EXPANDED_ICON;
|
||||
Icon collapseIcon = (isPathSelected && tree.hasFocus()) || dark? TREE_SELECTED_COLLAPSED_ICON
|
||||
: TREE_COLLAPSED_ICON;
|
||||
Icon expandIcon = (isPathSelected && tree.hasFocus()) || dark ? getTreeSelectedExpandedIcon()
|
||||
: UIUtil.getTreeExpandedIcon();
|
||||
Icon collapseIcon = (isPathSelected && tree.hasFocus()) || dark? getTreeSelectedCollapsedIcon()
|
||||
: UIUtil.getTreeCollapsedIcon();
|
||||
|
||||
|
||||
if (!isLeaf(row)) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.intellij.psi.xml.*;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomManager;
|
||||
import org.jetbrains.android.dom.resources.ResourceElement;
|
||||
import org.jetbrains.android.dom.wrappers.LazyValueResourceElementWrapper;
|
||||
import org.jetbrains.android.dom.wrappers.ResourceElementWrapper;
|
||||
import org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
@@ -45,21 +46,26 @@ import java.util.List;
|
||||
public class AndroidFindUsagesHandlerFactory extends FindUsagesHandlerFactory {
|
||||
@Override
|
||||
public boolean canFindUsages(@NotNull PsiElement element) {
|
||||
if (element instanceof XmlAttributeValue) {
|
||||
XmlAttributeValue value = (XmlAttributeValue)element;
|
||||
PsiElement element1 = LazyValueResourceElementWrapper.computeLazyElement(element);
|
||||
if (element1 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (element1 instanceof XmlAttributeValue) {
|
||||
XmlAttributeValue value = (XmlAttributeValue)element1;
|
||||
if (AndroidResourceUtil.findIdFields(value).length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
element = correctResourceElement(element);
|
||||
if (element instanceof PsiField) {
|
||||
return AndroidResourceUtil.isResourceField((PsiField)element);
|
||||
element1 = correctResourceElement(element1);
|
||||
if (element1 instanceof PsiField) {
|
||||
return AndroidResourceUtil.isResourceField((PsiField)element1);
|
||||
}
|
||||
else if (element instanceof PsiFile) {
|
||||
return AndroidResourceUtil.findResourceFieldsForFileResource((PsiFile)element, true).length > 0;
|
||||
else if (element1 instanceof PsiFile) {
|
||||
return AndroidResourceUtil.findResourceFieldsForFileResource((PsiFile)element1, true).length > 0;
|
||||
}
|
||||
else if (element instanceof XmlTag) {
|
||||
return AndroidResourceUtil.findResourceFieldsForValueResource((XmlTag)element, true).length > 0;
|
||||
else if (element1 instanceof XmlTag) {
|
||||
return AndroidResourceUtil.findResourceFieldsForValueResource((XmlTag)element1, true).length > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -101,7 +107,11 @@ public class AndroidFindUsagesHandlerFactory extends FindUsagesHandlerFactory {
|
||||
|
||||
@Override
|
||||
public FindUsagesHandler createFindUsagesHandler(@NotNull PsiElement element, boolean forHighlightUsages) {
|
||||
PsiElement e = element;
|
||||
PsiElement e = LazyValueResourceElementWrapper.computeLazyElement(element);
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AndroidFacet facet = AndroidFacet.getInstance(e);
|
||||
assert facet != null;
|
||||
if (e instanceof XmlAttributeValue) {
|
||||
|
||||
@@ -41,6 +41,7 @@ import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomManager;
|
||||
import org.jetbrains.android.dom.resources.ResourceElement;
|
||||
import org.jetbrains.android.dom.wrappers.LazyValueResourceElementWrapper;
|
||||
import org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.resourceManagers.LocalResourceManager;
|
||||
@@ -67,23 +68,28 @@ public class AndroidRenameResourceProcessor extends RenamePsiElementProcessor {
|
||||
public boolean canProcessElement(@NotNull final PsiElement element) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
public Boolean compute() {
|
||||
if (element instanceof PsiFile) {
|
||||
return AndroidFacet.getInstance(element) != null && AndroidResourceUtil.isInResourceSubdirectory((PsiFile)element, null);
|
||||
final PsiElement element1 = LazyValueResourceElementWrapper.computeLazyElement(element);
|
||||
if (element1 == null) {
|
||||
return false;
|
||||
}
|
||||
else if (element instanceof PsiField) {
|
||||
PsiField field = (PsiField)element;
|
||||
|
||||
if (element1 instanceof PsiFile) {
|
||||
return AndroidFacet.getInstance(element1) != null && AndroidResourceUtil.isInResourceSubdirectory((PsiFile)element1, null);
|
||||
}
|
||||
else if (element1 instanceof PsiField) {
|
||||
PsiField field = (PsiField)element1;
|
||||
if (AndroidResourceUtil.isResourceField(field)) {
|
||||
return AndroidResourceUtil.findResourcesByField(field).size() > 0;
|
||||
}
|
||||
}
|
||||
else if (element instanceof XmlAttributeValue) {
|
||||
LocalResourceManager manager = LocalResourceManager.getInstance(element);
|
||||
else if (element1 instanceof XmlAttributeValue) {
|
||||
LocalResourceManager manager = LocalResourceManager.getInstance(element1);
|
||||
if (manager != null) {
|
||||
if (AndroidResourceUtil.isIdDeclaration((XmlAttributeValue)element)) {
|
||||
if (AndroidResourceUtil.isIdDeclaration((XmlAttributeValue)element1)) {
|
||||
return true;
|
||||
}
|
||||
// then it is value resource
|
||||
XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
|
||||
XmlTag tag = PsiTreeUtil.getParentOfType(element1, XmlTag.class);
|
||||
return tag != null && manager.getValueResourceType(tag) != null;
|
||||
}
|
||||
}
|
||||
@@ -94,22 +100,29 @@ public class AndroidRenameResourceProcessor extends RenamePsiElementProcessor {
|
||||
|
||||
@Override
|
||||
public void prepareRenaming(PsiElement element, String newName, Map<PsiElement, String> allRenames) {
|
||||
AndroidFacet facet = AndroidFacet.getInstance(element);
|
||||
assert facet != null;
|
||||
if (element instanceof PsiFile) {
|
||||
prepareResourceFileRenaming((PsiFile)element, newName, allRenames, facet);
|
||||
final PsiElement element1 = LazyValueResourceElementWrapper.computeLazyElement(element);
|
||||
if (element1 == null) {
|
||||
return;
|
||||
}
|
||||
else if (element instanceof XmlAttributeValue) {
|
||||
XmlAttributeValue value = (XmlAttributeValue)element;
|
||||
|
||||
// todo: support renaming alternative value resources
|
||||
|
||||
AndroidFacet facet = AndroidFacet.getInstance(element1);
|
||||
assert facet != null;
|
||||
if (element1 instanceof PsiFile) {
|
||||
prepareResourceFileRenaming((PsiFile)element1, newName, allRenames, facet);
|
||||
}
|
||||
else if (element1 instanceof XmlAttributeValue) {
|
||||
XmlAttributeValue value = (XmlAttributeValue)element1;
|
||||
if (AndroidResourceUtil.isIdDeclaration(value)) {
|
||||
prepareIdRenaming(value, newName, allRenames, facet);
|
||||
}
|
||||
else {
|
||||
prepareValueResourceRenaming(element, newName, allRenames, facet);
|
||||
prepareValueResourceRenaming(element1, newName, allRenames, facet);
|
||||
}
|
||||
}
|
||||
else if (element instanceof PsiField) {
|
||||
prepareResourceFieldRenaming((PsiField)element, newName, allRenames);
|
||||
else if (element1 instanceof PsiField) {
|
||||
prepareResourceFieldRenaming((PsiField)element1, newName, allRenames);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
package org.jetbrains.android;
|
||||
|
||||
import com.android.resources.ResourceType;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.XmlRecursiveElementVisitor;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.indexing.*;
|
||||
@@ -11,8 +16,9 @@ import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import com.intellij.util.xml.NanoXmlUtil;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.ResourceEntry;
|
||||
import org.jetbrains.android.util.ValueResourcesFileParser;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -26,8 +32,12 @@ import java.util.Set;
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidValueResourcesIndex extends FileBasedIndexExtension<ResourceEntry, Set<ResourceEntry>> {
|
||||
public static final ID<ResourceEntry, Set<ResourceEntry>> INDEX_ID = ID.create("android.value.resources.index");
|
||||
public class AndroidValueResourcesIndex extends FileBasedIndexExtension<ResourceEntry, Set<AndroidValueResourcesIndex.MyResourceInfo>> {
|
||||
public static final ID<ResourceEntry, Set<MyResourceInfo>> INDEX_ID = ID.create("android.value.resources.index");
|
||||
|
||||
@NonNls private static final String RESOURCES_ROOT_TAG = "resources";
|
||||
@NonNls private static final String NAME_ATTRIBUTE_VALUE = "name";
|
||||
@NonNls private static final String TYPE_ATTRIBUTE_VALUE = "type";
|
||||
|
||||
private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() {
|
||||
@Override
|
||||
@@ -37,28 +47,54 @@ public class AndroidValueResourcesIndex extends FileBasedIndexExtension<Resource
|
||||
}
|
||||
};
|
||||
|
||||
private final DataIndexer<ResourceEntry, Set<ResourceEntry>, FileContent> myIndexer =
|
||||
new DataIndexer<ResourceEntry, Set<ResourceEntry>, FileContent>() {
|
||||
private final DataIndexer<ResourceEntry, Set<MyResourceInfo>, FileContent> myIndexer =
|
||||
new DataIndexer<ResourceEntry, Set<MyResourceInfo>, FileContent>() {
|
||||
@Override
|
||||
@NotNull
|
||||
public Map<ResourceEntry, Set<ResourceEntry>> map(FileContent inputData) {
|
||||
|
||||
if (CharArrayUtil.indexOf(inputData.getContentAsText(), "<resources", 0) < 0) {
|
||||
public Map<ResourceEntry, Set<MyResourceInfo>> map(FileContent inputData) {
|
||||
if (!isSimilarFile(inputData)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
final Map<ResourceEntry, Set<ResourceEntry>> result = new HashMap<ResourceEntry, Set<ResourceEntry>>();
|
||||
final PsiFile file = inputData.getPsiFile();
|
||||
|
||||
NanoXmlUtil.parse(CharArrayUtil.readerFromCharSequence(inputData.getContentAsText()), new ValueResourcesFileParser() {
|
||||
@Override
|
||||
protected void stop() {
|
||||
throw new NanoXmlUtil.ParserStoppedException();
|
||||
}
|
||||
if (!(file instanceof XmlFile)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
final Map<ResourceEntry, Set<MyResourceInfo>> result = new HashMap<ResourceEntry, Set<MyResourceInfo>>();
|
||||
|
||||
file.accept(new XmlRecursiveElementVisitor() {
|
||||
@Override
|
||||
protected void process(@NotNull ResourceEntry entry) {
|
||||
result.put(createKey(entry), Collections.<ResourceEntry>emptySet());
|
||||
addEntryToMap(entry, createTypeMarkerKey(entry.getType()), result);
|
||||
addEntryToMap(entry, createTypeNameMarkerKey(entry.getType(), entry.getName()), result);
|
||||
public void visitXmlTag(XmlTag tag) {
|
||||
super.visitXmlTag(tag);
|
||||
final String resName = tag.getAttributeValue(NAME_ATTRIBUTE_VALUE);
|
||||
|
||||
if (resName == null) {
|
||||
return;
|
||||
}
|
||||
final String tagName = tag.getName();
|
||||
final String resTypeStr;
|
||||
|
||||
if ("item".equals(tagName)) {
|
||||
resTypeStr = tag.getAttributeValue(TYPE_ATTRIBUTE_VALUE);
|
||||
}
|
||||
else {
|
||||
resTypeStr = AndroidCommonUtils.getResourceTypeByTagName(tagName);
|
||||
}
|
||||
final ResourceType resType = resTypeStr != null ? ResourceType.getEnum(resTypeStr) : null;
|
||||
|
||||
if (resType == null) {
|
||||
return;
|
||||
}
|
||||
final int offset = tag.getTextRange().getStartOffset();
|
||||
|
||||
if (resType == ResourceType.ATTR) {
|
||||
final XmlTag parentTag = tag.getParentTag();
|
||||
final String contextName = parentTag != null ? parentTag.getAttributeValue(NAME_ATTRIBUTE_VALUE) : null;
|
||||
processResourceEntry(new ResourceEntry(resTypeStr, resName, contextName != null ? contextName : ""), result, offset);
|
||||
}
|
||||
else {
|
||||
processResourceEntry(new ResourceEntry(resTypeStr, resName, ""), result, offset);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -66,14 +102,40 @@ public class AndroidValueResourcesIndex extends FileBasedIndexExtension<Resource
|
||||
}
|
||||
};
|
||||
|
||||
private static void addEntryToMap(ResourceEntry entry, ResourceEntry marker, Map<ResourceEntry, Set<ResourceEntry>> result) {
|
||||
Set<ResourceEntry> set = result.get(marker);
|
||||
private static boolean isSimilarFile(FileContent inputData) {
|
||||
if (CharArrayUtil.indexOf(inputData.getContentAsText(), "<" + RESOURCES_ROOT_TAG, 0) < 0) {
|
||||
return false;
|
||||
}
|
||||
final boolean[] ourRootTag = {false};
|
||||
|
||||
NanoXmlUtil.parse(CharArrayUtil.readerFromCharSequence(inputData.getContentAsText()), new NanoXmlUtil.IXMLBuilderAdapter() {
|
||||
@Override
|
||||
public void startElement(String name, String nsPrefix, String nsURI, String systemID, int lineNr)
|
||||
throws Exception {
|
||||
ourRootTag[0] = RESOURCES_ROOT_TAG.equals(name) && nsPrefix == null;
|
||||
stop();
|
||||
}
|
||||
});
|
||||
return ourRootTag[0];
|
||||
}
|
||||
|
||||
private static void processResourceEntry(@NotNull ResourceEntry entry,
|
||||
@NotNull Map<ResourceEntry, Set<MyResourceInfo>> result,
|
||||
int offset) {
|
||||
final MyResourceInfo info = new MyResourceInfo(entry, offset);
|
||||
result.put(entry, Collections.singleton(info));
|
||||
addEntryToMap(info, createTypeMarkerKey(entry.getType()), result);
|
||||
addEntryToMap(info, createTypeNameMarkerKey(entry.getType(), entry.getName()), result);
|
||||
}
|
||||
|
||||
private static void addEntryToMap(MyResourceInfo info, ResourceEntry marker, Map<ResourceEntry, Set<MyResourceInfo>> result) {
|
||||
Set<MyResourceInfo> set = result.get(marker);
|
||||
|
||||
if (set == null) {
|
||||
set = new HashSet<ResourceEntry>();
|
||||
set = new HashSet<MyResourceInfo>();
|
||||
result.put(marker, set);
|
||||
}
|
||||
set.add(entry);
|
||||
set.add(info);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -83,17 +145,7 @@ public class AndroidValueResourcesIndex extends FileBasedIndexExtension<Resource
|
||||
|
||||
@NotNull
|
||||
public static ResourceEntry createTypeNameMarkerKey(String type, String name) {
|
||||
return createKey(type, name, "TYPE_MARKER_CONTEXT");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ResourceEntry createKey(ResourceEntry entry) {
|
||||
return createKey(entry.getType(), entry.getName(), entry.getContext());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ResourceEntry createKey(String type, String name, String context) {
|
||||
return new ResourceEntry(type, normalizeDelimiters(name), context);
|
||||
return new ResourceEntry(type, normalizeDelimiters(name), "TYPE_MARKER_CONTEXT");
|
||||
}
|
||||
|
||||
private static String normalizeDelimiters(String s) {
|
||||
@@ -138,33 +190,35 @@ public class AndroidValueResourcesIndex extends FileBasedIndexExtension<Resource
|
||||
}
|
||||
};
|
||||
|
||||
private final DataExternalizer<Set<ResourceEntry>> myValueExternalizer = new DataExternalizer<Set<ResourceEntry>>() {
|
||||
private final DataExternalizer<Set<MyResourceInfo>> myValueExternalizer = new DataExternalizer<Set<MyResourceInfo>>() {
|
||||
@Override
|
||||
public void save(DataOutput out, Set<ResourceEntry> value) throws IOException {
|
||||
public void save(DataOutput out, Set<MyResourceInfo> value) throws IOException {
|
||||
out.writeInt(value.size());
|
||||
|
||||
for (ResourceEntry entry : value) {
|
||||
out.writeUTF(entry.getType());
|
||||
out.writeUTF(entry.getName());
|
||||
out.writeUTF(entry.getContext());
|
||||
for (MyResourceInfo entry : value) {
|
||||
out.writeUTF(entry.getResourceEntry().getType());
|
||||
out.writeUTF(entry.getResourceEntry().getName());
|
||||
out.writeUTF(entry.getResourceEntry().getContext());
|
||||
out.writeInt(entry.getOffset());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Set<ResourceEntry> read(DataInput in) throws IOException {
|
||||
public Set<MyResourceInfo> read(DataInput in) throws IOException {
|
||||
final int size = in.readInt();
|
||||
|
||||
if (size == 0) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
final Set<ResourceEntry> result = new HashSet<ResourceEntry>(size);
|
||||
final Set<MyResourceInfo> result = new HashSet<MyResourceInfo>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
final String type = in.readUTF();
|
||||
final String name = in.readUTF();
|
||||
final String context = in.readUTF();
|
||||
result.add(new ResourceEntry(type, name, context));
|
||||
final int offset = in.readInt();
|
||||
result.add(new MyResourceInfo(new ResourceEntry(type, name, context), offset));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -172,13 +226,13 @@ public class AndroidValueResourcesIndex extends FileBasedIndexExtension<Resource
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ID<ResourceEntry, Set<ResourceEntry>> getName() {
|
||||
public ID<ResourceEntry, Set<MyResourceInfo>> getName() {
|
||||
return INDEX_ID;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataIndexer<ResourceEntry, Set<ResourceEntry>, FileContent> getIndexer() {
|
||||
public DataIndexer<ResourceEntry, Set<MyResourceInfo>, FileContent> getIndexer() {
|
||||
return myIndexer;
|
||||
}
|
||||
|
||||
@@ -188,7 +242,7 @@ public class AndroidValueResourcesIndex extends FileBasedIndexExtension<Resource
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataExternalizer<Set<ResourceEntry>> getValueExternalizer() {
|
||||
public DataExternalizer<Set<MyResourceInfo>> getValueExternalizer() {
|
||||
return myValueExternalizer;
|
||||
}
|
||||
|
||||
@@ -204,6 +258,53 @@ public class AndroidValueResourcesIndex extends FileBasedIndexExtension<Resource
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 3;
|
||||
return 5;
|
||||
}
|
||||
|
||||
public static class MyResourceInfo {
|
||||
private final ResourceEntry myResourceEntry;
|
||||
private final int myOffset;
|
||||
|
||||
private MyResourceInfo(@NotNull ResourceEntry resourceEntry, int offset) {
|
||||
myResourceEntry = resourceEntry;
|
||||
myOffset = offset;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ResourceEntry getResourceEntry() {
|
||||
return myResourceEntry;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return myOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MyResourceInfo info = (MyResourceInfo)o;
|
||||
|
||||
if (myOffset != info.myOffset) {
|
||||
return false;
|
||||
}
|
||||
if (!myResourceEntry.equals(info.myResourceEntry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myResourceEntry.hashCode();
|
||||
result = 31 * result + myOffset;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+64
-16
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.jetbrains.android.dom.converters;
|
||||
|
||||
import com.intellij.navigation.NavigationItem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.ResolveCache;
|
||||
import com.intellij.psi.xml.XmlAttributeValue;
|
||||
@@ -26,12 +26,14 @@ import com.intellij.util.xml.*;
|
||||
import com.intellij.util.xml.impl.ConvertContextImpl;
|
||||
import com.intellij.util.xml.impl.DomCompletionContributor;
|
||||
import org.jetbrains.android.dom.AndroidDomUtil;
|
||||
import org.jetbrains.android.dom.resources.ResourceElement;
|
||||
import org.jetbrains.android.dom.resources.ResourceValue;
|
||||
import org.jetbrains.android.dom.wrappers.FileResourceElementWrapper;
|
||||
import org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper;
|
||||
import org.jetbrains.android.dom.wrappers.LazyValueResourceElementWrapper;
|
||||
import org.jetbrains.android.dom.wrappers.ResourceElementWrapper;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.resourceManagers.ResourceManager;
|
||||
import org.jetbrains.android.resourceManagers.ValueResourceInfo;
|
||||
import org.jetbrains.android.resourceManagers.ValueResourceInfoImpl;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidResourceUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -102,6 +104,29 @@ public class AndroidResourceReference extends PsiReferenceBase.Poly<XmlElement>
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiElement[] computeTargetElements() {
|
||||
final ResolveResult[] resolveResults = multiResolve(false);
|
||||
final List<PsiElement> results = new ArrayList<PsiElement>();
|
||||
|
||||
for (ResolveResult result : resolveResults) {
|
||||
PsiElement element = result.getElement();
|
||||
|
||||
if (element instanceof LazyValueResourceElementWrapper) {
|
||||
element = ((LazyValueResourceElementWrapper)element).computeElement();
|
||||
}
|
||||
|
||||
if (element instanceof ResourceElementWrapper) {
|
||||
element = ((ResourceElementWrapper)element).getWrappee();
|
||||
}
|
||||
|
||||
if (element != null) {
|
||||
results.add(element);
|
||||
}
|
||||
}
|
||||
return results.toArray(new PsiElement[results.size()]);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ResolveResult[] multiResolve(boolean incompleteCode) {
|
||||
@@ -122,7 +147,7 @@ public class AndroidResourceReference extends PsiReferenceBase.Poly<XmlElement>
|
||||
collectTargets(myFacet, myResourceValue, elements, files);
|
||||
|
||||
final List<ResolveResult> result = new ArrayList<ResolveResult>();
|
||||
|
||||
|
||||
for (PsiFile target : files) {
|
||||
if (target != null) {
|
||||
final PsiFile e = new FileResourceElementWrapper(target);
|
||||
@@ -131,15 +156,12 @@ public class AndroidResourceReference extends PsiReferenceBase.Poly<XmlElement>
|
||||
}
|
||||
|
||||
for (PsiElement target : elements) {
|
||||
final PsiElement e = target instanceof NavigationItem && target instanceof XmlAttributeValue
|
||||
? new ValueResourceElementWrapper((XmlAttributeValue)target)
|
||||
: target;
|
||||
result.add(new PsiElementResolveResult(e));
|
||||
result.add(new PsiElementResolveResult(target));
|
||||
}
|
||||
return result.toArray(new ResolveResult[result.size()]);
|
||||
}
|
||||
|
||||
private static void collectTargets(AndroidFacet facet, ResourceValue resValue, List<PsiElement> elements, List<PsiFile> files) {
|
||||
private void collectTargets(AndroidFacet facet, ResourceValue resValue, List<PsiElement> elements, List<PsiFile> files) {
|
||||
String resType = resValue.getResourceType();
|
||||
if (resType == null) {
|
||||
return;
|
||||
@@ -148,15 +170,13 @@ public class AndroidResourceReference extends PsiReferenceBase.Poly<XmlElement>
|
||||
if (manager != null) {
|
||||
String resName = resValue.getResourceName();
|
||||
if (resName != null) {
|
||||
List<ResourceElement> valueResources = manager.findValueResources(resType, resName, false);
|
||||
for (ResourceElement resource : valueResources) {
|
||||
elements.add(resource.getName().getXmlAttributeValue());
|
||||
List<ValueResourceInfoImpl> valueResources = manager.findValueResourceInfos(resType, resName, false);
|
||||
|
||||
for (final ValueResourceInfo resource : valueResources) {
|
||||
elements.add(new LazyValueResourceElementWrapper(resource, myElement));
|
||||
}
|
||||
if (resType.equals("id")) {
|
||||
List<PsiElement> idAttrs = manager.findIdDeclarations(resName);
|
||||
if (idAttrs != null) {
|
||||
elements.addAll(idAttrs);
|
||||
}
|
||||
elements.addAll(manager.findIdDeclarations(resName));
|
||||
}
|
||||
if (elements.size() == 0) {
|
||||
files.addAll(manager.findResourceFiles(resType, resName, false));
|
||||
@@ -164,4 +184,32 @@ public class AndroidResourceReference extends PsiReferenceBase.Poly<XmlElement>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReferenceTo(PsiElement element) {
|
||||
final ResolveResult[] results = multiResolve(false);
|
||||
final PsiFile psiFile = element.getContainingFile();
|
||||
final VirtualFile vFile = psiFile != null ? psiFile.getVirtualFile() : null;
|
||||
|
||||
for (ResolveResult result : results) {
|
||||
final PsiElement target = result.getElement();
|
||||
|
||||
if (element.getManager().areElementsEquivalent(target, element)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target instanceof LazyValueResourceElementWrapper && vFile != null) {
|
||||
final ValueResourceInfo info = ((LazyValueResourceElementWrapper)target).getResourceInfo();
|
||||
|
||||
if (info.getContainingFile().equals(vFile)) {
|
||||
final XmlAttributeValue realTarget = info.computeXmlElement();
|
||||
|
||||
if (element.getManager().areElementsEquivalent(realTarget, element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ public class StyleItemNameConverter extends ResolvingConverter<String> {
|
||||
@Override
|
||||
public String fromString(@Nullable @NonNls String s, ConvertContext context) {
|
||||
if (s == null) return null;
|
||||
String[] strs = s.split(s);
|
||||
String[] strs = s.split(":");
|
||||
if (strs.length < 2 || !"android".equals(strs[0])) {
|
||||
return s;
|
||||
}
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package org.jetbrains.android.dom.wrappers;
|
||||
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiTarget;
|
||||
import com.intellij.psi.impl.RenameableFakePsiElement;
|
||||
import com.intellij.psi.xml.XmlAttributeValue;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.android.resourceManagers.ValueResourceInfo;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class LazyValueResourceElementWrapper extends RenameableFakePsiElement implements PsiTarget {
|
||||
private final ValueResourceInfo myResourceInfo;
|
||||
private final PsiElement myParent;
|
||||
|
||||
public LazyValueResourceElementWrapper(@NotNull ValueResourceInfo resourceInfo, @NotNull PsiElement parent) {
|
||||
super(parent);
|
||||
myParent = parent;
|
||||
myResourceInfo = resourceInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return myResourceInfo.getName();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
|
||||
final XmlAttributeValue element = computeElement();
|
||||
if (element == null) {
|
||||
throw new IncorrectOperationException(
|
||||
"Cannot find resource '" + myResourceInfo.getName() + "' in file " + myResourceInfo.getContainingFile().getPath());
|
||||
}
|
||||
return new ValueResourceElementWrapper(element).setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemPresentation getPresentation() {
|
||||
return new ItemPresentation() {
|
||||
@Nullable
|
||||
public String getPresentableText() {
|
||||
final String name = myResourceInfo.getName();
|
||||
final VirtualFile resDir = myResourceInfo.getContainingFile().getParent();
|
||||
if (resDir == null) {
|
||||
return name;
|
||||
}
|
||||
return name + " (" + resDir.getName() + ')';
|
||||
}
|
||||
|
||||
public String getLocationString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Icon getIcon(boolean open) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public XmlAttributeValue computeElement() {
|
||||
return myResourceInfo.computeXmlElement();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getNavigationElement() {
|
||||
final XmlAttributeValue element = myResourceInfo.computeXmlElement();
|
||||
return element != null ? element : myParent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ValueResourceInfo getResourceInfo() {
|
||||
return myResourceInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "Android Value Resource";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement computeLazyElement(PsiElement element) {
|
||||
if (element instanceof LazyValueResourceElementWrapper) {
|
||||
element = ((LazyValueResourceElementWrapper)element).computeElement();
|
||||
}
|
||||
return element;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.jetbrains.android.resourceManagers;
|
||||
|
||||
import com.android.resources.ResourceType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.XmlRecursiveElementVisitor;
|
||||
import com.intellij.psi.xml.XmlAttributeValue;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import org.jetbrains.android.util.AndroidResourceUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class IdResourceInfo extends ValueResourceInfoBase {
|
||||
private final Project myProject;
|
||||
|
||||
IdResourceInfo(@NotNull String name, @NotNull VirtualFile file, @NotNull Project project) {
|
||||
super(name, ResourceType.ID, file);
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlAttributeValue computeXmlElement() {
|
||||
final PsiFile psiFile = PsiManager.getInstance(myProject).findFile(myFile);
|
||||
|
||||
if (!(psiFile instanceof XmlFile)) {
|
||||
return null;
|
||||
}
|
||||
final Ref<XmlAttributeValue> result = Ref.create();
|
||||
|
||||
psiFile.accept(new XmlRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitXmlAttributeValue(XmlAttributeValue attributeValue) {
|
||||
if (!result.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (AndroidResourceUtil.isIdDeclaration(attributeValue)) {
|
||||
final String idInAttr = AndroidResourceUtil.getResourceNameByReferenceText(attributeValue.getValue());
|
||||
|
||||
if (myName.equals(idInAttr)) {
|
||||
result.set(attributeValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return result.get();
|
||||
}
|
||||
}
|
||||
+7
-8
@@ -141,22 +141,21 @@ public class LocalResourceManager extends ResourceManager {
|
||||
for (ResourceType resourceType : AndroidResourceUtil.ALL_VALUE_RESOURCE_TYPES) {
|
||||
final ResourceEntry typeMarkerEntry = AndroidValueResourcesIndex.createTypeMarkerKey(resourceType.getName());
|
||||
|
||||
for (Set<ResourceEntry> entrySet : index.getValues(AndroidValueResourcesIndex.INDEX_ID, typeMarkerEntry, scope)) {
|
||||
for (ResourceEntry entry : entrySet) {
|
||||
final Collection<VirtualFile> files =
|
||||
index.getContainingFiles(AndroidValueResourcesIndex.INDEX_ID, AndroidValueResourcesIndex.createKey(entry), scope);
|
||||
|
||||
for (VirtualFile file : files) {
|
||||
index.processValues(AndroidValueResourcesIndex.INDEX_ID, typeMarkerEntry, null, new FileBasedIndex.ValueProcessor<Set<AndroidValueResourcesIndex.MyResourceInfo>>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile file, Set<AndroidValueResourcesIndex.MyResourceInfo> infos) {
|
||||
for (AndroidValueResourcesIndex.MyResourceInfo info : infos) {
|
||||
Set<String> resourcesInFile = file2Types.get(file);
|
||||
|
||||
if (resourcesInFile == null) {
|
||||
resourcesInFile = new HashSet<String>();
|
||||
file2Types.put(file, resourcesInFile);
|
||||
}
|
||||
resourcesInFile.add(entry.getType());
|
||||
resourcesInFile.add(info.getResourceEntry().getType());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}, scope);
|
||||
}
|
||||
final Set<String> result = new HashSet<String>();
|
||||
|
||||
|
||||
@@ -279,28 +279,28 @@ public abstract class ResourceManager {
|
||||
if (type == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final FileBasedIndex index = FileBasedIndex.getInstance();
|
||||
final ResourceEntry typeMarkerEntry = AndroidValueResourcesIndex.createTypeMarkerKey(resourceType);
|
||||
final GlobalSearchScope scope = GlobalSearchScope.allScope(myModule.getProject());
|
||||
|
||||
final Map<VirtualFile, Set<ResourceEntry>> file2resourceSet = new HashMap<VirtualFile, Set<ResourceEntry>>();
|
||||
for (Set<ResourceEntry> entrySet : index.getValues(AndroidValueResourcesIndex.INDEX_ID, typeMarkerEntry, scope)) {
|
||||
for (ResourceEntry entry : entrySet) {
|
||||
final Collection<VirtualFile> files =
|
||||
index.getContainingFiles(AndroidValueResourcesIndex.INDEX_ID, AndroidValueResourcesIndex.createKey(entry), scope);
|
||||
|
||||
for (VirtualFile file : files) {
|
||||
index.processValues(AndroidValueResourcesIndex.INDEX_ID, typeMarkerEntry, null, new FileBasedIndex.ValueProcessor<Set<AndroidValueResourcesIndex.MyResourceInfo>>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile file, Set<AndroidValueResourcesIndex.MyResourceInfo> infos) {
|
||||
for (AndroidValueResourcesIndex.MyResourceInfo info : infos) {
|
||||
Set<ResourceEntry> resourcesInFile = file2resourceSet.get(file);
|
||||
|
||||
if (resourcesInFile == null) {
|
||||
resourcesInFile = new HashSet<ResourceEntry>();
|
||||
file2resourceSet.put(file, resourcesInFile);
|
||||
}
|
||||
resourcesInFile.add(entry);
|
||||
resourcesInFile.add(info.getResourceEntry());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}, scope);
|
||||
|
||||
final List<ResourceEntry> result = new ArrayList<ResourceEntry>();
|
||||
|
||||
for (VirtualFile file : getAllValueResourceFiles()) {
|
||||
@@ -332,7 +332,7 @@ public abstract class ResourceManager {
|
||||
public abstract AttributeDefinitions getAttributeDefinitions();
|
||||
|
||||
// searches only declarations such as "@+id/..."
|
||||
@Nullable
|
||||
@NotNull
|
||||
public List<PsiElement> findIdDeclarations(@NotNull final String id) {
|
||||
if (!isResourcePublic(ResourceType.ID.getName(), id)) {
|
||||
return Collections.emptyList();
|
||||
@@ -428,33 +428,56 @@ public abstract class ResourceManager {
|
||||
return findValueResources(resType, resName, true);
|
||||
}
|
||||
|
||||
// not recommended to use, because it is too slow
|
||||
@NotNull
|
||||
public List<ResourceElement> findValueResources(@NotNull String resourceType,
|
||||
@NotNull String resourceName,
|
||||
boolean distinguishDelimetersInName) {
|
||||
final ResourceType type = ResourceType.getEnum(resourceType);
|
||||
if (type == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final Collection<VirtualFile> files = FileBasedIndex.getInstance()
|
||||
.getContainingFiles(AndroidValueResourcesIndex.INDEX_ID,
|
||||
AndroidValueResourcesIndex.createTypeNameMarkerKey(resourceType, resourceName),
|
||||
GlobalSearchScope.allScope(myModule.getProject()));
|
||||
|
||||
if (files.size() == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final Set<VirtualFile> fileSet = new HashSet<VirtualFile>(files);
|
||||
boolean distinguishDelimitersInName) {
|
||||
final List<ValueResourceInfoImpl> resources = findValueResourceInfos(resourceType, resourceName, distinguishDelimitersInName);
|
||||
final List<ResourceElement> result = new ArrayList<ResourceElement>();
|
||||
|
||||
for (ResourceElement element : getValueResources(resourceType, fileSet)) {
|
||||
final String name = element.getName().getValue();
|
||||
for (ValueResourceInfoImpl resource : resources) {
|
||||
final ResourceElement domElement = resource.computeDomElement();
|
||||
|
||||
if (AndroidUtils.equal(resourceName, name, distinguishDelimetersInName)) {
|
||||
result.add(element);
|
||||
if (domElement != null) {
|
||||
result.add(domElement);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<ValueResourceInfoImpl> findValueResourceInfos(@NotNull String resourceType,
|
||||
@NotNull final String resourceName,
|
||||
final boolean distinguishDelimetersInName) {
|
||||
final ResourceType type = ResourceType.getEnum(resourceType);
|
||||
if (type == null || !AndroidResourceUtil.VALUE_RESOURCE_TYPES.contains(type)) {
|
||||
// do not search for styleables and atts here because we don't want to resolve references to it
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
new HashMap<VirtualFile, Set<AndroidValueResourcesIndex.MyResourceInfo>>();
|
||||
final GlobalSearchScope scope = GlobalSearchScope.allScope(myModule.getProject());
|
||||
final List<ValueResourceInfoImpl> result = new ArrayList<ValueResourceInfoImpl>();
|
||||
final Set<VirtualFile> valueResourceFiles = getAllValueResourceFiles();
|
||||
|
||||
FileBasedIndex.getInstance()
|
||||
.processValues(AndroidValueResourcesIndex.INDEX_ID, AndroidValueResourcesIndex.createTypeNameMarkerKey(resourceType, resourceName),
|
||||
null, new FileBasedIndex.ValueProcessor<Set<AndroidValueResourcesIndex.MyResourceInfo>>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile file, Set<AndroidValueResourcesIndex.MyResourceInfo> infos) {
|
||||
for (AndroidValueResourcesIndex.MyResourceInfo info : infos) {
|
||||
final String name = info.getResourceEntry().getName();
|
||||
|
||||
if (AndroidUtils.equal(resourceName, name, distinguishDelimetersInName)) {
|
||||
if (valueResourceFiles.contains(file)) {
|
||||
result.add(new ValueResourceInfoImpl(info.getResourceEntry().getName(), type, file, myModule, info.getOffset()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}, scope);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.jetbrains.android.resourceManagers;
|
||||
|
||||
import com.android.resources.ResourceType;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.xml.XmlAttributeValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public interface ValueResourceInfo {
|
||||
@Nullable
|
||||
XmlAttributeValue computeXmlElement();
|
||||
|
||||
@NotNull
|
||||
VirtualFile getContainingFile();
|
||||
|
||||
@NotNull
|
||||
String getName();
|
||||
|
||||
@NotNull
|
||||
ResourceType getType();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.jetbrains.android.resourceManagers;
|
||||
|
||||
import com.android.resources.ResourceType;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
abstract class ValueResourceInfoBase implements ValueResourceInfo {
|
||||
protected final String myName;
|
||||
protected final ResourceType myType;
|
||||
protected final VirtualFile myFile;
|
||||
|
||||
protected ValueResourceInfoBase(@NotNull String name, @NotNull ResourceType type, @NotNull VirtualFile file) {
|
||||
myName = name;
|
||||
myType = type;
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public VirtualFile getContainingFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ResourceType getType() {
|
||||
return myType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ANDROID_RESOURCE: " + myType + ", " + myName + ", " + myFile.getPath() + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.jetbrains.android.resourceManagers;
|
||||
|
||||
import com.android.resources.ResourceType;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.XmlAttributeValue;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomManager;
|
||||
import org.jetbrains.android.dom.resources.Item;
|
||||
import org.jetbrains.android.dom.resources.ResourceElement;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class ValueResourceInfoImpl extends ValueResourceInfoBase {
|
||||
private final Module myModule;
|
||||
private final int myOffset;
|
||||
|
||||
ValueResourceInfoImpl(@NotNull String name, @NotNull ResourceType type, @NotNull VirtualFile file, @NotNull Module module, int offset) {
|
||||
super(name, type, file);
|
||||
myModule = module;
|
||||
myOffset = offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlAttributeValue computeXmlElement() {
|
||||
final ResourceElement resDomElement = computeDomElement();
|
||||
return resDomElement != null ? resDomElement.getName().getXmlAttributeValue() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceElement computeDomElement() {
|
||||
final Project project = myModule.getProject();
|
||||
final PsiFile file = PsiManager.getInstance(project).findFile(myFile);
|
||||
|
||||
if (!(file instanceof XmlFile)) {
|
||||
return null;
|
||||
}
|
||||
final XmlTag tag = PsiTreeUtil.findElementOfClassAtOffset(file, myOffset, XmlTag.class, true);
|
||||
|
||||
if (tag == null) {
|
||||
return null;
|
||||
}
|
||||
final DomElement domElement = DomManager.getDomManager(project).getDomElement(tag);
|
||||
if (!(domElement instanceof ResourceElement)) {
|
||||
return null;
|
||||
}
|
||||
final String resType = domElement instanceof Item
|
||||
? ((Item)domElement).getType().getStringValue()
|
||||
: AndroidCommonUtils.getResourceTypeByTagName(tag.getName());
|
||||
|
||||
if (!myType.getName().equals(resType)) {
|
||||
return null;
|
||||
}
|
||||
final ResourceElement resDomElement = (ResourceElement)domElement;
|
||||
final String resName = ((ResourceElement)domElement).getName().getStringValue();
|
||||
return myName.equals(resName) ? resDomElement : null;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/str1"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/str2"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/str100"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/str1000"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/str2500"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,11 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@strin<caret>g/str1000"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -2,5 +2,7 @@
|
||||
<resources>
|
||||
<style name="TextAppearance.Theme.PlainText">
|
||||
<item name="android:textStyle">normal|bold</item>
|
||||
<item name="<error>android:unknown</error>">normal|bold</item>
|
||||
<item name="unknown">normal|bold</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -12,6 +12,9 @@ import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.xml.XmlAttributeValue;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.util.ThrowableRunnable;
|
||||
import org.jetbrains.android.inspections.CreateFileResourceQuickFix;
|
||||
import org.jetbrains.android.inspections.CreateValueResourceQuickFix;
|
||||
|
||||
@@ -405,26 +408,67 @@ public class AndroidLayoutDomTest extends AndroidDomTest {
|
||||
toTestCompletion(getTestName(true) + ".xml", getTestName(true) + "_after.xml");
|
||||
}
|
||||
|
||||
/*public void testCustomAttrsPerformance() throws Throwable {
|
||||
public void testCustomAttrsPerformance() throws Throwable {
|
||||
myFixture.copyFileToProject("dom/resources/bigfile.xml", "res/values/bigfile.xml");
|
||||
myFixture.copyFileToProject("dom/resources/bigattrs.xml", "res/values/bigattrs.xml");
|
||||
myFixture.copyFileToProject("dom/resources/bigattrs.xml", "res/values/bigattrs1.xml");
|
||||
myFixture.copyFileToProject("dom/resources/bigattrs.xml", "res/values/bigattrs2.xml");
|
||||
myFixture.copyFileToProject("dom/resources/bigattrs.xml", "res/values/bigattrs3.xml");
|
||||
String path = copyFileToProject("bigfile.xml");
|
||||
VirtualFile f = myFixture.findFileInTempDir(path);
|
||||
VirtualFile f = copyFileToProject("bigfile.xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
IdeaTestUtil.assertTiming("", 800, new Runnable() {
|
||||
|
||||
PlatformTestUtil.startPerformanceTest("android custom attrs highlighting is slow", 800, new ThrowableRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
myFixture.doHighlighting();
|
||||
}
|
||||
catch (Exception e) {
|
||||
public void run() throws Throwable {
|
||||
myFixture.doHighlighting();
|
||||
}
|
||||
}).attempts(2).cpuBound().usesAllCPUCores().assertTiming();
|
||||
}
|
||||
|
||||
public void testResourceHighlightingPerformance() throws Throwable {
|
||||
doCopyManyStrings();
|
||||
final VirtualFile f = copyFileToProject(getTestName(true) + ".xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
PlatformTestUtil.startPerformanceTest("android highlighting is slow", 400, new ThrowableRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
myFixture.doHighlighting();
|
||||
}
|
||||
}).attempts(2).cpuBound().usesAllCPUCores().assertTiming();
|
||||
}
|
||||
|
||||
public void testResourceNavigationPerformance() throws Throwable {
|
||||
doCopyManyStrings();
|
||||
final VirtualFile f = copyFileToProject(getTestName(true) + ".xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
|
||||
final List<PsiElement> navElements = new ArrayList<PsiElement>();
|
||||
|
||||
// warm
|
||||
myFixture.doHighlighting();
|
||||
|
||||
PlatformTestUtil.startPerformanceTest("android highlighting is slow", 7000, new ThrowableRunnable() {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
final PsiReference reference = TargetElementUtilBase.findReference(myFixture.getEditor(), myFixture.getCaretOffset());
|
||||
final ResolveResult[] results = ((PsiPolyVariantReference)reference).multiResolve(false);
|
||||
for (ResolveResult result : results) {
|
||||
final PsiElement navElement = result.getElement().getNavigationElement();
|
||||
assertInstanceOf(navElement, XmlAttributeValue.class);
|
||||
navElements.add(navElement);
|
||||
}
|
||||
}
|
||||
});
|
||||
}*/
|
||||
}).attempts(1).cpuBound().usesAllCPUCores().assertTiming();
|
||||
assertEquals(31, navElements.size());
|
||||
}
|
||||
|
||||
private void doCopyManyStrings() {
|
||||
myFixture.copyFileToProject(testFolder + "/many_strings.xml", "res/values/strings.xml");
|
||||
for (int i = 0; i < 30; i++) {
|
||||
myFixture.copyFileToProject(testFolder + "/many_strings.xml", "res/values-" + Integer.toString(i) + "/strings.xml");
|
||||
}
|
||||
}
|
||||
|
||||
public void testViewClassReference() throws Throwable {
|
||||
VirtualFile file = myFixture.copyFileToProject(testFolder + "/vcr.xml", getPathToCopy("vcr.xml"));
|
||||
|
||||
@@ -30,9 +30,9 @@ import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.xml.XmlAttributeValue;
|
||||
import com.intellij.refactoring.actions.InlineAction;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import org.jetbrains.android.dom.wrappers.LazyValueResourceElementWrapper;
|
||||
import org.jetbrains.android.inspections.CreateValueResourceQuickFix;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -252,7 +252,8 @@ public class AndroidValueResourcesTest extends AndroidDomTest {
|
||||
PsiReference rootReference = psiFile.findReferenceAt(rootOffset);
|
||||
assertNotNull(rootReference);
|
||||
PsiElement element = rootReference.resolve();
|
||||
assertTrue("Must be PsiClass reference", element instanceof XmlAttributeValue);
|
||||
assertInstanceOf(element, LazyValueResourceElementWrapper.class);
|
||||
assertNotNull(((LazyValueResourceElementWrapper)element).computeElement());
|
||||
}
|
||||
|
||||
// see getPathToCopy()
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
<orderEntry type="module" module-name="spellchecker" />
|
||||
<orderEntry type="module" module-name="resources" scope="TEST" />
|
||||
<orderEntry type="module" module-name="xml" />
|
||||
<orderEntry type="module" module-name="testFramework-java" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
*/
|
||||
package com.intellij.lang.properties;
|
||||
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
|
||||
|
||||
/**
|
||||
* @author Rustam Vishnyakov
|
||||
*/
|
||||
public class PropertiesFoldingTest extends LightCodeInsightFixtureTestCase {
|
||||
public class PropertiesFoldingTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
|
||||
private static final String BASE_PATH = "/plugins/properties/testData/propertiesFile/folding/";
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
<extensionPoint name="generation.topLevelFactory" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
|
||||
|
||||
<extensionPoint name="codeInsight.createFieldFromUsageHelper" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
|
||||
|
||||
<extensionPoint name="findUsages.java.customJavaFindUsagesHandlerProvider" interface="com.intellij.find.findUsages.CustomJavaFindUsagesHandlerProvider"/>
|
||||
</extensionPoints>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
|
||||
@@ -83,7 +83,7 @@ public class XmlDoctypeImpl extends XmlElementImpl implements XmlDoctype {
|
||||
|
||||
@Nullable
|
||||
public String getDtdUri() {
|
||||
final XmlElement dtdUrlElement = getDtdUrlElement();
|
||||
final PsiElement dtdUrlElement = getDtdUrlElement();
|
||||
if (dtdUrlElement == null || dtdUrlElement.getTextLength() == 0) return null;
|
||||
return extractValue(dtdUrlElement);
|
||||
}
|
||||
@@ -120,7 +120,7 @@ public class XmlDoctypeImpl extends XmlElementImpl implements XmlDoctype {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public XmlElement getDtdUrlElement() {
|
||||
public PsiElement getDtdUrlElement() {
|
||||
PsiElement docTypePublic = findChildByRoleAsPsiElement(XmlChildRole.XML_DOCTYPE_PUBLIC);
|
||||
|
||||
if (docTypePublic != null){
|
||||
@@ -216,33 +216,32 @@ public class XmlDoctypeImpl extends XmlElementImpl implements XmlDoctype {
|
||||
|
||||
@NotNull
|
||||
public PsiReference[] getReferences() {
|
||||
final XmlElement dtdUrlElement = getDtdUrlElement();
|
||||
final PsiElement docTypePublic = findChildByRoleAsPsiElement(XmlChildRole.XML_DOCTYPE_PUBLIC);
|
||||
PsiReference[] uriRefs = null;
|
||||
final PsiElement dtdUrlElement = getDtdUrlElement();
|
||||
|
||||
PsiReference uriRef = null;
|
||||
if (dtdUrlElement != null) {
|
||||
uriRefs = new PsiReference[1];
|
||||
uriRefs[0] = new URLReference(XmlDoctypeImpl.this) {
|
||||
@NotNull
|
||||
public Object[] getVariants() {
|
||||
return docTypePublic != null ?
|
||||
super.getVariants(): EMPTY_ARRAY;
|
||||
}
|
||||
@NotNull
|
||||
public String getCanonicalText() {
|
||||
return extractValue(dtdUrlElement);
|
||||
}
|
||||
public TextRange getRangeInElement() {
|
||||
return TextRange.from(dtdUrlElement.getTextRange().getStartOffset() - getTextRange().getStartOffset() + 1, Math.max(dtdUrlElement.getTextRange().getLength() - 2, 0));
|
||||
}
|
||||
};
|
||||
uriRef = createUrlReference(dtdUrlElement);
|
||||
}
|
||||
|
||||
final PsiReference[] referencesFromProviders = ReferenceProvidersRegistry.getReferencesFromProviders(this);
|
||||
final PsiReference[] refs = ReferenceProvidersRegistry.getReferencesFromProviders(this);
|
||||
|
||||
return ArrayUtil.mergeArrays(
|
||||
uriRefs != null? uriRefs: PsiReference.EMPTY_ARRAY,
|
||||
referencesFromProviders
|
||||
);
|
||||
return uriRef == null ? refs : ArrayUtil.mergeArrays(new PsiReference[] {uriRef}, refs);
|
||||
}
|
||||
|
||||
protected PsiReference createUrlReference(final PsiElement dtdUrlElement) {
|
||||
return new URLReference(XmlDoctypeImpl.this) {
|
||||
@NotNull
|
||||
public Object[] getVariants() {
|
||||
return findChildByRoleAsPsiElement(XmlChildRole.XML_DOCTYPE_PUBLIC) != null ?
|
||||
super.getVariants(): EMPTY_ARRAY;
|
||||
}
|
||||
@NotNull
|
||||
public String getCanonicalText() {
|
||||
return extractValue(dtdUrlElement);
|
||||
}
|
||||
public TextRange getRangeInElement() {
|
||||
return TextRange.from(dtdUrlElement.getTextRange().getStartOffset() - getTextRange().getStartOffset() + 1, Math.max(dtdUrlElement.getTextRange().getLength() - 2, 0));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,15 @@
|
||||
*/
|
||||
package com.intellij.psi.xml;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
/**
|
||||
* @author Mike
|
||||
*/
|
||||
public interface XmlDoctype extends XmlElement {
|
||||
XmlElement getNameElement();
|
||||
String getDtdUri();
|
||||
XmlElement getDtdUrlElement();
|
||||
PsiElement getDtdUrlElement();
|
||||
XmlMarkupDecl getMarkupDecl();
|
||||
String getPublicId();
|
||||
String getSystemId();
|
||||
|
||||
Reference in New Issue
Block a user