IDEA-86604 improve "create layout" and "create resource" actions: choosing root element, opening new layouts in last used editor

This commit is contained in:
Eugene Kudelevsky
2012-06-07 16:11:11 +04:00
parent e584286529
commit d7d236fa98
13 changed files with 481 additions and 61 deletions
@@ -879,7 +879,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
});
}
private void setSelectedEditor(VirtualFile file, String fileEditorProviderId) {
public void setSelectedEditor(VirtualFile file, String fileEditorProviderId) {
EditorWithProviderComposite composite = getCurrentEditorWithProviderComposite(file);
if (composite == null) {
final List<EditorWithProviderComposite> composites = getEditorComposites(file);
@@ -407,4 +407,6 @@ android.facet.settings.include.system.proguard=Include system proguard file
file.already.exists.error=File {0} already exists
deployment.target.settings.min.sdk.info.message=Only compatible AVDs are shown. See 'uses-sdk' tag in AndroidManifest.xml
android.compilation.warning.circular.app.dependency=Generated fields in {0}.R class in module ''{1}'' won''t be final, because of circular dependency on module ''{2}''
cannot.find.zip.align=The zipalign tool was not found in the SDK.\n\nPlease update to the latest SDK and re-export your application\nor run zipalign manually.\n\nAligning applications allows Android to use application resources\nmore efficiently.
cannot.find.zip.align=The zipalign tool was not found in the SDK.\n\nPlease update to the latest SDK and re-export your application\nor run zipalign manually.\n\nAligning applications allows Android to use application resources\nmore efficiently.
file.name.not.specified.error=File name is not specified
root.element.not.specified.error=Root element is not specified
@@ -19,12 +19,10 @@ import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import org.jetbrains.android.dom.AndroidDomExtender;
import org.jetbrains.android.dom.animation.AndroidAnimationUtils;
import org.jetbrains.android.dom.animation.AnimationDomFileDescription;
import org.jetbrains.android.dom.animator.AndroidAnimatorUtil;
@@ -32,17 +30,16 @@ import org.jetbrains.android.dom.animator.AnimatorDomFileDescription;
import org.jetbrains.android.dom.color.ColorDomFileDescription;
import org.jetbrains.android.dom.drawable.AndroidDrawableDomUtil;
import org.jetbrains.android.dom.drawable.DrawableStateListDomFileDescription;
import org.jetbrains.android.dom.layout.AndroidLayoutUtil;
import org.jetbrains.android.dom.layout.LayoutDomFileDescription;
import org.jetbrains.android.dom.manifest.ManifestDomFileDescription;
import org.jetbrains.android.dom.xml.AndroidXmlResourcesUtil;
import org.jetbrains.android.dom.xml.XmlResourceDomFileDescription;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
/**
* @author coyote
@@ -68,15 +65,7 @@ public class AndroidCompletionContributor extends CompletionContributor {
return false;
}
else if (LayoutDomFileDescription.isLayoutFile(xmlFile)) {
resultSet.addElement(LookupElementBuilder.create("view"));
resultSet.addElement(LookupElementBuilder.create("merge"));
Map<String, PsiClass> viewClassMap = AndroidDomExtender.getViewClassMap(facet);
for (String tagName : viewClassMap.keySet()) {
final PsiClass viewClass = viewClassMap.get(tagName);
if (!AndroidUtils.isAbstract(viewClass)) {
resultSet.addElement(LookupElementBuilder.create(tagName));
}
}
addAll(AndroidLayoutUtil.getPossibleRoots(facet), resultSet);
return false;
}
else if (AnimationDomFileDescription.isAnimationFile(xmlFile)) {
@@ -0,0 +1,188 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.android.actions;
import com.android.resources.ResourceType;
import com.intellij.CommonBundle;
import com.intellij.facet.ProjectFacetManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorProvider;
import com.intellij.openapi.fileEditor.impl.EditorHistoryManager;
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.InputValidator;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlFile;
import com.intellij.ui.TextFieldWithAutoCompletion;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.containers.HashSet;
import org.jetbrains.android.dom.layout.AndroidLayoutUtil;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.Set;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidCreateLayoutFileAction extends CreateTypedResourceFileAction {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.actions.AndroidCreateLayoutFileAction");
private String myLastRootComponentName;
public AndroidCreateLayoutFileAction() {
super("Layout", "layout", "LinearLayout", false, false);
}
@NotNull
@Override
protected PsiElement[] invokeDialog(Project project, PsiDirectory directory) {
final AndroidFacet facet = AndroidFacet.getInstance(directory);
LOG.assertTrue(facet != null);
MyInputValidator validator = new MyInputValidator(project, directory);
final MyDialog dialog = new MyDialog(facet, validator);
dialog.show();
return PsiElement.EMPTY_ARRAY;
}
@NotNull
@Override
protected PsiElement[] create(String newName, PsiDirectory directory) throws Exception {
assert myLastRootComponentName != null;
return doCreate(newName, directory, myLastRootComponentName, false);
}
@Override
protected void doNavigate(XmlFile file) {
final Project project = file.getProject();
final String preferredEditorProviderId = computePreferredEditorForLayoutFiles(project);
super.doNavigate(file);
if (preferredEditorProviderId != null) {
final FileEditorManager manager = FileEditorManager.getInstance(project);
if (manager instanceof FileEditorManagerImpl) {
final VirtualFile vFile = file.getVirtualFile();
if (vFile != null) {
((FileEditorManagerImpl)manager).setSelectedEditor(vFile, preferredEditorProviderId);
}
}
}
}
@NotNull
@Override
public List<String> getAllowedTagNames(@NotNull AndroidFacet facet) {
return AndroidLayoutUtil.getPossibleRoots(facet);
}
@Nullable
private static String computePreferredEditorForLayoutFiles(Project project) {
final EditorHistoryManager manager = EditorHistoryManager.getInstance(project);
final Set<VirtualFile> resourceDirs = new HashSet<VirtualFile>();
final List<AndroidFacet> facets = ProjectFacetManager.getInstance(project).getFacets(AndroidFacet.ID);
for (AndroidFacet facet : facets) {
final VirtualFile resourceDir = AndroidRootUtil.getResourceDir(facet);
if (resourceDir != null) {
resourceDirs.add(resourceDir);
}
}
final VirtualFile[] files = manager.getFiles();
for (int i = files.length - 1; i >= 0; i--) {
final VirtualFile file = files[i];
final VirtualFile parent = file.getParent();
if (parent != null) {
final String resType = AndroidCommonUtils.getResourceTypeByDirName(parent.getName());
if (ResourceType.LAYOUT.getName().equals(resType) && resourceDirs.contains(parent.getParent())) {
final FileEditorProvider provider = manager.getSelectedProvider(file);
if (provider != null) {
return provider.getEditorTypeId();
}
}
}
}
return null;
}
public class MyDialog extends DialogWrapper {
private final InputValidator myValidator;
private JTextField myFileNameField;
private TextFieldWithAutoCompletion<String> myRootElementField;
private JPanel myPanel;
private JPanel myRootElementFieldWrapper;
private JBLabel myRootElementLabel;
protected MyDialog(@NotNull AndroidFacet facet, @Nullable InputValidator validator) {
super(facet.getModule().getProject());
myValidator = validator;
setTitle(AndroidBundle.message("new.typed.resource.dialog.title", "Layout"));
final List<String> tagNames = getSortedAllowedTagNames(facet);
myRootElementField = new TextFieldWithAutoCompletion<String>(
facet.getModule().getProject(), new TextFieldWithAutoCompletion.StringsCompletionProvider(tagNames, null), true);
myRootElementField.setText(myDefaultRootTag);
myRootElementFieldWrapper.add(myRootElementField, BorderLayout.CENTER);
myRootElementLabel.setLabelFor(myRootElementField);
init();
}
@Override
protected JComponent createCenterPanel() {
return myPanel;
}
@Override
public JComponent getPreferredFocusedComponent() {
return myFileNameField;
}
@Override
protected void doOKAction() {
final String fileName = myFileNameField.getText().trim();
myLastRootComponentName = myRootElementField.getText().trim();
if (fileName.length() == 0) {
Messages.showErrorDialog(myPanel, AndroidBundle.message("file.name.not.specified.error"), CommonBundle.getErrorTitle());
return;
}
if (myLastRootComponentName.length() == 0) {
Messages.showErrorDialog(myPanel, AndroidBundle.message("root.element.not.specified.error"), CommonBundle.getErrorTitle());
return;
}
if (myValidator == null ||
myValidator.checkInput(fileName) && myValidator.canClose(fileName)) {
super.doOKAction();
}
}
}
}
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.android.actions.AndroidCreateLayoutFileAction.MyDialog">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="500" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="5f781" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<labelFor value="1dac9"/>
<text value="&amp;File name:"/>
</properties>
</component>
<vspacer id="59f15">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<component id="1dac9" class="javax.swing.JTextField" binding="myFileNameField">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="150" height="-1"/>
</grid>
</constraints>
<properties/>
</component>
<component id="f57b7" class="com.intellij.ui.components.JBLabel" binding="myRootElementLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="&amp;Root element:"/>
</properties>
</component>
<grid id="2457e" binding="myRootElementFieldWrapper" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
</children>
</grid>
</form>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.android.actions.CreateResourceDialog">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="6" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="417" height="188"/>
@@ -54,7 +54,7 @@
</component>
<grid id="8653" binding="myDeviceConfiguratorWrapper" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="3" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="4" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -62,13 +62,13 @@
</grid>
<component id="f676e" class="com.intellij.ui.components.JBLabel" binding="myErrorLabel">
<constraints>
<grid row="4" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="5" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
<component id="fda57" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<labelFor value="90507"/>
@@ -77,7 +77,7 @@
</component>
<component id="90507" class="javax.swing.JTextField" binding="myDirectoryNameTextField">
<constraints>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="150" height="-1"/>
</grid>
</constraints>
@@ -85,6 +85,22 @@
<enabled value="false"/>
</properties>
</component>
<component id="be58a" class="com.intellij.ui.components.JBLabel" binding="myRootElementLabel">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Root &amp;element:"/>
</properties>
</component>
<grid id="5b73f" binding="myRootElementFieldWrapper" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
</children>
</grid>
</form>
@@ -18,25 +18,27 @@ package org.jetbrains.android.actions;
import com.android.ide.common.resources.configuration.FolderConfiguration;
import com.android.resources.ResourceFolderType;
import com.intellij.CommonBundle;
import com.intellij.ide.actions.TemplateKindCombo;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.InputValidator;
import com.intellij.openapi.ui.Messages;
import com.intellij.ui.TextFieldWithAutoCompletion;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.HashMap;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.uipreview.DeviceConfiguratorPanel;
import org.jetbrains.android.uipreview.InvalidOptionValueException;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.*;
import java.util.List;
/**
* Created by IntelliJ IDEA.
@@ -54,13 +56,18 @@ public abstract class CreateResourceDialog extends DialogWrapper {
private JPanel myDeviceConfiguratorWrapper;
private JBLabel myErrorLabel;
private JTextField myDirectoryNameTextField;
private JPanel myRootElementFieldWrapper;
private JBLabel myRootElementLabel;
private TextFieldWithAutoCompletion<String> myRootElementField;
private InputValidator myValidator;
private final Map<String, CreateTypedResourceFileAction> myResType2ActionMap = new HashMap<String, CreateTypedResourceFileAction>();
private final DeviceConfiguratorPanel myDeviceConfiguratorPanel;
private final AndroidFacet myFacet;
public CreateResourceDialog(Project project, Collection<CreateTypedResourceFileAction> actions, CreateTypedResourceFileAction selected) {
super(project);
public CreateResourceDialog(@NotNull AndroidFacet facet, Collection<CreateTypedResourceFileAction> actions) {
super(facet.getModule().getProject());
myFacet = facet;
myResTypeLabel.setLabelFor(myResourceTypeCombo);
myResourceTypeCombo.registerUpDownHint(myFileNameField);
myUpDownHint.setIcon(PlatformIcons.UP_DOWN_ARROWS);
@@ -111,22 +118,57 @@ public abstract class CreateResourceDialog extends DialogWrapper {
@Override
public void actionPerformed(ActionEvent e) {
myDeviceConfiguratorPanel.applyEditors();
updateRootElementCombo();
}
});
myDeviceConfiguratorPanel.updateAll();
myDeviceConfiguratorWrapper.add(myDeviceConfiguratorPanel, BorderLayout.CENTER);
setOKActionEnabled(myDirectoryNameTextField.getText().length() > 0);
updateRootElementCombo();
init();
}
private void updateRootElementCombo() {
final CreateTypedResourceFileAction action = getSelectedAction();
if (action != null) {
final List<String> allowedTagNames = action.getSortedAllowedTagNames(myFacet);
myRootElementField = new TextFieldWithAutoCompletion<String>(
myFacet.getModule().getProject(), new TextFieldWithAutoCompletion.StringsCompletionProvider(allowedTagNames, null), true);
myRootElementField.setEnabled(allowedTagNames.size() > 1);
myRootElementField.setText(!action.isChooseTagName() ? action.getDefaultRootTag() : "");
myRootElementFieldWrapper.removeAll();
myRootElementFieldWrapper.add(myRootElementField, BorderLayout.CENTER);
}
}
private static boolean containsElement(@NotNull ListModel model, @NotNull Object objectToFind) {
for (int i = 0, n = model.getSize(); i < n; i++) {
if (objectToFind.equals(model.getElementAt(i))) {
return true;
}
}
return false;
}
protected abstract InputValidator createValidator(@NotNull String subdirName);
@Override
protected void doOKAction() {
String fileName = myFileNameField.getText();
assert getSelectedAction() != null;
String fileName = myFileNameField.getText().trim();
final CreateTypedResourceFileAction action = getSelectedAction();
assert action != null;
if (fileName.length() == 0) {
Messages.showErrorDialog(myPanel, AndroidBundle.message("file.name.not.specified.error"), CommonBundle.getErrorTitle());
return;
}
if (!action.isChooseTagName() && getRootElement().length() == 0) {
Messages.showErrorDialog(myPanel, AndroidBundle.message("root.element.not.specified.error"), CommonBundle.getErrorTitle());
return;
}
final String subdirName = myDirectoryNameTextField.getText();
assert subdirName != null && subdirName.length() > 0;
@@ -137,6 +179,12 @@ public abstract class CreateResourceDialog extends DialogWrapper {
}
}
@NotNull
protected String getRootElement() {
final String item = myRootElementField.getText().trim();
return item != null ? item.trim() : "";
}
public InputValidator getValidator() {
return myValidator;
}
@@ -24,6 +24,7 @@ import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.InputValidator;
@@ -33,6 +34,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.annotations.NotNull;
@@ -47,7 +49,10 @@ import java.util.Map;
* @author Eugene.Kudelevsky
*/
public class CreateResourceFileAction extends CreateElementActionBase {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.actions.CreateResourceFileAction");
private final Map<String, CreateTypedResourceFileAction> mySubactions = new HashMap<String, CreateTypedResourceFileAction>();
private String myRootElement;
@NotNull
public static CreateResourceFileAction getInstance() {
@@ -101,20 +106,24 @@ public class CreateResourceFileAction extends CreateElementActionBase {
@NotNull
@Override
protected PsiElement[] invokeDialog(final Project project, final PsiDirectory directory) {
CreateTypedResourceFileAction createLayoutAction = mySubactions.get("layout");
CreateResourceDialog dialog = new CreateResourceDialog(project, mySubactions.values(), createLayoutAction) {
final AndroidFacet facet = AndroidFacet.getInstance(directory);
LOG.assertTrue(facet != null);
CreateResourceDialog dialog = new CreateResourceDialog(facet, mySubactions.values()) {
@Override
protected InputValidator createValidator(@NotNull String subdirName) {
return CreateResourceFileAction.this.createValidator(project, directory, subdirName);
}
@Override
protected void doOKAction() {
myRootElement = getRootElement();
super.doOKAction();
}
};
dialog.setTitle(AndroidBundle.message("new.resource.dialog.title"));
dialog.show();
InputValidator validator = dialog.getValidator();
if (validator == null) {
return PsiElement.EMPTY_ARRAY;
}
return ((MyInputValidator)validator).getCreatedElements();
return PsiElement.EMPTY_ARRAY;
}
@NotNull
@@ -134,6 +143,9 @@ public class CreateResourceFileAction extends CreateElementActionBase {
@Override
protected PsiElement[] create(String newName, PsiDirectory directory) throws Exception {
CreateTypedResourceFileAction action = getActionByDir(directory);
if (myRootElement != null && myRootElement.length() > 0) {
return action.doCreate(newName, directory, myRootElement, false);
}
return action.create(newName, directory);
}
@@ -17,8 +17,15 @@
package org.jetbrains.android.actions;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import org.jetbrains.android.dom.animation.AndroidAnimationUtils;
import org.jetbrains.android.dom.animator.AndroidAnimatorUtil;
import org.jetbrains.android.dom.drawable.AndroidDrawableDomUtil;
import org.jetbrains.android.dom.xml.AndroidXmlResourcesUtil;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: Eugene.Kudelevsky
@@ -31,14 +38,44 @@ public class CreateResourceFileActionGroup extends DefaultActionGroup {
public CreateResourceFileActionGroup() {
CreateResourceFileAction a = new CreateResourceFileAction();
a.add(new CreateTypedResourceFileAction("Layout", "layout", "LinearLayout"));
a.add(new CreateTypedResourceFileAction("XML", "xml", "PreferenceScreen"));
a.add(new CreateTypedResourceFileAction("Drawable", "drawable", "selector"));
a.add(new AndroidCreateLayoutFileAction());
a.add(new CreateTypedResourceFileAction("XML", "xml", "PreferenceScreen", false, true) {
@NotNull
@Override
public List<String> getAllowedTagNames(@NotNull AndroidFacet facet) {
return AndroidXmlResourcesUtil.getPossibleRoots(facet);
}
});
a.add(new CreateTypedResourceFileAction("Drawable", "drawable", "selector", false, true) {
@NotNull
@Override
public List<String> getAllowedTagNames(@NotNull AndroidFacet facet) {
return AndroidDrawableDomUtil.getPossibleRoots();
}
});
a.add(new CreateTypedResourceFileAction("Color", "color", "selector", false, false));
a.add(new CreateTypedResourceFileAction("Values", "values", "resources", true, false));
a.add(new CreateTypedResourceFileAction("Menu", "menu", "menu", false, false));
a.add(new CreateTypedResourceFileAction("Animation", "anim", "set"));
a.add(new CreateTypedResourceFileAction("Animator", "animator", "set"));
a.add(new CreateTypedResourceFileAction("Animation", "anim", "set", false, true) {
@NotNull
@Override
public List<String> getAllowedTagNames(@NotNull AndroidFacet facet) {
return AndroidAnimationUtils.getPossibleChildren(facet);
}
});
a.add(new CreateTypedResourceFileAction("Animator", "animator", "set", false, true) {
@NotNull
@Override
public List<String> getAllowedTagNames(@NotNull AndroidFacet facet) {
return AndroidAnimatorUtil.getPossibleChildren();
}
});
myMajorAction = a;
add(a);
for (CreateTypedResourceFileAction subaction : a.getSubactions()) {
@@ -22,7 +22,7 @@ import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.FileTemplateUtil;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Editor;
@@ -39,29 +39,29 @@ import com.intellij.psi.xml.XmlTag;
import com.intellij.util.PsiNavigateUtil;
import com.intellij.xml.refactoring.XmlTagInplaceRenamer;
import org.jetbrains.android.AndroidFileTemplateProvider;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
/**
* @author Eugene.Kudelevsky
*/
public class CreateTypedResourceFileAction extends CreateElementActionBase {
private static final String ROOT_TAG_PROPERTY = "ROOT_TAG";
static final String ROOT_TAG_PROPERTY = "ROOT_TAG";
private final String myResourceType;
private final String myResourcePresentableName;
private final String myDefaultRootTag;
protected final String myDefaultRootTag;
private final boolean myValuesResourceFile;
private final boolean myChooseTagName;
public CreateTypedResourceFileAction(@NotNull String presentableName, @NotNull String resourceType, @NotNull String defaultRootTag) {
this(presentableName, resourceType, defaultRootTag, false, true);
}
public CreateTypedResourceFileAction(@NotNull String resourcePresentableName,
@NotNull String resourceType,
@NotNull String defaultRootTag,
@@ -87,24 +87,29 @@ public class CreateTypedResourceFileAction extends CreateElementActionBase {
Messages.showInputDialog(project, AndroidBundle.message("new.file.dialog.text"),
AndroidBundle.message("new.typed.resource.dialog.title", myResourcePresentableName),
Messages.getQuestionIcon(), "", validator);
return validator.getCreatedElements();
return PsiElement.EMPTY_ARRAY;
}
@NotNull
@Override
protected PsiElement[] create(String newName, PsiDirectory directory) throws Exception {
return doCreate(newName, directory, myDefaultRootTag, myChooseTagName);
}
PsiElement[] doCreate(String newName, PsiDirectory directory, String rootTagName, boolean chooseTagName) throws Exception {
FileTemplateManager manager = FileTemplateManager.getInstance();
String templateName = getTemplateName();
FileTemplate template = manager.getJ2eeTemplate(templateName);
Properties properties = new Properties();
if (!myValuesResourceFile) {
properties.setProperty(ROOT_TAG_PROPERTY, myDefaultRootTag);
properties.setProperty(ROOT_TAG_PROPERTY, rootTagName);
}
PsiElement createdElement = FileTemplateUtil.createFromTemplate(template, newName, properties, directory);
assert createdElement instanceof XmlFile;
final XmlFile file = (XmlFile)createdElement;
PsiNavigateUtil.navigate(file);
if (myChooseTagName) {
doNavigate(file);
if (chooseTagName) {
XmlDocument document = file.getDocument();
if (document != null) {
XmlTag rootTag = document.getRootTag();
@@ -122,6 +127,10 @@ public class CreateTypedResourceFileAction extends CreateElementActionBase {
return new PsiElement[]{createdElement};
}
protected void doNavigate(XmlFile file) {
PsiNavigateUtil.navigate(file);
}
private String getTemplateName() {
if (myValuesResourceFile) {
return AndroidFileTemplateProvider.VALUE_RESOURCE_FILE_TEMPLATE;
@@ -134,13 +143,36 @@ public class CreateTypedResourceFileAction extends CreateElementActionBase {
@Override
protected boolean isAvailable(DataContext context) {
if (!super.isAvailable(context)) return false;
final PsiElement element = (PsiElement)context.getData(DataKeys.PSI_ELEMENT.getName());
return super.isAvailable(context) && doIsAvailable(context, myResourceType);
}
public boolean isChooseTagName() {
return myChooseTagName;
}
@NotNull
public List<String> getAllowedTagNames(@NotNull AndroidFacet facet) {
return Collections.singletonList(getDefaultRootTag());
}
@NotNull
protected final List<String> getSortedAllowedTagNames(@NotNull AndroidFacet facet) {
final List<String> result = new ArrayList<String>(getAllowedTagNames(facet));
Collections.sort(result);
return result;
}
public String getDefaultRootTag() {
return myDefaultRootTag;
}
static boolean doIsAvailable(DataContext context, final String resourceType) {
final PsiElement element = (PsiElement)context.getData(LangDataKeys.PSI_ELEMENT.getName());
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
PsiElement e = element;
while (e != null) {
if (e instanceof PsiDirectory && AndroidResourceUtil.isResourceSubdirectory((PsiDirectory)e, myResourceType)) {
if (e instanceof PsiDirectory && AndroidResourceUtil.isResourceSubdirectory((PsiDirectory)e, resourceType)) {
return true;
}
e = e.getParent();
@@ -48,10 +48,7 @@ import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
import static org.jetbrains.android.util.AndroidUtils.SYSTEM_RESOURCE_PACKAGE;
@@ -328,4 +325,22 @@ public class AndroidDomUtil {
}
return null;
}
@NotNull
public static Collection<String> removeUnambigiousNames(@NotNull Map<String, PsiClass> viewClassMap) {
final Map<String, String> class2Name = new HashMap<String, String>();
for (String tagName : viewClassMap.keySet()) {
final PsiClass viewClass = viewClassMap.get(tagName);
if (!AndroidUtils.isAbstract(viewClass)) {
final String qName = viewClass.getQualifiedName();
final String prevTagName = class2Name.get(qName);
if (prevTagName == null || tagName.indexOf('.') == -1) {
class2Name.put(qName, tagName);
}
}
}
return class2Name.values();
}
}
@@ -0,0 +1,28 @@
package org.jetbrains.android.dom.layout;
import org.jetbrains.android.dom.AndroidDomExtender;
import org.jetbrains.android.dom.AndroidDomUtil;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidLayoutUtil {
private AndroidLayoutUtil() {
}
@NotNull
public static List<String> getPossibleRoots(@NotNull AndroidFacet facet) {
final List<String> result = new ArrayList<String>();
result.add("view");
result.add("merge");
result.addAll(AndroidDomUtil.removeUnambigiousNames(
AndroidDomExtender.getViewClassMap(facet)));
result.remove("View");
return result;
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.android.dom.xml;
import com.intellij.util.containers.HashMap;
import org.jetbrains.android.dom.AndroidDomExtender;
import org.jetbrains.android.dom.AndroidDomUtil;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -68,7 +69,8 @@ public class AndroidXmlResourcesUtil {
@NotNull
public static List<String> getPossibleRoots(@NotNull AndroidFacet facet) {
List<String> result = new ArrayList<String>();
result.addAll(AndroidDomExtender.getPreferencesClassMap(facet).keySet());
result.addAll(AndroidDomUtil.removeUnambigiousNames(
AndroidDomExtender.getPreferencesClassMap(facet)));
result.addAll(Arrays.asList(ROOT_TAGS));
return result;