mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-80865 extract as include refactoring
This commit is contained in:
+18
-9
@@ -9,30 +9,39 @@ import com.intellij.psi.xml.XmlTag;
|
||||
import org.jetbrains.android.refactoring.AndroidRefactoringContextProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidDesignerRefactoringContextProvider implements AndroidRefactoringContextProvider {
|
||||
@NotNull
|
||||
@Override
|
||||
public XmlTag getComponentTag(@NotNull DataContext dataContext) {
|
||||
public XmlTag[] getComponentTags(@NotNull DataContext dataContext) {
|
||||
final EditableArea area = EditableArea.DATA_KEY.getData(dataContext);
|
||||
|
||||
if (area == null) {
|
||||
return null;
|
||||
return XmlTag.EMPTY;
|
||||
}
|
||||
final List<RadComponent> selection = area.getSelection();
|
||||
|
||||
if (selection.size() != 1) {
|
||||
return null;
|
||||
if (selection.size() == 0) {
|
||||
return XmlTag.EMPTY;
|
||||
}
|
||||
final RadComponent component = selection.get(0);
|
||||
final List<XmlTag> tags = new ArrayList<XmlTag>(selection.size());
|
||||
|
||||
if (!(component instanceof RadViewComponent)) {
|
||||
return null;
|
||||
for (RadComponent component : selection) {
|
||||
if (!(component instanceof RadViewComponent)) {
|
||||
return XmlTag.EMPTY;
|
||||
}
|
||||
final XmlTag tag = ((RadViewComponent)component).getTag();
|
||||
|
||||
if (tag == null || tag.equals(EmptyXmlTag.INSTANCE)) {
|
||||
return XmlTag.EMPTY;
|
||||
}
|
||||
tags.add(tag);
|
||||
}
|
||||
final XmlTag tag = ((RadViewComponent)component).getTag();
|
||||
return tag != null && !tag.equals(EmptyXmlTag.INSTANCE) ? tag : null;
|
||||
return tags.toArray(new XmlTag[tags.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -60,6 +60,7 @@ import com.intellij.util.ThrowableConsumer;
|
||||
import com.intellij.util.ThrowableRunnable;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.maven.AndroidMavenUtil;
|
||||
import org.jetbrains.android.refactoring.AndroidExtractAsIncludeAction;
|
||||
import org.jetbrains.android.refactoring.AndroidExtractStyleAction;
|
||||
import org.jetbrains.android.refactoring.AndroidInlineStyleReferenceAction;
|
||||
import org.jetbrains.android.sdk.AndroidPlatform;
|
||||
@@ -163,10 +164,13 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel {
|
||||
final ActionManager manager = ActionManager.getInstance();
|
||||
|
||||
AnAction action = manager.getAction(AndroidExtractStyleAction.ACTION_ID);
|
||||
group.add(new AndroidRefactoringActionWrapper("_Extract style", action));
|
||||
group.add(new AndroidRefactoringActionWrapper("_Extract Style", action));
|
||||
|
||||
action = manager.getAction(AndroidInlineStyleReferenceAction.ACTION_ID);
|
||||
group.add(new AndroidRefactoringActionWrapper("_Inline style", action));
|
||||
group.add(new AndroidRefactoringActionWrapper("_Inline Style", action));
|
||||
|
||||
action = manager.getAction(AndroidExtractAsIncludeAction.ACTION_ID);
|
||||
group.add(new AndroidRefactoringActionWrapper("E_xtract Layout", action));
|
||||
return group;
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -34,8 +34,7 @@ import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBTabbedPane;
|
||||
@@ -246,10 +245,10 @@ public class ResourceDialog extends DialogWrapper implements TreeSelectionListen
|
||||
|
||||
private void createNewResourceFile(ResourceType resourceType) {
|
||||
AndroidFacet facet = AndroidFacet.getInstance(myModule);
|
||||
PsiElement[] elements = CreateResourceFileAction.createFileResource(facet, resourceType, null, true);
|
||||
XmlFile newFile = CreateResourceFileAction.createFileResource(facet, resourceType, null, true);
|
||||
|
||||
if (elements.length == 1) {
|
||||
String name = ((PsiFile)elements[0]).getName();
|
||||
if (newFile != null) {
|
||||
String name = newFile.getName();
|
||||
int index = name.lastIndexOf('.');
|
||||
if (index != -1) {
|
||||
name = name.substring(0, index);
|
||||
|
||||
@@ -425,4 +425,5 @@ android.extract.style.title=Extract Android Style
|
||||
android.inline.style.title=Inline Android Style
|
||||
android.inline.style.command.name=Inline Style ''{0}''
|
||||
android.inline.style.inline.all.text=Inline &all references and remove the style
|
||||
android.inline.style.inline.this.text=Inline &this usage and keep the style
|
||||
android.inline.style.inline.this.text=Inline &this usage and keep the style
|
||||
android.extract.as.include.title=Extract Android Layout
|
||||
@@ -82,10 +82,14 @@
|
||||
icon="/icons/attachDebugger.png">
|
||||
<add-to-group group-id="ToolbarRunGroup" anchor="after" relative-to-action="RunnerActions"/>
|
||||
</action>
|
||||
<action id="AndroidExtractStyleAction" class="org.jetbrains.android.refactoring.AndroidExtractStyleAction" text="Extract St_yle..."
|
||||
<action id="AndroidExtractStyleAction" class="org.jetbrains.android.refactoring.AndroidExtractStyleAction" text="St_yle..."
|
||||
description="Pull out style-related attributes from layout and extract them as a new style">
|
||||
<add-to-group group-id="IntroduceActionsGroup"/>
|
||||
</action>
|
||||
<action id="AndroidExtractAsIncludeAction" class="org.jetbrains.android.refactoring.AndroidExtractAsIncludeAction"
|
||||
text="_Layout..." description="Extract one or more views into a separate layout">
|
||||
<add-to-group group-id="IntroduceActionsGroup"/>
|
||||
</action>
|
||||
<action id="AndroidInlineStyleReferenceAction" class="org.jetbrains.android.refactoring.AndroidInlineStyleReferenceAction"
|
||||
text="Inline _Style..." description="Inlines Android style">
|
||||
<add-to-group group-id="RefactoringMenu"/>
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidResourceUtil;
|
||||
@@ -91,11 +92,24 @@ public class CreateResourceFileAction extends CreateElementActionBase {
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static XmlFile createFileResource(@NotNull AndroidFacet facet,
|
||||
@NotNull final ResourceType resType,
|
||||
@Nullable String resName,
|
||||
boolean chooseResName) {
|
||||
final PsiElement[] elements = doCreateFileResource(facet, resType, resName, chooseResName);
|
||||
if (elements.length == 0) {
|
||||
return null;
|
||||
}
|
||||
assert elements.length == 1 && elements[0] instanceof XmlFile;
|
||||
return (XmlFile)elements[0];
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PsiElement[] createFileResource(@NotNull AndroidFacet facet,
|
||||
@NotNull final ResourceType resType,
|
||||
@Nullable String resName,
|
||||
boolean chooseResName) {
|
||||
private static PsiElement[] doCreateFileResource(@NotNull AndroidFacet facet,
|
||||
@NotNull final ResourceType resType,
|
||||
@Nullable String resName,
|
||||
boolean chooseResName) {
|
||||
final CreateResourceFileAction action = getInstance();
|
||||
|
||||
final String subdirName;
|
||||
|
||||
+3
-3
@@ -14,9 +14,9 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.android.actions.CreateResourceFileAction;
|
||||
import org.jetbrains.android.actions.CreateTypedResourceFileAction;
|
||||
@@ -73,9 +73,9 @@ public class CreateFileResourceQuickFix implements LocalQuickFix, IntentionActio
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
final PsiElement[] createdElements =
|
||||
final XmlFile newFile =
|
||||
CreateResourceFileAction.createFileResource(myFacet, myResourceType, myResourceName + ".xml", myChooseResName);
|
||||
if (createdElements.length > 0) {
|
||||
if (newFile != null) {
|
||||
UndoUtil.markPsiFileForUndo(myFile);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -16,8 +16,13 @@ import org.jetbrains.annotations.Nullable;
|
||||
public abstract class AndroidBaseLayoutRefactoringAction extends AndroidBaseXmlRefactoringAction {
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled(@NotNull XmlTag tag) {
|
||||
return getLayoutViewElement(tag) != null;
|
||||
protected boolean isEnabledForTags(@NotNull XmlTag[] tags) {
|
||||
for (XmlTag tag : tags) {
|
||||
if (getLayoutViewElement(tag) == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+146
-26
@@ -6,9 +6,14 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
@@ -26,27 +31,124 @@ import org.jetbrains.annotations.Nullable;
|
||||
abstract class AndroidBaseXmlRefactoringAction extends BaseRefactoringAction {
|
||||
@Override
|
||||
protected boolean isAvailableOnElementInEditorAndFile(PsiElement element, Editor editor, PsiFile file, DataContext context) {
|
||||
final XmlTag[] tags = getXmlTagsFromExternalContext(context);
|
||||
if (tags.length > 0) {
|
||||
return AndroidFacet.getInstance(tags[0]) != null && isEnabledForTags(tags);
|
||||
}
|
||||
|
||||
final TextRange range = getNonEmptySelectionRange(editor);
|
||||
if (range != null) {
|
||||
final Pair<PsiElement, PsiElement> psiRange = getExtractableRange(
|
||||
file, range.getStartOffset(), range.getEndOffset());
|
||||
return psiRange != null && isEnabledForPsiRange(psiRange.getFirst(), psiRange.getSecond());
|
||||
}
|
||||
|
||||
if (element == null ||
|
||||
AndroidFacet.getInstance(element) == null ||
|
||||
PsiTreeUtil.getParentOfType(element, XmlText.class) != null) {
|
||||
return false;
|
||||
}
|
||||
final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
|
||||
return tag != null && isEnabled(tag);
|
||||
return tag != null && isEnabledForTags(new XmlTag[]{tag});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TextRange getNonEmptySelectionRange(Editor editor) {
|
||||
if (editor != null) {
|
||||
final SelectionModel model = editor.getSelectionModel();
|
||||
|
||||
if (model.hasSelection()) {
|
||||
final int start = model.getSelectionStart();
|
||||
final int end = model.getSelectionEnd();
|
||||
|
||||
if (start < end) {
|
||||
return TextRange.create(start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Pair<PsiElement, PsiElement> getExtractableRange(PsiFile file, int start, int end) {
|
||||
PsiElement startElement = file.findElementAt(start);
|
||||
PsiElement parent = startElement != null ? startElement.getParent() : null;
|
||||
|
||||
while (parent != null &&
|
||||
!(parent instanceof PsiFile) &&
|
||||
parent.getTextRange().getStartOffset() == startElement.getTextRange().getStartOffset()) {
|
||||
startElement = parent;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
PsiElement endElement = file.findElementAt(end - 1);
|
||||
parent = endElement != null ? endElement.getParent() : null;
|
||||
|
||||
while (parent != null &&
|
||||
!(parent instanceof PsiFile) &&
|
||||
parent.getTextRange().getEndOffset() == endElement.getTextRange().getEndOffset()) {
|
||||
endElement = parent;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
|
||||
if (startElement == null || endElement == null) {
|
||||
return null;
|
||||
}
|
||||
final PsiElement commonParent = startElement.getParent();
|
||||
|
||||
if (commonParent == null ||
|
||||
!(commonParent instanceof XmlTag) ||
|
||||
commonParent != endElement.getParent()) {
|
||||
return null;
|
||||
}
|
||||
PsiElement e = startElement;
|
||||
boolean containTag = false;
|
||||
|
||||
while (e != null) {
|
||||
if (!(e instanceof XmlText) &&
|
||||
!(e instanceof XmlTag) &&
|
||||
!(e instanceof PsiWhiteSpace) &&
|
||||
!(e instanceof PsiComment)) {
|
||||
return null;
|
||||
}
|
||||
if (e instanceof XmlTag) {
|
||||
containTag = true;
|
||||
}
|
||||
if (e == endElement) {
|
||||
break;
|
||||
}
|
||||
e = e.getNextSibling();
|
||||
}
|
||||
return e != null && containTag
|
||||
? Pair.create(startElement, endElement)
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabledOnElements(PsiElement[] elements) {
|
||||
if (elements.length != 1) {
|
||||
if (elements.length == 0) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement element = elements[0];
|
||||
return element instanceof XmlTag &&
|
||||
AndroidFacet.getInstance(element) != null &&
|
||||
isEnabled((XmlTag)element);
|
||||
|
||||
if (AndroidFacet.getInstance(element) == null) {
|
||||
return false;
|
||||
}
|
||||
final XmlTag[] tags = new XmlTag[elements.length];
|
||||
|
||||
for (int i = 0; i < tags.length; i++) {
|
||||
if (!(elements[i] instanceof XmlTag)) {
|
||||
return false;
|
||||
}
|
||||
tags[i] = (XmlTag)elements[i];
|
||||
}
|
||||
return isEnabledForTags(tags);
|
||||
}
|
||||
|
||||
protected abstract boolean isEnabled(@NotNull XmlTag tag);
|
||||
protected abstract boolean isEnabledForTags(@NotNull XmlTag[] tags);
|
||||
|
||||
protected boolean isEnabledForPsiRange(@NotNull PsiElement from, @Nullable PsiElement to) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAvailableForLanguage(Language language) {
|
||||
@@ -74,7 +176,11 @@ abstract class AndroidBaseXmlRefactoringAction extends BaseRefactoringAction {
|
||||
return data;
|
||||
}
|
||||
if (LangDataKeys.PSI_ELEMENT.is(dataId)) {
|
||||
return getXmlTagFromExternalContext(context);
|
||||
final XmlTag[] tags = getXmlTagsFromExternalContext(context);
|
||||
return tags.length == 1 ? tags[0] : null;
|
||||
}
|
||||
else if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) {
|
||||
return getXmlTagsFromExternalContext(context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -83,12 +189,15 @@ abstract class AndroidBaseXmlRefactoringAction extends BaseRefactoringAction {
|
||||
e.getActionManager(), e.getModifiers()));
|
||||
}
|
||||
|
||||
protected abstract void doRefactor(@NotNull Project project, @NotNull XmlTag tag);
|
||||
protected abstract void doRefactorForTags(@NotNull Project project, @NotNull XmlTag[] tags);
|
||||
|
||||
protected void doRefactorForPsiRange(@NotNull Project project, @NotNull PsiFile file, @NotNull PsiElement from, @NotNull PsiElement to) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RefactoringActionHandler getHandler(DataContext dataContext) {
|
||||
final XmlTag componentTag = getXmlTagFromExternalContext(dataContext);
|
||||
return new MyHandler(componentTag);
|
||||
final XmlTag[] componentTags = getXmlTagsFromExternalContext(dataContext);
|
||||
return new MyHandler(componentTags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,35 +205,46 @@ abstract class AndroidBaseXmlRefactoringAction extends BaseRefactoringAction {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static XmlTag getXmlTagFromExternalContext(DataContext dataContext) {
|
||||
@NotNull
|
||||
protected static XmlTag[] getXmlTagsFromExternalContext(DataContext dataContext) {
|
||||
if (dataContext == null) {
|
||||
return null;
|
||||
return XmlTag.EMPTY;
|
||||
}
|
||||
|
||||
for (AndroidRefactoringContextProvider provider : AndroidRefactoringContextProvider.EP_NAME.getExtensions()) {
|
||||
final XmlTag componentTag = provider.getComponentTag(dataContext);
|
||||
final XmlTag[] componentTags = provider.getComponentTags(dataContext);
|
||||
|
||||
if (componentTag != null) {
|
||||
return componentTag;
|
||||
if (componentTags.length > 0) {
|
||||
return componentTags;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return XmlTag.EMPTY;
|
||||
}
|
||||
|
||||
private class MyHandler implements RefactoringActionHandler {
|
||||
private final XmlTag myTagFromExternalContext;
|
||||
private final XmlTag[] myTagsFromExternalContext;
|
||||
|
||||
private MyHandler(@Nullable XmlTag tagFromExternalContext) {
|
||||
myTagFromExternalContext = tagFromExternalContext;
|
||||
private MyHandler(@NotNull XmlTag[] tagsFromExternalContext) {
|
||||
myTagsFromExternalContext = tagsFromExternalContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
|
||||
if (myTagFromExternalContext != null) {
|
||||
doRefactor(project, myTagFromExternalContext);
|
||||
if (myTagsFromExternalContext.length > 0) {
|
||||
doRefactorForTags(project, myTagsFromExternalContext);
|
||||
return;
|
||||
}
|
||||
|
||||
final TextRange range = getNonEmptySelectionRange(editor);
|
||||
if (range != null) {
|
||||
final Pair<PsiElement, PsiElement> psiRange = getExtractableRange(
|
||||
file, range.getStartOffset(), range.getEndOffset());
|
||||
if (psiRange != null) {
|
||||
doRefactorForPsiRange(project, file, psiRange.getFirst(), psiRange.getSecond());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiElement element = getElementAtCaret(editor, file);
|
||||
if (element == null) {
|
||||
return;
|
||||
@@ -133,13 +253,13 @@ abstract class AndroidBaseXmlRefactoringAction extends BaseRefactoringAction {
|
||||
if (tag == null) {
|
||||
return;
|
||||
}
|
||||
doRefactor(project, tag);
|
||||
doRefactorForTags(project, new XmlTag[]{tag});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
|
||||
if (myTagFromExternalContext != null) {
|
||||
doRefactor(project, myTagFromExternalContext);
|
||||
if (myTagsFromExternalContext.length > 0) {
|
||||
doRefactorForTags(project, myTagsFromExternalContext);
|
||||
return;
|
||||
}
|
||||
if (elements.length != 1) {
|
||||
@@ -149,7 +269,7 @@ abstract class AndroidBaseXmlRefactoringAction extends BaseRefactoringAction {
|
||||
if (!(element instanceof XmlTag)) {
|
||||
return;
|
||||
}
|
||||
doRefactor(project, (XmlTag)element);
|
||||
doRefactorForTags(project, new XmlTag[]{(XmlTag)element});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+343
@@ -0,0 +1,343 @@
|
||||
package org.jetbrains.android.refactoring;
|
||||
|
||||
import com.android.resources.ResourceType;
|
||||
import com.intellij.openapi.command.UndoConfirmationPolicy;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.InputValidatorEx;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.XmlAttribute;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomManager;
|
||||
import org.jetbrains.android.dom.layout.Include;
|
||||
import org.jetbrains.android.dom.layout.LayoutViewElement;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidExtractAsIncludeAction extends AndroidBaseLayoutRefactoringAction {
|
||||
@NonNls public static final String ACTION_ID = "AndroidExtractAsIncludeAction";
|
||||
|
||||
private final MyTestConfig myTestConfig;
|
||||
|
||||
public AndroidExtractAsIncludeAction() {
|
||||
myTestConfig = null;
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public AndroidExtractAsIncludeAction(@Nullable MyTestConfig testConfig) {
|
||||
myTestConfig = testConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRefactorForTags(@NotNull Project project, @NotNull XmlTag[] tags) {
|
||||
if (tags.length == 0) {
|
||||
return;
|
||||
}
|
||||
final PsiFile file = tags[0].getContainingFile();
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
XmlTag startTag = null;
|
||||
XmlTag endTag = null;
|
||||
int startOffset = Integer.MAX_VALUE;
|
||||
int endOffset = -1;
|
||||
|
||||
for (XmlTag tag : tags) {
|
||||
final TextRange range = tag.getTextRange();
|
||||
|
||||
final int start = range.getStartOffset();
|
||||
if (start < startOffset) {
|
||||
startOffset = start;
|
||||
startTag = tag;
|
||||
}
|
||||
|
||||
final int end = range.getEndOffset();
|
||||
if (end > endOffset) {
|
||||
endOffset = end;
|
||||
endTag = tag;
|
||||
}
|
||||
}
|
||||
assert startTag != null && endTag != null;
|
||||
doRefactorForPsiRange(project, file, startTag, endTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabledForTags(@NotNull XmlTag[] tags) {
|
||||
if (tags.length == 0) {
|
||||
return false;
|
||||
}
|
||||
final DomManager domManager = DomManager.getDomManager(tags[0].getProject());
|
||||
boolean containsViewElement = false;
|
||||
|
||||
for (XmlTag tag : tags) {
|
||||
final DomElement domElement = domManager.getDomElement(tag);
|
||||
|
||||
if (!isSuitableDomElement(domElement)) {
|
||||
return false;
|
||||
}
|
||||
if (domElement instanceof LayoutViewElement) {
|
||||
containsViewElement = true;
|
||||
}
|
||||
}
|
||||
if (!containsViewElement) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement parent = tags[0].getParent();
|
||||
|
||||
if (!(parent instanceof XmlTag) || parent.getContainingFile() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 1; i < tags.length; i++) {
|
||||
if (tags[i].getParent() != parent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRefactorForPsiRange(@NotNull final Project project, @NotNull final PsiFile file, @NotNull final PsiElement from,
|
||||
@NotNull final PsiElement to) {
|
||||
final PsiDirectory dir = file.getContainingDirectory();
|
||||
if (dir == null) {
|
||||
return;
|
||||
}
|
||||
final AndroidFacet facet = AndroidFacet.getInstance(from);
|
||||
assert facet != null;
|
||||
|
||||
final XmlTag parentTag = PsiTreeUtil.getParentOfType(from, XmlTag.class);
|
||||
assert parentTag != null;
|
||||
|
||||
final List<XmlTag> tagsInRange = collectAllTags(from, to);
|
||||
assert tagsInRange.size() > 0 : "there is no tag inside the range";
|
||||
|
||||
final String title = AndroidBundle.message("android.extract.as.include.title");
|
||||
final String fileName;
|
||||
|
||||
if (myTestConfig != null) {
|
||||
fileName = myTestConfig.myLayoutFileName;
|
||||
}
|
||||
else {
|
||||
fileName = Messages.showInputDialog(project, "Enter new layout file name", title, Messages.getQuestionIcon(),
|
||||
null, new MyInputValidatorEx(dir));
|
||||
}
|
||||
|
||||
if (fileName == null) {
|
||||
return;
|
||||
}
|
||||
final String fileName1 = addXmlExtensionIfNecessary(fileName);
|
||||
|
||||
new WriteCommandAction.Simple(project, "Extract '" + fileName1 + "' layout", file) {
|
||||
@Override
|
||||
protected void run() throws Throwable {
|
||||
doRefactor(project, file, from, to, dir, parentTag, fileName1, tagsInRange.size() > 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UndoConfirmationPolicy getUndoConfirmationPolicy() {
|
||||
return UndoConfirmationPolicy.REQUEST_CONFIRMATION;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
private static void doRefactor(Project project,
|
||||
PsiFile file,
|
||||
PsiElement from,
|
||||
PsiElement to,
|
||||
PsiDirectory dir,
|
||||
XmlTag parentTag,
|
||||
String fileName,
|
||||
boolean wrapWithMerge) {
|
||||
final String textToExtract = file.getText().substring(from.getTextRange().getStartOffset(),
|
||||
to.getTextRange().getEndOffset());
|
||||
final XmlFile newFile;
|
||||
try {
|
||||
final PsiFile f = dir.createFile(fileName);
|
||||
assert f instanceof XmlFile;
|
||||
newFile = (XmlFile)f;
|
||||
}
|
||||
catch (Exception e) {
|
||||
AndroidUtils.reportError(project, e.getClass().getName() + ": " + e.getMessage(),
|
||||
AndroidBundle.message("android.extract.as.include.title"));
|
||||
return;
|
||||
}
|
||||
final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
|
||||
final Document document = documentManager.getDocument(newFile);
|
||||
assert document != null;
|
||||
document.setText("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
|
||||
(wrapWithMerge ? "<merge>\n" + textToExtract + "\n</merge>" : textToExtract));
|
||||
documentManager.commitDocument(document);
|
||||
|
||||
final Set<String> unknownPrefixes = new HashSet<String>();
|
||||
|
||||
newFile.accept(new XmlRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitXmlTag(XmlTag tag) {
|
||||
super.visitXmlTag(tag);
|
||||
final String prefix = tag.getNamespacePrefix();
|
||||
|
||||
if (!unknownPrefixes.contains(prefix) && tag.getNamespace().length() == 0) {
|
||||
unknownPrefixes.add(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitXmlAttribute(XmlAttribute attribute) {
|
||||
final String prefix = attribute.getNamespacePrefix();
|
||||
|
||||
if (!unknownPrefixes.contains(prefix) && attribute.getNamespace().length() == 0) {
|
||||
unknownPrefixes.add(prefix);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
final XmlTag rootTag = newFile.getRootTag();
|
||||
assert rootTag != null;
|
||||
final XmlElementFactory elementFactory = XmlElementFactory.getInstance(project);
|
||||
final XmlAttribute[] attributes = rootTag.getAttributes();
|
||||
final XmlAttribute firstAttribute = attributes.length > 0 ? attributes[0] : null;
|
||||
|
||||
for (String prefix : unknownPrefixes) {
|
||||
final String namespace = parentTag.getNamespaceByPrefix(prefix);
|
||||
final String xmlNsAttrName = "xmlns:" + prefix;
|
||||
|
||||
if (namespace.length() > 0 && rootTag.getAttribute(xmlNsAttrName) == null) {
|
||||
final XmlAttribute xmlnsAttr = elementFactory.createXmlAttribute(xmlNsAttrName, namespace);
|
||||
|
||||
if (firstAttribute != null) {
|
||||
rootTag.addBefore(xmlnsAttr, firstAttribute);
|
||||
}
|
||||
else {
|
||||
rootTag.add(xmlnsAttr);
|
||||
}
|
||||
}
|
||||
}
|
||||
final String resourceName = AndroidCommonUtils.getResourceName(ResourceType.LAYOUT.getName(), fileName);
|
||||
final XmlTag includeTag = elementFactory.createTagFromText("<include layout=\"@layout/" + resourceName + "\"/>");
|
||||
parentTag.addAfter(includeTag, to);
|
||||
parentTag.deleteChildRange(from, to);
|
||||
|
||||
final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
|
||||
codeStyleManager.reformat(newFile);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String addXmlExtensionIfNecessary(@NotNull String inputString) {
|
||||
final String ext = FileUtil.getExtension(inputString);
|
||||
return "xml".equals(ext) ? inputString : inputString + ".xml";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<XmlTag> collectAllTags(PsiElement from, PsiElement to) {
|
||||
final List<XmlTag> result = new ArrayList<XmlTag>();
|
||||
PsiElement e = from;
|
||||
|
||||
while (e != null) {
|
||||
if (e instanceof XmlTag) {
|
||||
result.add((XmlTag)e);
|
||||
}
|
||||
if (e == to) {
|
||||
break;
|
||||
}
|
||||
e = e.getNextSibling();
|
||||
}
|
||||
assert e != null : "invalid range";
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabledForPsiRange(@NotNull PsiElement from, @Nullable PsiElement to) {
|
||||
final DomManager domManager = DomManager.getDomManager(from.getProject());
|
||||
PsiElement e = from;
|
||||
boolean containsViewElement = false;
|
||||
|
||||
while (e != null) {
|
||||
if (e instanceof XmlTag) {
|
||||
final DomElement domElement = domManager.getDomElement((XmlTag)e);
|
||||
|
||||
if (!isSuitableDomElement(domElement)) {
|
||||
return false;
|
||||
}
|
||||
if (domElement instanceof LayoutViewElement) {
|
||||
containsViewElement = true;
|
||||
}
|
||||
}
|
||||
if (e == to) {
|
||||
break;
|
||||
}
|
||||
e = e.getNextSibling();
|
||||
}
|
||||
return containsViewElement;
|
||||
}
|
||||
|
||||
private static boolean isSuitableDomElement(DomElement element) {
|
||||
return element instanceof LayoutViewElement ||
|
||||
element instanceof Include;
|
||||
}
|
||||
|
||||
static class MyTestConfig {
|
||||
private final String myLayoutFileName;
|
||||
|
||||
MyTestConfig(@NotNull String layoutFileName) {
|
||||
myLayoutFileName = layoutFileName;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyInputValidatorEx implements InputValidatorEx {
|
||||
private final PsiDirectory myDirectory;
|
||||
|
||||
public MyInputValidatorEx(@NotNull PsiDirectory directory) {
|
||||
myDirectory = directory;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getErrorText(String inputString) {
|
||||
if (inputString.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
final String fileName = addXmlExtensionIfNecessary(inputString);
|
||||
try {
|
||||
myDirectory.checkCreateFile(fileName);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
return e.getMessage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkInput(String inputString) {
|
||||
return inputString.length() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canClose(String inputString) {
|
||||
return checkInput(inputString) && getErrorText(inputString) == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -56,8 +56,8 @@ public class AndroidExtractStyleAction extends AndroidBaseLayoutRefactoringActio
|
||||
myTestConfig = testConfig;
|
||||
}
|
||||
|
||||
protected boolean isEnabled(@NotNull XmlTag tag) {
|
||||
return doIsEnabled(tag);
|
||||
protected boolean isEnabledForTags(@NotNull XmlTag[] tags) {
|
||||
return tags.length == 1 && doIsEnabled(tags[0]);
|
||||
}
|
||||
|
||||
public static boolean doIsEnabled(@NotNull XmlTag tag) {
|
||||
@@ -222,7 +222,10 @@ public class AndroidExtractStyleAction extends AndroidBaseLayoutRefactoringActio
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRefactor(@NotNull Project project, @NotNull XmlTag tag) {
|
||||
protected void doRefactorForTags(@NotNull Project project, @NotNull XmlTag[] tags) {
|
||||
assert tags.length == 1;
|
||||
|
||||
final XmlTag tag = tags[0];
|
||||
final Module module = ModuleUtilCore.findModuleForPsiElement(tag);
|
||||
assert module != null;
|
||||
doExtractStyle(module, tag, true, myTestConfig);
|
||||
|
||||
+6
-3
@@ -39,7 +39,10 @@ public class AndroidInlineStyleReferenceAction extends AndroidBaseXmlRefactoring
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRefactor(@NotNull Project project, @NotNull final XmlTag tag) {
|
||||
protected void doRefactorForTags(@NotNull Project project, @NotNull final XmlTag[] tags) {
|
||||
assert tags.length == 1;
|
||||
final XmlTag tag = tags[0];
|
||||
|
||||
final PsiFile file = tag.getContainingFile();
|
||||
if (file == null) {
|
||||
return;
|
||||
@@ -83,8 +86,8 @@ public class AndroidInlineStyleReferenceAction extends AndroidBaseXmlRefactoring
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled(@NotNull XmlTag tag) {
|
||||
return AndroidInlineUtil.getUsageData(tag) != null;
|
||||
protected boolean isEnabledForTags(@NotNull XmlTag[] tags) {
|
||||
return tags.length == 1 && AndroidInlineUtil.getUsageData(tags[0]) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-3
@@ -4,7 +4,6 @@ import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
@@ -13,6 +12,6 @@ public interface AndroidRefactoringContextProvider {
|
||||
ExtensionPointName<AndroidRefactoringContextProvider> EP_NAME =
|
||||
ExtensionPointName.create("org.jetbrains.android.refactoringContextProvider");
|
||||
|
||||
@Nullable
|
||||
XmlTag getComponentTag(@NotNull DataContext dataContext);
|
||||
@NotNull
|
||||
XmlTag[] getComponentTags(@NotNull DataContext dataContext);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextVi<caret>ew
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:andr1="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res/p1.p2"
|
||||
andr1:orientation="vertical"
|
||||
andr1:layout_width="fill_parent"
|
||||
andr1:layout_height="fill_parent">
|
||||
<TextView
|
||||
andr1:lay<caret>out_width="fill_parent"
|
||||
andr1:layout_height="wrap_content"
|
||||
andr1:text="Hello World, MyActivity"
|
||||
app:customAttribute="Hello"
|
||||
/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:andr1="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res/p1.p2"
|
||||
andr1:orientation="vertical"
|
||||
andr1:layout_width="fill_parent"
|
||||
andr1:layout_height="fill_parent">
|
||||
<include layout="@layout/extracted"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
xmlns:app="http://schemas.android.com/apk/res/p1.p2" xmlns:andr1="http://schemas.android.com/apk/res/android"
|
||||
andr1:layout_width="fill_parent"
|
||||
andr1:layout_height="wrap_content"
|
||||
andr1:text="Hello World, MyActivity"
|
||||
app:customAttribute="Hello"
|
||||
/>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<include layout="@layout/extracted"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<selection><TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/></selection>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<include layout="@layout/extracted"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<T<selection>extView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/></selection>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Linea<caret>rLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selection><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
</LinearLayout></selection>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<selection><TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/></selection>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<include layout="@layout/extracted"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
</merge>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<selection><!-- comment1 -->
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
|
||||
<!-- comment2 -->
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/></selection>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<include layout="@layout/extracted"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- comment1 -->
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
|
||||
<!-- comment2 -->
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
</merge>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<!-- co<selection>mment1 -->
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/>
|
||||
|
||||
<!-- comment2 -->
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, MyActivity"
|
||||
/></selection>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:andr1="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res/p1.p2"
|
||||
andr1:orientation="vertical"
|
||||
andr1:layout_width="fill_parent"
|
||||
andr1:layout_height="fill_parent">
|
||||
<selection><TextView
|
||||
andr1:layout_width="fill_parent"
|
||||
andr1:layout_height="wrap_content"
|
||||
andr1:text="Hello World, MyActivity"
|
||||
/>
|
||||
<TextView xmlns:andr2="http://schemas.android.com/apk/res/android"
|
||||
andr2:layout_width="fill_parent"
|
||||
andr2:layout_height="wrap_content"
|
||||
andr2:text="Hello World, MyActivity"/></selection>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:andr1="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res/p1.p2"
|
||||
andr1:orientation="vertical"
|
||||
andr1:layout_width="fill_parent"
|
||||
andr1:layout_height="fill_parent">
|
||||
<include layout="@layout/extracted"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:andr1="http://schemas.android.com/apk/res/android">
|
||||
<TextView
|
||||
andr1:layout_width="fill_parent"
|
||||
andr1:layout_height="wrap_content"
|
||||
andr1:text="Hello World, MyActivity"
|
||||
/>
|
||||
<TextView xmlns:andr2="http://schemas.android.com/apk/res/android"
|
||||
andr2:layout_width="fill_parent"
|
||||
andr2:layout_height="wrap_content"
|
||||
andr2:text="Hello World, MyActivity"/>
|
||||
</merge>
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package org.jetbrains.android.refactoring;
|
||||
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.android.AndroidTestCase;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidExtractAsIncludeTest extends AndroidTestCase {
|
||||
private static final String BASE_PATH = "refactoring/extractAsInclude/";
|
||||
|
||||
public void test1() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void test2() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void test3() throws Exception {
|
||||
doTestDisabled();
|
||||
}
|
||||
|
||||
public void test4() throws Exception {
|
||||
doTestDisabled();
|
||||
}
|
||||
|
||||
public void test5() throws Exception {
|
||||
doTestDisabled();
|
||||
}
|
||||
|
||||
public void test6() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void test7() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void test8() throws Exception {
|
||||
doTestDisabled();
|
||||
}
|
||||
|
||||
public void test9() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void test10() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
final String testName = getTestName(true);
|
||||
final VirtualFile f = myFixture.copyFileToProject(BASE_PATH + testName + ".xml", "res/layout/test.xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
final String extractedFileName = "extracted.xml";
|
||||
myFixture.testAction(new AndroidExtractAsIncludeAction(new AndroidExtractAsIncludeAction.MyTestConfig(extractedFileName)));
|
||||
myFixture.checkResultByFile(BASE_PATH + testName + "_after.xml", true);
|
||||
myFixture.checkResultByFile("res/layout/" + extractedFileName, BASE_PATH + testName + "_extracted.xml", true);
|
||||
}
|
||||
|
||||
private void doTestDisabled() {
|
||||
final String testName = getTestName(true);
|
||||
final VirtualFile f = myFixture.copyFileToProject(BASE_PATH + testName + ".xml", "res/layout/test.xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
final Presentation p =
|
||||
myFixture.testAction(new AndroidExtractAsIncludeAction(new AndroidExtractAsIncludeAction.MyTestConfig("extracted.xml")));
|
||||
assertTrue(p.isVisible());
|
||||
assertFalse(p.isEnabled());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user