Merge remote-tracking branch 'origin/master'

This commit is contained in:
Maxim.Medvedev
2012-02-10 15:27:58 +04:00
43 changed files with 671 additions and 122 deletions
@@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import gnu.trove.THashSet;
import org.intellij.images.ImagesBundle;
import org.intellij.images.fileTypes.ImageFileTypeManager;
import org.intellij.images.vfs.IfsUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -76,15 +77,16 @@ final class ImageFileTypeManagerImpl extends ImageFileTypeManager implements App
}
public void createFileTypes(final @NotNull FileTypeConsumer consumer) {
final String[] readerFormatNames = ImageIO.getReaderFormatNames();
final Set<String> processed = new THashSet<String>();
final String[] readerFormatNames = ImageIO.getReaderFormatNames();
for (String format : readerFormatNames) {
final String s = format.toLowerCase();
if (processed.contains(s)) continue;
processed.add(s);
final String ext = format.toLowerCase();
processed.add(ext);
}
processed.add(IfsUtil.ICO_FORMAT.toLowerCase());
consumer.consume(imageFileType, StringUtil.join(processed, FileTypeConsumer.EXTENSION_DELIMITER));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* 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.
@@ -27,6 +27,9 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.reference.SoftReference;
import com.intellij.util.LogicalRoot;
import com.intellij.util.LogicalRootsManager;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.common.byteSources.ByteSourceArray;
import org.apache.sanselan.formats.ico.IcoImageParser;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -46,9 +49,12 @@ import java.util.Iterator;
* @author <a href="mailto:aefimov.box@gmail.com">Alexey Efimov</a>
*/
public final class IfsUtil {
public static final String ICO_FORMAT = "ico";
private static final Key<Long> TIMESTAMP_KEY = Key.create("Image.timeStamp");
private static final Key<String> FORMAT_KEY = Key.create("Image.format");
private static final Key<SoftReference<BufferedImage>> BUFFERED_IMAGE_REF_KEY = Key.create("Image.bufferedImage");
private static final IcoImageParser ICO_IMAGE_PARSER = new IcoImageParser();
/**
* Load image data for file and put user data attributes into file.
@@ -63,6 +69,17 @@ public final class IfsUtil {
if (loadedTimeStamp == null || loadedTimeStamp.longValue() != file.getTimeStamp() || imageRef == null || imageRef.get() == null) {
try {
final byte[] content = file.contentsToByteArray();
if (ICO_FORMAT.equalsIgnoreCase(file.getExtension())) {
try {
final BufferedImage image = ICO_IMAGE_PARSER.getBufferedImage(new ByteSourceArray(content), null);
file.putUserData(FORMAT_KEY, ICO_FORMAT);
file.putUserData(BUFFERED_IMAGE_REF_KEY, new SoftReference<BufferedImage>(image));
return true;
}
catch (ImageReadException ignore) { }
}
InputStream inputStream = new ByteArrayInputStream(content, 0, content.length);
ImageInputStream imageInputStream = ImageIO.createImageInputStream(inputStream);
try {
@@ -500,7 +500,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
}
private ModalityState getStateForUpdate() {
return null;//myStateForUpdate != null ? myStateForUpdate.compute() : ModalityState.stateForComponent(this);
return myStateForUpdate != null ? myStateForUpdate.compute() : ModalityState.stateForComponent(this);
}
private void requestFlushImmediately() {
@@ -1873,7 +1873,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (myBalloon != null) {
if (myBalloon != null && e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
myBalloon.hide();
}
if (myListener != null) {
@@ -208,20 +208,8 @@ public class PopupFactoryImpl extends JBPopupFactory {
builder.buildGroup(actionGroup);
final List<ActionItem> items = builder.getItems();
int defaultOptionIndex = 0;
if (preselectActionCondition != null) {
for (int i = 0; i < items.size(); i++) {
final AnAction action = items.get(i).getAction();
if (preselectActionCondition.value(action)) {
defaultOptionIndex = i;
break;
}
}
}
return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items),
defaultOptionIndex,
false, showDisabledActions);
preselectActionCondition, false, showDisabledActions);
}
@Override
@@ -300,14 +288,42 @@ public class PopupFactoryImpl extends JBPopupFactory {
return createActionsStep(actionGroup, dataContext, showNumbers, showDisabledActions, title, component, honorActionMnemonics, 0, false);
}
private static ListPopupStep createActionsStep(ActionGroup actionGroup, @NotNull DataContext dataContext, boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions,
String title, Component component, boolean honorActionMnemonics, int defaultOptionIndex,
final boolean autoSelectionEnabled) {
final ActionStepBuilder builder = new ActionStepBuilder(dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics);
builder.buildGroup(actionGroup);
final List<ActionItem> items = builder.getItems();
private static ListPopupStep createActionsStep(ActionGroup actionGroup, @NotNull DataContext dataContext,
boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions,
String title, Component component, boolean honorActionMnemonics,
final int defaultOptionIndex, final boolean autoSelectionEnabled) {
final List<ActionItem> items = makeActionItemsFromActionGroup(actionGroup, dataContext, showNumbers, useAlphaAsNumbers,
showDisabledActions, honorActionMnemonics);
return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items),
new Condition<AnAction>() {
@Override
public boolean value(AnAction action) {
return defaultOptionIndex >= 0 &&
defaultOptionIndex < items.size() &&
items.get(defaultOptionIndex).getAction().equals(action);
}
}, autoSelectionEnabled, showDisabledActions);
}
return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), defaultOptionIndex,
private static List<ActionItem> makeActionItemsFromActionGroup(ActionGroup actionGroup,
DataContext dataContext,
boolean showNumbers,
boolean useAlphaAsNumbers,
boolean showDisabledActions,
boolean honorActionMnemonics) {
final ActionStepBuilder builder = new ActionStepBuilder(dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions,
honorActionMnemonics);
builder.buildGroup(actionGroup);
return builder.getItems();
}
private static ListPopupStep createActionsStep(ActionGroup actionGroup, @NotNull DataContext dataContext,
boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions,
String title, Component component, boolean honorActionMnemonics,
Condition<AnAction> preselectActionCondition, boolean autoSelectionEnabled) {
final List<ActionItem> items = makeActionItemsFromActionGroup(actionGroup, dataContext, showNumbers, useAlphaAsNumbers,
showDisabledActions, honorActionMnemonics);
return new ActionPopupStep(items, title, component, showNumbers || honorActionMnemonics && itemsHaveMnemonics(items), preselectActionCondition,
autoSelectionEnabled, showDisabledActions);
}
@@ -487,21 +503,35 @@ public class PopupFactoryImpl extends JBPopupFactory {
private final boolean myAutoSelectionEnabled;
private final boolean myShowDisabledActions;
private Runnable myFinalRunnable;
@Nullable private final Condition<AnAction> myPreselectActionCondition;
private ActionPopupStep(@NotNull final List<ActionItem> items,
final String title,
Component context,
boolean enableMnemonics,
final int defaultOptionIndex, final boolean autoSelection, boolean showDisabledActions) {
private ActionPopupStep(@NotNull final List<ActionItem> items, final String title, Component context, boolean enableMnemonics,
@Nullable Condition<AnAction> preselectActionCondition, final boolean autoSelection, boolean showDisabledActions) {
myItems = items;
myTitle = title;
myContext = context;
myEnableMnemonics = enableMnemonics;
myDefaultOptionIndex = defaultOptionIndex;
myDefaultOptionIndex = getDefaultOptionIndexFromSelectCondition(preselectActionCondition, items);
myPreselectActionCondition = preselectActionCondition;
myAutoSelectionEnabled = autoSelection;
myShowDisabledActions = showDisabledActions;
}
private static int getDefaultOptionIndexFromSelectCondition(@Nullable Condition<AnAction> preselectActionCondition,
@NotNull List<ActionItem> items) {
int defaultOptionIndex = 0;
if (preselectActionCondition != null) {
for (int i = 0; i < items.size(); i++) {
final AnAction action = items.get(i).getAction();
if (preselectActionCondition.value(action)) {
defaultOptionIndex = i;
break;
}
}
}
return defaultOptionIndex;
}
@NotNull
public List<ActionItem> getValues() {
return myItems;
@@ -552,13 +582,14 @@ public class PopupFactoryImpl extends JBPopupFactory {
final DataContext dataContext = myContext != null ? mgr.getDataContext(myContext) : mgr.getDataContext();
if (action instanceof ActionGroup && (!finalChoice || !((ActionGroup)action).canBePerformed(dataContext))) {
return JBPopupFactory.getInstance().createActionsStep((ActionGroup)action, dataContext, myEnableMnemonics, myShowDisabledActions, null, myContext, false);
return createActionsStep((ActionGroup)action, dataContext, myEnableMnemonics, true, myShowDisabledActions, null, myContext, false,
myPreselectActionCondition, false);
}
else {
myFinalRunnable = new Runnable() {
public void run() {
action.actionPerformed(
new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, (Presentation)action.getTemplatePresentation().clone(),
new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, action.getTemplatePresentation().clone(),
ActionManager.getInstance(), 0));
}
};
+4
View File
@@ -190,11 +190,15 @@
<externalAnnotator language="XML" implementationClass="org.jetbrains.android.inspections.lint.AndroidLintExternalAnnotator"/>
<externalAnnotator language="TEXT" implementationClass="org.jetbrains.android.inspections.lint.AndroidLintExternalAnnotator"/>
<usageTargetProvider implementation="org.jetbrains.android.AndroidUsagesTargetProvider"/>
<renameHandler implementation="org.jetbrains.android.AndroidRenameHandler" order="first"/>
<compileServer.plugin jar-path="jps/android-jps-plugin.jar"/>
<compileServer.plugin jar-path="android-rt.jar"/>
<compileServer.plugin jar-path="sdklib.jar"/>
<compileServer.plugin jar-path="../../../../../community/plugins/android/lib/sdklib.jar"/>
<compileServer.plugin jar-path="../../../../../plugins/android/lib/sdklib.jar"/>
</extensions>
<extensionPoints>
@@ -0,0 +1,98 @@
package org.jetbrains.android;
import com.intellij.ide.TitledHandler;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlTag;
import com.intellij.refactoring.rename.PsiElementRenameHandler;
import com.intellij.refactoring.rename.RenameDialog;
import com.intellij.refactoring.rename.RenameHandler;
import org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper;
import org.jetbrains.annotations.NotNull;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidRenameHandler implements RenameHandler, TitledHandler {
@Override
public boolean isAvailableOnDataContext(DataContext dataContext) {
final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
if (editor == null) {
return false;
}
final PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext);
if (file == null) {
return false;
}
return AndroidUsagesTargetProvider.findValueResourceTagInContext(editor, file) != null;
}
@Override
public boolean isRenaming(DataContext dataContext) {
return isAvailableOnDataContext(dataContext);
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
if (file == null || editor == null) {
return;
}
final XmlTag tag = AndroidUsagesTargetProvider.findValueResourceTagInContext(editor, file);
if (tag == null) {
return;
}
final XmlAttribute nameAttribute = tag.getAttribute("name");
if (nameAttribute == null) {
return;
}
final XmlAttributeValue attributeValue = nameAttribute.getValueElement();
if (attributeValue == null) {
return;
}
final RenameDialog dialog = new RenameDialog(project, new ValueResourceElementWrapper(attributeValue), null, editor);
if (ApplicationManager.getApplication().isUnitTestMode()) {
final String name = PsiElementRenameHandler.DEFAULT_NAME.getData(dataContext);
//noinspection TestOnlyProblems
dialog.performRename(name);
dialog.close(DialogWrapper.OK_EXIT_CODE);
}
else {
dialog.show();
}
}
@Override
public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
if (editor == null) {
return;
}
final PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext);
if (file == null) {
return;
}
invoke(project, editor, file, dataContext);
}
@Override
public String getActionTitle() {
return "Rename Android value resource";
}
}
@@ -0,0 +1,72 @@
package org.jetbrains.android;
import com.android.resources.ResourceFolderType;
import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.usages.UsageTarget;
import com.intellij.usages.UsageTargetProvider;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.resourceManagers.ResourceManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidUsagesTargetProvider implements UsageTargetProvider {
@Override
public UsageTarget[] getTargets(Editor editor, PsiFile file) {
if (editor == null || file == null) {
return UsageTarget.EMPTY_ARRAY;
}
final XmlTag tag = findValueResourceTagInContext(editor, file);
return tag != null
? new UsageTarget[]{new PsiElement2UsageTargetAdapter(tag)}
: UsageTarget.EMPTY_ARRAY;
}
@Override
public UsageTarget[] getTargets(PsiElement psiElement) {
return UsageTarget.EMPTY_ARRAY;
}
@Nullable
static XmlTag findValueResourceTagInContext(@NotNull Editor editor, @NotNull PsiFile file) {
if (!(file instanceof XmlFile)) {
return null;
}
final AndroidFacet facet = AndroidFacet.getInstance(file);
if (facet == null) {
return null;
}
if (!ResourceManager.isInResourceSubdirectory(file, ResourceFolderType.VALUES.getName())) {
return null;
}
final PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
if (element == null) {
return null;
}
final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
if (tag == null) {
return null;
}
final String name = tag.getAttributeValue("name");
if (name == null || name.length() == 0) {
return null;
}
final XmlTag parentTag = tag.getParentTag();
return parentTag != null && parentTag.getParentTag() == null ? tag : null;
}
}
@@ -0,0 +1,5 @@
<resources>
<caret><string name="hello">hello</string>
<item name="hi" type="string"/>
<string-array name="str_arr"></string-array>
</resources>
@@ -0,0 +1,5 @@
<resources>
<stri<caret>ng name="hello">hello</string>
<item name="hi" type="string"/>
<string-array name="str_arr"></string-array>
</resources>
@@ -0,0 +1,5 @@
<resources>
<string<caret> name="hello">hello</string>
<item name="hi" type="string"/>
<string-array name="str_arr"></string-array>
</resources>
@@ -0,0 +1,5 @@
<resources>
<string name="he<caret>llo">hello</string>
<item name="hi" type="string"/>
<string-array name="str_arr"></string-array>
</resources>
@@ -0,0 +1,5 @@
<resources>
<string name="hello"<caret>>hello</string>
<item name="hi" type="string"/>
<string-array name="str_arr"></string-array>
</resources>
@@ -0,0 +1,5 @@
<resources>
<string name="hello">he<caret>llo</string>
<item name="hi" type="string"/>
<string-array name="str_arr"></string-array>
</resources>
@@ -0,0 +1,5 @@
<resources>
<string name="hello">hello</s<caret>tring>
<item name="hi" type="string"/>
<string-array name="str_arr"></string-array>
</resources>
@@ -0,0 +1,5 @@
<resources>
<string name="hello">hello<<caret>/string>
<item name="hi" type="string"/>
<string-array name="str_arr"></string-array>
</resources>
@@ -0,0 +1,8 @@
<resources>
<string name="hello">hello</string>
<item name="hi" type="string"/>
<string-array name="str_arr">
<item>str1</item>
<item>str2</item>
</string-array>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:text="@string/str"/>
</LinearLayout>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:text="@string/str1"/>
</LinearLayout>
@@ -0,0 +1,3 @@
<resources>
<string name="s<caret>tr">HellO!</string>
</resources>
@@ -0,0 +1,3 @@
<resources>
<string name="str">He<caret>llO!</string>
</resources>
@@ -0,0 +1,3 @@
<resources>
<string name="str">HellO!</stri<caret>ng>
</resources>
@@ -0,0 +1,3 @@
<resources>
<s<caret>tring name="str">HellO!</string>
</resources>
@@ -17,21 +17,23 @@
package org.jetbrains.android;
import com.intellij.codeInsight.TargetElementUtilBase;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture;
import com.intellij.usageView.UsageInfo;
import com.intellij.usages.PsiElementUsageTarget;
import com.intellij.usages.UsageTarget;
import com.intellij.usages.UsageTargetUtil;
import org.jetbrains.annotations.NonNls;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
/**
* Created by IntelliJ IDEA.
* User: Eugene.Kudelevsky
* Date: Aug 5, 2009
* Time: 4:48:01 PM
* To change this template use File | Settings | File Templates.
* @author Eugene.Kudelevsky
*/
public class AndroidFindUsagesTest extends AndroidTestCase {
private static final String BASE_PATH = "/findUsages/";
@@ -39,13 +41,12 @@ public class AndroidFindUsagesTest extends AndroidTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
myFixture.copyFileToProject(BASE_PATH + "picture3.gif", "res/drawable/picture3.gif");
myFixture.copyFileToProject(BASE_PATH + "R.java", "gen/p1/p2/R.java");
}
public List<UsageInfo> findCodeUsages(String path) throws Throwable {
Collection<UsageInfo> usages = findElementAtCaret(path, myFixture, BASE_PATH);
public List<UsageInfo> findCodeUsages(String path, String pathInProject) throws Throwable {
Collection<UsageInfo> usages = findUsages(path, myFixture, pathInProject);
List<UsageInfo> result = new ArrayList<UsageInfo>();
for (UsageInfo usage : usages) {
if (!usage.isNonCodeUsage) {
@@ -56,70 +57,146 @@ public class AndroidFindUsagesTest extends AndroidTestCase {
}
public void testFileResource() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
myFixture.copyFileToProject(BASE_PATH + "styles.xml", "res/values/styles.xml");
Collection<UsageInfo> references = findCodeUsages("fu1_layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu1_layout.xml", "res/layout/fu1_layout.xml");
assertEquals(3, references.size());
}
public void testValueResource() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
Collection<UsageInfo> references = findCodeUsages("fu2_layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu2_layout.xml", "res/layout/fu2_layout.xml");
assertEquals(2, references.size());
}
public void testValueResource1() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu1_values.xml", "res/values/fu1_values.xml");
assertEquals(2, references.size());
}
public void testValueResource2() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu2_values.xml", "res/values/fu2_values.xml");
assertEquals(2, references.size());
}
public void testValueResource3() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu2_values.xml", "res/values/fu3_values.xml");
assertEquals(2, references.size());
}
public void testValueResource4() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu2_values.xml", "res/values/fu4_values.xml");
assertEquals(2, references.size());
}
public void testValueResource5() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu2_values.xml", "res/values/fu5_values.xml");
assertEquals(2, references.size());
}
public void testValueResource6() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu2_values.xml", "res/values/fu6_values.xml");
assertEquals(2, references.size());
}
public void testValueResource7() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu2_values.xml", "res/values/fu7_values.xml");
assertEquals(2, references.size());
}
public void testValueResource8() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu2_values.xml", "res/values/f8_values.xml");
assertEquals(2, references.size());
}
public void testValueItemResource() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
Collection<UsageInfo> references = findCodeUsages("fu5_layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu5_layout.xml", "res/layout/fu5_layout.xml");
assertEquals(2, references.size());
}
public void testFileResourceField() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("Fu3.java");
Collection<UsageInfo> references = findCodeUsages("Fu3.java", "src/p1/p2/Fu3.java");
assertEquals(2, references.size());
}
public void testValueResourceField() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("Fu4.java");
Collection<UsageInfo> references = findCodeUsages("Fu4.java", "src/p1/p2/Fu4.java");
assertEquals(2, references.size());
}
public void testValueItemResourceField() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("Fu6.java");
Collection<UsageInfo> references = findCodeUsages("Fu6.java", "src/p1/p2/Fu6.java");
assertEquals(2, references.size());
}
public void testIdResource() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
Collection<UsageInfo> references = findCodeUsages("fu7_layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu7_layout.xml", "res/layout/fu7_layout.xml");
assertEquals(2, references.size());
}
public void testIdResourceField() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
myFixture.copyFileToProject(BASE_PATH + "layout.xml", "res/layout/layout.xml");
Collection<UsageInfo> references = findCodeUsages("Fu8.java");
Collection<UsageInfo> references = findCodeUsages("Fu8.java", "src/p1/p2/Fu8.java");
assertEquals(2, references.size());
}
public void testIdResourceDeclaration() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
Collection<UsageInfo> references = findCodeUsages("fu9_layout.xml");
Collection<UsageInfo> references = findCodeUsages("fu9_layout.xml", "res/layout/fu9_layout.xml");
assertEquals(2, references.size());
}
public void testStringArray() throws Throwable {
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
myFixture.copyFileToProject(BASE_PATH + "Class.java", "src/p1/p2/Class.java");
Collection<UsageInfo> references = findCodeUsages("stringArray.xml");
Collection<UsageInfo> references = findCodeUsages("stringArray.xml", "res/layout/stringArray.xml");
assertEquals(2, references.size());
}
private static Collection<UsageInfo> findElementAtCaret(String fileName, JavaCodeInsightTestFixture fixture, String basePath) throws Throwable {
String newFilePath = "res/layout/" + fileName;
VirtualFile file = fixture.copyFileToProject(basePath + fileName, newFilePath);
return findUsages(file, fixture);
private static Collection<UsageInfo> findUsages(String fileName, final JavaCodeInsightTestFixture fixture, String newFilePath)
throws Throwable {
VirtualFile file = fixture.copyFileToProject(BASE_PATH + fileName, newFilePath);
fixture.configureFromExistingVirtualFile(file);
final UsageTarget[] targets = UsageTargetUtil.findUsageTargets(new DataProvider() {
@Override
public Object getData(@NonNls String dataId) {
return ((EditorEx)fixture.getEditor()).getDataContext().getData(dataId);
}
});
assert targets != null && targets.length > 0 && targets[0] instanceof PsiElementUsageTarget;
return fixture.findUsages(((PsiElementUsageTarget)targets[0]).getElement());
}
public static Collection<UsageInfo> findUsages(VirtualFile file, JavaCodeInsightTestFixture fixture) throws Exception {
@@ -18,8 +18,10 @@ package org.jetbrains.android;
import com.android.sdklib.SdkConstants;
import com.intellij.codeInsight.TargetElementUtilBase;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
@@ -28,8 +30,10 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.refactoring.PackageWrapper;
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor;
import com.intellij.refactoring.move.moveClassesOrPackages.SingleSourceRootMoveDestination;
import com.intellij.refactoring.rename.RenameProcessor;
import com.intellij.refactoring.rename.RenamePsiElementProcessor;
import com.intellij.refactoring.rename.*;
import org.jetbrains.annotations.NonNls;
import java.io.IOException;
/**
* Created by IntelliJ IDEA.
@@ -132,6 +136,53 @@ public class AndroidRenameTest extends AndroidTestCase {
myFixture.checkResultByFile("res/values/strings.xml", BASE_PATH + "strings_after.xml", true);
}
public void testValueResource1() throws Throwable {
doTestStringRename("strings1.xml");
}
public void testValueResource2() throws Throwable {
doTestStringRename("strings2.xml");
}
public void testValueResource3() throws Throwable {
doTestStringRename("strings3.xml");
}
public void testValueResource4() throws Throwable {
doTestStringRename("strings4.xml");
}
private void doTestStringRename(String fileName) throws IOException {
createManifest();
VirtualFile file = myFixture.copyFileToProject(BASE_PATH + fileName, "res/values/strings.xml");
myFixture.configureFromExistingVirtualFile(file);
myFixture.copyFileToProject(BASE_PATH + "layoutStrUsage.xml", "res/layout/layoutStrUsage.xml");
myFixture.copyFileToProject(BASE_PATH + "R2.java", R_JAVA_PATH);
findHandlerAndDoRename();
myFixture.checkResultByFile(BASE_PATH + "strings_after.xml");
myFixture.checkResultByFile(R_JAVA_PATH, BASE_PATH + "R_value_after.java", true);
myFixture.checkResultByFile("res/layout/layoutStrUsage.xml", BASE_PATH + "layoutStrUsage_after.xml", true);
}
private void findHandlerAndDoRename() throws IOException {
final DataContext editorContext = ((EditorEx)myFixture.getEditor()).getDataContext();
final DataContext context = new DataContext() {
@Override
public Object getData(@NonNls String dataId) {
return PsiElementRenameHandler.DEFAULT_NAME.getName().equals(dataId)
? "str1"
: editorContext.getData(dataId);
}
};
final RenameHandler renameHandler = RenameHandlerRegistry.getInstance().getRenameHandler(context);
assertNotNull(renameHandler);
renameHandler.invoke(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile(), context);
}
public void testJavaReferenceToFileResource() throws Throwable {
createManifest();
VirtualFile file = myFixture.copyFileToProject(BASE_PATH + "R3.java", R_JAVA_PATH);
+1 -1
View File
@@ -37,7 +37,7 @@
</group>
<group id="GitRepositoryActions">
<action id="Git.Branches" class="git4idea.ui.branch.GitBranchesAction" text="_Branches"/>
<action id="Git.Branches" class="git4idea.ui.branch.GitBranchesAction" text="_Branches" icon="/icons/branch.png"/>
<separator/>
<action id="Git.Tag" class="git4idea.actions.GitTag" text="Tag Files..."/>
@@ -34,6 +34,7 @@ import com.intellij.util.Function;
import com.intellij.util.ui.UIUtil;
import git4idea.*;
import git4idea.commands.GitMessageWithFilesDetector;
import git4idea.config.GitVcsSettings;
import git4idea.merge.GitConflictResolver;
import git4idea.repo.GitRepository;
import git4idea.util.UntrackedFilesNotifier;
@@ -59,18 +60,22 @@ abstract class GitBranchOperation {
@NotNull protected final Project myProject;
@NotNull private final Collection<GitRepository> myRepositories;
@NotNull private final String myCurrentBranchOrRev;
@NotNull private final ProgressIndicator myIndicator;
private final GitVcsSettings mySettings;
@NotNull private final Collection<GitRepository> mySuccessfulRepositories;
@NotNull private final Collection<GitRepository> myRemainingRepositories;
protected GitBranchOperation(@NotNull Project project, @NotNull Collection<GitRepository> repositories,
@NotNull ProgressIndicator indicator) {
@NotNull String currentBranchOrRev, @NotNull ProgressIndicator indicator) {
myProject = project;
myRepositories = repositories;
myCurrentBranchOrRev = currentBranchOrRev;
myIndicator = indicator;
mySuccessfulRepositories = new ArrayList<GitRepository>();
myRemainingRepositories = new ArrayList<GitRepository>(myRepositories);
mySettings = GitVcsSettings.getInstance(myProject);
}
protected abstract void execute();
@@ -159,7 +164,7 @@ abstract class GitBranchOperation {
NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "", message, NotificationType.INFORMATION);
}
protected void notifySuccess() {
protected final void notifySuccess() {
notifySuccess(getSuccessMessage());
}
@@ -242,6 +247,20 @@ abstract class GitBranchOperation {
return pluralize("repository", getSuccessfulRepositories().size());
}
/**
* Updates the recently visited branch in the settings.
* This is to be performed after successful checkout operation.
*/
protected void updateRecentBranch() {
if (getRepositories().size() == 1) {
GitRepository repository = myRepositories.iterator().next();
mySettings.setRecentBranchOfRepository(repository.getRoot().getPath(), myCurrentBranchOrRev);
}
else {
mySettings.setRecentCommonBranch(myCurrentBranchOrRev);
}
}
private void showUnmergedFilesDialogWithRollback() {
final AtomicBoolean ok = new AtomicBoolean();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@@ -81,7 +81,7 @@ public final class GitBranchOperationsProcessor {
}
@NotNull
private String getCurrentBranch() {
private String getCurrentBranchOrRev() {
if (myRepositories.size() > 1) {
GitMultiRootBranchConfig multiRootBranchConfig = new GitMultiRootBranchConfig(myRepositories);
String currentBranch = multiRootBranchConfig.getCurrentBranch();
@@ -121,7 +121,7 @@ public final class GitBranchOperationsProcessor {
}
private void doCheckoutNewBranch(@NotNull final String name, @NotNull ProgressIndicator indicator) {
new GitCheckoutNewBranchOperation(myProject, myRepositories, name, getCurrentBranch(), indicator).execute();
new GitCheckoutNewBranchOperation(myProject, myRepositories, name, getCurrentBranchOrRev(), indicator).execute();
}
/**
@@ -162,7 +162,7 @@ public final class GitBranchOperationsProcessor {
}
private void doCheckout(@NotNull ProgressIndicator indicator, @NotNull String reference, @Nullable String newBranch) {
new GitCheckoutOperation(myProject, myRepositories, reference, newBranch, getCurrentBranch(), indicator).execute();
new GitCheckoutOperation(myProject, myRepositories, reference, newBranch, getCurrentBranchOrRev(), indicator).execute();
}
public void deleteBranch(final String branchName) {
@@ -174,7 +174,7 @@ public final class GitBranchOperationsProcessor {
}
private void doDelete(final String branchName, ProgressIndicator indicator) {
new GitDeleteBranchOperation(myProject, myRepositories, branchName, getCurrentBranch(), indicator).execute();
new GitDeleteBranchOperation(myProject, myRepositories, branchName, getCurrentBranchOrRev(), indicator).execute();
}
/**
@@ -197,7 +197,7 @@ public final class GitBranchOperationsProcessor {
LOG.error("The task to get compare info didn't finish. Repositories: \n" + myRepositories + "\nbranch name: " + branchName);
return;
}
displayCompareDialog(branchName, getCurrentBranch(), myCompareInfo);
displayCompareDialog(branchName, getCurrentBranchOrRev(), myCompareInfo);
}
}.runInBackground();
}
@@ -247,7 +247,7 @@ public final class GitBranchOperationsProcessor {
for (GitRepository repository : myRepositories) {
revisions.put(repository, repository.getCurrentRevision());
}
new GitMergeOperation(myProject, myRepositories, branchName, getCurrentBranch(), revisions, indicator).execute();
new GitMergeOperation(myProject, myRepositories, branchName, getCurrentBranchOrRev(), mySelectedRepository, revisions, indicator).execute();
}
/**
@@ -44,9 +44,8 @@ class GitCheckoutNewBranchOperation extends GitBranchOperation {
@NotNull private final String myPreviousBranch;
GitCheckoutNewBranchOperation(@NotNull Project project, @NotNull Collection<GitRepository> repositories,
@NotNull String newBranchName, @NotNull String previousBranch,
@NotNull ProgressIndicator indicator) {
super(project, repositories, indicator);
@NotNull String newBranchName, @NotNull String previousBranch, @NotNull ProgressIndicator indicator) {
super(project, repositories, previousBranch, indicator);
myNewBranchName = newBranchName;
myProject = project;
myPreviousBranch = previousBranch;
@@ -77,6 +76,7 @@ class GitCheckoutNewBranchOperation extends GitBranchOperation {
if (!fatalErrorHappened) {
notifySuccess();
updateRecentBranch();
}
}
@@ -59,7 +59,7 @@ class GitCheckoutOperation extends GitBranchOperation {
GitCheckoutOperation(@NotNull Project project, @NotNull Collection<GitRepository> repositories,
@NotNull String startPointReference, @Nullable String newBranch, @NotNull String previousBranch,
@NotNull ProgressIndicator indicator) {
super(project, repositories, indicator);
super(project, repositories, previousBranch, indicator);
myStartPointReference = startPointReference;
myNewBranch = newBranch;
myPreviousBranch = previousBranch;
@@ -104,10 +104,11 @@ class GitCheckoutOperation extends GitBranchOperation {
if (!fatalErrorHappened) {
notifySuccess();
updateRecentBranch();
}
}
private boolean smartCheckoutOrNotify(@NotNull GitRepository repository,
private boolean smartCheckoutOrNotify(@NotNull GitRepository repository,
@NotNull GitMessageWithFilesDetector localChangesOverwrittenByCheckout) {
Pair<List<GitRepository>, List<Change>> conflictingRepositoriesAndAffectedChanges =
getConflictingRepositoriesAndAffectedChanges(repository, localChangesOverwrittenByCheckout, myPreviousBranch, myStartPointReference);
@@ -53,8 +53,8 @@ class GitDeleteBranchOperation extends GitBranchOperation {
private final String myCurrentBranch;
GitDeleteBranchOperation(@NotNull Project project, @NotNull Collection<GitRepository> repositories,
@NotNull String branchName, @NotNull String currentBranch, @NotNull ProgressIndicator indicator) {
super(project, repositories, indicator);
@NotNull String branchName, @NotNull String currentBranch, @NotNull ProgressIndicator indicator) {
super(project, repositories, currentBranch, indicator);
myBranchName = branchName;
myCurrentBranch = currentBranch;
}
@@ -15,6 +15,8 @@
*/
package git4idea.branch;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -35,6 +37,7 @@ import git4idea.repo.GitRepository;
import git4idea.util.GitPreservingProcess;
import org.jetbrains.annotations.NotNull;
import javax.swing.event.HyperlinkEvent;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -52,6 +55,7 @@ class GitMergeOperation extends GitBranchOperation {
@NotNull private final ChangeListManager myChangeListManager;
@NotNull private final String myBranchToMerge;
@NotNull private final String myCurrentBranch;
@NotNull private final GitRepository myCurrentRepository;
@NotNull private final Map<GitRepository, String> myCurrentRevisionsBeforeMerge;
// true in value if unstash will be needed after resolving conflicts.
@@ -59,13 +63,13 @@ class GitMergeOperation extends GitBranchOperation {
private GitPreservingProcess myPreservingProcess;
protected GitMergeOperation(@NotNull Project project, @NotNull Collection<GitRepository> repositories,
@NotNull String branchToMerge,
@NotNull String currentBranch,
@NotNull String branchToMerge, @NotNull String currentBranch, @NotNull GitRepository currentRepository,
@NotNull Map<GitRepository, String> currentRevisionsBeforeMerge,
@NotNull ProgressIndicator indicator) {
super(project, repositories, indicator);
super(project, repositories, currentBranch, indicator);
myBranchToMerge = branchToMerge;
myCurrentBranch = currentBranch;
myCurrentRepository = currentRepository;
myCurrentRevisionsBeforeMerge = currentRevisionsBeforeMerge;
myChangeListManager = ChangeListManager.getInstance(myProject);
}
@@ -126,13 +130,28 @@ class GitMergeOperation extends GitBranchOperation {
notifySuccess();
}
else {
notifySuccess("Already up-to-date.");
notifySuccess("Already up-to-date");
}
}
restoreLocalChanges();
}
@Override
protected void notifySuccess(@NotNull String message) {
String description = message + "<br/><a href='delete'>Delete " + myBranchToMerge + "</a>";
NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "", description, NotificationType.INFORMATION,
new NotificationListener() {
@Override
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED && event.getDescription().equalsIgnoreCase("delete")) {
new GitBranchOperationsProcessor(myProject, new ArrayList<GitRepository>(getRepositories()), myCurrentRepository).
deleteBranch(myBranchToMerge);
}
}
});
}
private boolean resolveConflicts() {
if (!myConflictedRepositories.isEmpty()) {
GitMerger merger = new GitMerger(myProject);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* 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.
@@ -17,7 +17,6 @@ package git4idea.branch;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ui.ChangesBrowser;
import com.intellij.ui.IdeBorderFactory;
@@ -31,6 +30,8 @@ import java.awt.event.ActionEvent;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import static com.intellij.openapi.util.text.StringUtil.capitalize;
/**
* The dialog that is shown when the error
* "Your local changes to the following files would be overwritten by merge/checkout"
@@ -46,7 +47,7 @@ class GitSmartOperationDialog extends DialogWrapper {
private final Project myProject;
private final List<Change> myChanges;
@NotNull private final String myCapitalizedOperationTitle;
@NotNull private final String myOperationTitle;
private final boolean myForceButton;
/**
@@ -71,10 +72,10 @@ class GitSmartOperationDialog extends DialogWrapper {
super(project);
myProject = project;
myChanges = changes;
myCapitalizedOperationTitle = StringUtil.capitalize(operationTitle);
myOperationTitle = operationTitle;
myForceButton = forceButton;
setOKButtonText("Smart " + myCapitalizedOperationTitle);
setCancelButtonText("Don't " + myCapitalizedOperationTitle);
setOKButtonText("Smart " + capitalize(myOperationTitle));
setCancelButtonText("Don't " + capitalize(myOperationTitle));
getCancelAction().putValue(FOCUSED_ACTION, Boolean.TRUE);
init();
}
@@ -82,15 +83,15 @@ class GitSmartOperationDialog extends DialogWrapper {
@Override
protected Action[] createLeftSideActions() {
if (myForceButton) {
return new Action[] {new ForceCheckoutAction(myCapitalizedOperationTitle) };
return new Action[] {new ForceCheckoutAction(myOperationTitle) };
}
return new Action[0];
}
@Override
protected JComponent createNorthPanel() {
JBLabel description = new JBLabel("<html>Your local changes to the following files would be overwritten by checkout.<br/>" +
"IDEA can stash the changes, checkout and unstash them after that.</html>");
JBLabel description = new JBLabel("<html>Your local changes to the following files would be overwritten by " + myOperationTitle +
".<br/>IDEA can stash the changes, " + myOperationTitle + " and unstash them after that.</html>");
description.setBorder(IdeBorderFactory.createEmptyBorder(0, 0, 10, 0));
return description;
}
@@ -112,7 +113,7 @@ class GitSmartOperationDialog extends DialogWrapper {
private class ForceCheckoutAction extends AbstractAction {
ForceCheckoutAction(@NotNull String operationTitle) {
super("Force " + operationTitle);
super("&Force " + capitalize(operationTitle));
}
@Override
@@ -26,7 +26,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Git VCS settings
@@ -70,6 +72,8 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
public boolean PUSH_AUTO_UPDATE = false;
public GitBranchSyncSetting SYNC_SETTING = GitBranchSyncSetting.NOT_DECIDED;
public String RECENT_GIT_ROOT_PATH = null;
public Map<String, String> RECENT_BRANCH_BY_REPOSITORY = new HashMap<String, String>();
public String RECENT_COMMON_BRANCH = null;
}
public GitVcsSettings(GitVcsApplicationSettings appSettings) {
@@ -80,11 +84,7 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
return myAppSettings;
}
@Nullable
public static GitVcsSettings getInstance(Project project) {
if (project == null || project.isDisposed()) {
return null;
}
return PeriodicalTasksCloser.getInstance().safeGetService(project, GitVcsSettings.class);
}
@@ -172,4 +172,22 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
myState.RECENT_GIT_ROOT_PATH = recentGitRootPath;
}
@NotNull
public Map<String, String> getRecentBranchesByRepository() {
return myState.RECENT_BRANCH_BY_REPOSITORY;
}
public void setRecentBranchOfRepository(@NotNull String repositoryPath, @NotNull String branch) {
myState.RECENT_BRANCH_BY_REPOSITORY.put(repositoryPath, branch);
}
@Nullable
public String getRecentCommonBranch() {
return myState.RECENT_COMMON_BRANCH;
}
public void setRecentCommonBranch(@NotNull String branch) {
myState.RECENT_COMMON_BRANCH = branch;
}
}
@@ -51,6 +51,11 @@ public abstract class GitChangesSaver {
protected GitConflictResolver.Params myParams;
/**
* Refreshes files changed during save or load.
*/
public abstract void refresh();
/**
* Returns an instance of the proper GitChangesSaver depending on the chosen save changes policy.
* @return {@link GitStashChangesSaver}, {@link GitShelveChangesSaver} or {@link GitDumbChangesSaver}
@@ -89,11 +89,19 @@ public class GitShelveChangesSaver extends GitChangesSaver {
return myShelvedChangeList != null;
}
@Override public String getSaverName() {
@Override
public String getSaverName() {
return "shelf";
}
@Override protected void showSavedChanges() {
@Override
protected void showSavedChanges() {
myShelveViewManager.activateView(myShelvedChangeList);
}
@Override
public void refresh() {
// refreshed inside shelve manager
}
}
@@ -35,8 +35,8 @@ import git4idea.commands.*;
import git4idea.config.GitVcsSettings;
import git4idea.convert.GitFileSeparatorConverter;
import git4idea.merge.GitConflictResolver;
import git4idea.util.GitUIUtil;
import git4idea.ui.GitUnstashDialog;
import git4idea.util.GitUIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -77,11 +77,21 @@ public class GitStashChangesSaver extends GitChangesSaver {
}
public void load() throws VcsException {
Collection<VirtualFile> conflictedRoots = new ArrayList<VirtualFile>();
for (VirtualFile root : myStashedRoots) {
loadRoot(root);
boolean conflict = loadRoot(root);
if (conflict) {
conflictedRoots.add(root);
}
}
boolean conflictsResolved = new UnstashConflictResolver(myProject, myStashedRoots, myParams).merge();
if (conflictsResolved) {
LOG.info("load: all conflicts resolved, dropping stash in " + myStashedRoots);
for (VirtualFile root : conflictedRoots) {
GitStashUtils.dropStash(myProject, root);
}
}
// we'll refresh more but this way we needn't compute what files under roots etc
LocalFileSystem.getInstance().refreshIoFiles(myChangeManager.getAffectedPaths());
}
@Override
@@ -89,14 +99,22 @@ public class GitStashChangesSaver extends GitChangesSaver {
return !myStashedRoots.isEmpty();
}
@Override public String getSaverName() {
@Override
public String getSaverName() {
return "stash";
}
@Override protected void showSavedChanges() {
@Override
protected void showSavedChanges() {
GitUnstashDialog.showUnstashDialog(myProject, new ArrayList<VirtualFile>(myStashedRoots), myStashedRoots.iterator().next(), new HashSet<VirtualFile>());
}
@Override
public void refresh() {
// we'll refresh more but this way we needn't compute what files under roots etc
LocalFileSystem.getInstance().refreshIoFiles(myChangeManager.getAffectedPaths());
}
private void stash(Collection<VirtualFile> roots) throws VcsException {
for (VirtualFile root : roots) {
final String message = GitHandlerUtil.formatOperationName("Stashing changes from", root);
@@ -122,7 +140,11 @@ public class GitStashChangesSaver extends GitChangesSaver {
}
}
private void loadRoot(final VirtualFile root) throws VcsException {
/**
* Returns true if the root was loaded with conflict.
* False is returned in all other cases: in the case of success and in case of some other error.
*/
private boolean loadRoot(final VirtualFile root) throws VcsException {
LOG.info("loadRoot " + root);
myProgressIndicator.setText(GitHandlerUtil.formatOperationName("Unstashing changes to", root));
final GitLineHandler handler = new GitLineHandler(myProject, root, GitCommand.STASH);
@@ -159,26 +181,21 @@ public class GitStashChangesSaver extends GitChangesSaver {
if (failure.get()) {
if (conflict.get()) {
boolean conflictsResolved = new UnstashConflictResolver(myProject, root, myStashedRoots, myParams).merge();
if (conflictsResolved) {
LOG.info("loadRoot " + root + " conflicts resolved, dropping stash");
GitStashUtils.dropStash(myProject, root);
}
return true;
} else {
LOG.info("unstash failed " + handler.errors());
GitUIUtil.notifyImportantError(myProject, "Couldn't unstash", "<br/>" + GitUIUtil.stringifyErrors(handler.errors()));
}
}
return false;
}
private static class UnstashConflictResolver extends GitConflictResolver {
private final VirtualFile myRoot;
private final Set<VirtualFile> myStashedRoots;
public UnstashConflictResolver(@NotNull Project project, @NotNull VirtualFile root, @NotNull Set<VirtualFile> stashedRoots, @Nullable Params params) {
super(project, Collections.singleton(root), makeParamsOrUse(params));
myRoot = root;
public UnstashConflictResolver(@NotNull Project project, @NotNull Set<VirtualFile> stashedRoots, @Nullable Params params) {
super(project, stashedRoots, makeParamsOrUse(params));
myStashedRoots = stashedRoots;
}
@@ -206,7 +223,7 @@ public class GitStashChangesSaver extends GitChangesSaver {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
if (event.getDescription().equals("saver")) {
// we don't use #showSavedChanges to specify unmerged root first
GitUnstashDialog.showUnstashDialog(myProject, new ArrayList<VirtualFile>(myStashedRoots), myRoot,
GitUnstashDialog.showUnstashDialog(myProject, new ArrayList<VirtualFile>(myStashedRoots), myStashedRoots.iterator().next(),
new HashSet<VirtualFile>());
} else if (event.getDescription().equals("resolve")) {
mergeNoProceed();
@@ -27,6 +27,7 @@ import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.IconLoader;
import com.intellij.ui.popup.PopupFactoryImpl;
import com.intellij.ui.popup.WizardPopup;
@@ -88,10 +89,33 @@ class GitBranchPopup {
String title = createPopupTitle(currentRepository);
Condition<AnAction> preselectActionCondition = new Condition<AnAction>() {
@Override
public boolean value(AnAction action) {
if (action instanceof GitBranchPopupActions.LocalBranchActions) {
GitBranchPopupActions.LocalBranchActions branchAction = (GitBranchPopupActions.LocalBranchActions)action;
String branchName = branchAction.getBranchName();
String recentBranch;
List<GitRepository> repositories = branchAction.getRepositories();
if (repositories.size() == 1) {
recentBranch = myVcsSettings.getRecentBranchesByRepository().get(repositories.iterator().next().getRoot().getPath());
}
else {
recentBranch = myVcsSettings.getRecentCommonBranch();
}
if (recentBranch != null && recentBranch.equals(branchName)) {
return true;
}
}
return false;
}
};
myPopup = new PopupFactoryImpl.ActionGroupPopup(
title, createActions(),
SimpleDataContext.getProjectContext(project),
false, false, false, true, null, -1, null, null) {
false, false, false, true, null, -1, preselectActionCondition, null) {
@Override
protected WizardPopup createPopup(WizardPopup parent, PopupStep step, Object parentValue) {
WizardPopup popup = super.createPopup(parent, step, parentValue);
@@ -180,6 +180,16 @@ class GitBranchPopupActions {
}
}
@NotNull
List<GitRepository> getRepositories() {
return myRepositories;
}
@NotNull
public String getBranchName() {
return myBranchName;
}
@NotNull
@Override
public AnAction[] getChildren(@Nullable AnActionEvent e) {
@@ -215,6 +215,7 @@ public class GitUpdateProcess {
final ContinuationFinalTasksInserter finalTasksInserter = new ContinuationFinalTasksInserter(context);
finalTasksInserter.allNextAreFinal();
mySaver.restoreLocalChanges(context);
mySaver.refresh();
finalTasksInserter.removeFinalPropertyAdder();
}
@@ -492,7 +492,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase {
public void merge_simple_without_problems() throws Exception {
prepareBranchWithCommit("feature", myUltimate, myCommunity, myContrib);
doMerge("feature");
assertNotify(NotificationType.INFORMATION, "Merged feature to master");
assertNotify(NotificationType.INFORMATION, "Merged feature to master<br/>Delete feature");
assertFile(myUltimate, "unmerged_branch_file", "content");
assertFile(myCommunity, "unmerged_branch_file", "content");
@@ -514,7 +514,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase {
doMerge("master2");
assertNotify(NotificationType.INFORMATION, "Already up-to-date.");
assertNotify(NotificationType.INFORMATION, "Already up-to-date<br/>Delete master2");
}
@Test
@@ -525,7 +525,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase {
doMerge("master2");
assertNotify(NotificationType.INFORMATION, "Merged master2 to master");
assertNotify(NotificationType.INFORMATION, "Merged master2 to master<br/>Delete master2");
assertFile(myCommunity, "unmerged_branch_file", "content");
assertNull(myUltimate.getRoot().findChild("unmerged_branch_file"));
}
@@ -89,14 +89,14 @@ public class SvnChangesCorrectlyRefreshedTest extends SvnTestCase {
//ChangeListManagerImpl.DEBUG = true;
final SubTree subTree = new SubTree(myWorkingCopyDir);
checkin();
sleep(1000);
sleep(100);
editFileInCommand(myProject, subTree.myS1File, "new");
editFileInCommand(myProject, subTree.myS1File, "new content");
final CharSequence text1 = LoadTextUtil.loadText(subTree.myS1File);
Assert.assertEquals("new", text1.toString());
Assert.assertEquals("new content", text1.toString());
sleep(1000);
sleep(100);
LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(subTree.myS1File.getPath()));
VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty();
clManager.ensureUpToDate(false);
@@ -23,6 +23,7 @@
package com.intellij.xml.refactoring;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.TitledHandler;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
@@ -45,7 +46,7 @@ import com.intellij.xml.impl.schema.AnyXmlElementDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class XmlTagRenameHandler implements RenameHandler {
public class XmlTagRenameHandler implements RenameHandler, TitledHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.xml.refactoring.XmlTagRenameHandler");
@@ -74,6 +75,11 @@ public class XmlTagRenameHandler implements RenameHandler {
return isAvailableOnDataContext(dataContext);
}
@Override
public String getActionTitle() {
return "Rename XML tag";
}
private static boolean isInplaceRenameAvailable(final Editor editor) {
return editor.getSettings().isVariableInplaceRenameEnabled();
}