diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index d73e0ee92783..db3effd06305 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -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 composites = getEditorComposites(file); diff --git a/plugins/android/resources/messages/AndroidBundle.properties b/plugins/android/resources/messages/AndroidBundle.properties index c02686496a4d..7e87a93e68bd 100644 --- a/plugins/android/resources/messages/AndroidBundle.properties +++ b/plugins/android/resources/messages/AndroidBundle.properties @@ -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. \ No newline at end of file +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 \ No newline at end of file diff --git a/plugins/android/src/org/jetbrains/android/AndroidCompletionContributor.java b/plugins/android/src/org/jetbrains/android/AndroidCompletionContributor.java index 266e64dc4085..b22c3ef12c87 100644 --- a/plugins/android/src/org/jetbrains/android/AndroidCompletionContributor.java +++ b/plugins/android/src/org/jetbrains/android/AndroidCompletionContributor.java @@ -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 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)) { diff --git a/plugins/android/src/org/jetbrains/android/actions/AndroidCreateLayoutFileAction.java b/plugins/android/src/org/jetbrains/android/actions/AndroidCreateLayoutFileAction.java new file mode 100644 index 000000000000..77de2e06e5b0 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/actions/AndroidCreateLayoutFileAction.java @@ -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 getAllowedTagNames(@NotNull AndroidFacet facet) { + return AndroidLayoutUtil.getPossibleRoots(facet); + } + + @Nullable + private static String computePreferredEditorForLayoutFiles(Project project) { + final EditorHistoryManager manager = EditorHistoryManager.getInstance(project); + final Set resourceDirs = new HashSet(); + final List 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 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 tagNames = getSortedAllowedTagNames(facet); + myRootElementField = new TextFieldWithAutoCompletion( + 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(); + } + } + } +} diff --git a/plugins/android/src/org/jetbrains/android/actions/AndroidCreateLayoutFileDialog.form b/plugins/android/src/org/jetbrains/android/actions/AndroidCreateLayoutFileDialog.form new file mode 100644 index 000000000000..7e4b1363c3c4 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/actions/AndroidCreateLayoutFileDialog.form @@ -0,0 +1,51 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.form b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.form index 560b404bdd2d..7707b5a275ac 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.form +++ b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.form @@ -1,6 +1,6 @@
- + @@ -54,7 +54,7 @@ - + @@ -62,13 +62,13 @@ - + - + @@ -77,7 +77,7 @@ - + @@ -85,6 +85,22 @@ + + + + + + + + + + + + + + + + diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.java b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.java index f0d4c9163102..f53dcb9cd0f8 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.java +++ b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDialog.java @@ -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 myRootElementField; private InputValidator myValidator; private final Map myResType2ActionMap = new HashMap(); private final DeviceConfiguratorPanel myDeviceConfiguratorPanel; + private final AndroidFacet myFacet; - public CreateResourceDialog(Project project, Collection actions, CreateTypedResourceFileAction selected) { - super(project); + public CreateResourceDialog(@NotNull AndroidFacet facet, Collection 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 allowedTagNames = action.getSortedAllowedTagNames(myFacet); + myRootElementField = new TextFieldWithAutoCompletion( + 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; } diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileAction.java b/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileAction.java index 74f064334916..137f48b5ce27 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileAction.java @@ -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 mySubactions = new HashMap(); + 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); } diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java b/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java index 21666f9d9c58..5024481ba13b 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java +++ b/plugins/android/src/org/jetbrains/android/actions/CreateResourceFileActionGroup.java @@ -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 getAllowedTagNames(@NotNull AndroidFacet facet) { + return AndroidXmlResourcesUtil.getPossibleRoots(facet); + } + }); + + a.add(new CreateTypedResourceFileAction("Drawable", "drawable", "selector", false, true) { + @NotNull + @Override + public List 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 getAllowedTagNames(@NotNull AndroidFacet facet) { + return AndroidAnimationUtils.getPossibleChildren(facet); + } + }); + + a.add(new CreateTypedResourceFileAction("Animator", "animator", "set", false, true) { + @NotNull + @Override + public List getAllowedTagNames(@NotNull AndroidFacet facet) { + return AndroidAnimatorUtil.getPossibleChildren(); + } + }); + myMajorAction = a; add(a); for (CreateTypedResourceFileAction subaction : a.getSubactions()) { diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateTypedResourceFileAction.java b/plugins/android/src/org/jetbrains/android/actions/CreateTypedResourceFileAction.java index 278f4fc3c1b8..5c32c6de9de6 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateTypedResourceFileAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/CreateTypedResourceFileAction.java @@ -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 getAllowedTagNames(@NotNull AndroidFacet facet) { + return Collections.singletonList(getDefaultRootTag()); + } + + @NotNull + protected final List getSortedAllowedTagNames(@NotNull AndroidFacet facet) { + final List result = new ArrayList(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() { 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(); diff --git a/plugins/android/src/org/jetbrains/android/dom/AndroidDomUtil.java b/plugins/android/src/org/jetbrains/android/dom/AndroidDomUtil.java index effbeac74e96..c7688e735e74 100644 --- a/plugins/android/src/org/jetbrains/android/dom/AndroidDomUtil.java +++ b/plugins/android/src/org/jetbrains/android/dom/AndroidDomUtil.java @@ -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 removeUnambigiousNames(@NotNull Map viewClassMap) { + final Map class2Name = new HashMap(); + + 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(); + } } diff --git a/plugins/android/src/org/jetbrains/android/dom/layout/AndroidLayoutUtil.java b/plugins/android/src/org/jetbrains/android/dom/layout/AndroidLayoutUtil.java new file mode 100644 index 000000000000..d553c7518b00 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/dom/layout/AndroidLayoutUtil.java @@ -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 getPossibleRoots(@NotNull AndroidFacet facet) { + final List result = new ArrayList(); + result.add("view"); + result.add("merge"); + result.addAll(AndroidDomUtil.removeUnambigiousNames( + AndroidDomExtender.getViewClassMap(facet))); + result.remove("View"); + return result; + } +} diff --git a/plugins/android/src/org/jetbrains/android/dom/xml/AndroidXmlResourcesUtil.java b/plugins/android/src/org/jetbrains/android/dom/xml/AndroidXmlResourcesUtil.java index ce68d4199c64..6989f910f2bc 100644 --- a/plugins/android/src/org/jetbrains/android/dom/xml/AndroidXmlResourcesUtil.java +++ b/plugins/android/src/org/jetbrains/android/dom/xml/AndroidXmlResourcesUtil.java @@ -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 getPossibleRoots(@NotNull AndroidFacet facet) { List result = new ArrayList(); - result.addAll(AndroidDomExtender.getPreferencesClassMap(facet).keySet()); + result.addAll(AndroidDomUtil.removeUnambigiousNames( + AndroidDomExtender.getPreferencesClassMap(facet))); result.addAll(Arrays.asList(ROOT_TAGS)); return result;