| /* |
| * Copyright 2016 The Bazel Authors. All rights reserved. |
| * |
| * 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 com.google.idea.blaze.android.resources.actions; |
| |
| import com.android.resources.ResourceFolderType; |
| import com.intellij.CommonBundle; |
| import com.intellij.openapi.actionSystem.CommonDataKeys; |
| import com.intellij.openapi.actionSystem.DataContext; |
| import com.intellij.openapi.actionSystem.LangDataKeys; |
| import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.project.Project; |
| 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.PsiManager; |
| import com.intellij.ui.ComboboxWithBrowseButton; |
| import com.intellij.ui.EnumComboBoxModel; |
| import com.intellij.ui.ListCellRendererWrapper; |
| import com.intellij.ui.components.JBLabel; |
| import com.intellij.uiDesigner.core.GridConstraints; |
| import com.intellij.uiDesigner.core.GridLayoutManager; |
| import java.awt.BorderLayout; |
| import java.awt.Dimension; |
| import java.awt.Insets; |
| import javax.swing.JComboBox; |
| import javax.swing.JComponent; |
| import javax.swing.JLabel; |
| import javax.swing.JList; |
| import javax.swing.JPanel; |
| import javax.swing.JTextField; |
| import org.jetbrains.android.actions.CreateResourceDirectoryDialogBase; |
| import org.jetbrains.android.actions.ElementCreatingValidator; |
| import org.jetbrains.android.uipreview.DeviceConfiguratorPanel; |
| import org.jetbrains.android.util.AndroidBundle; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| /** |
| * Dialog to decide where to create a res/ subdirectory (e.g., layout/, values-foo/, etc.) and how |
| * to name the subdirectory based on resource type and chosen configuration. |
| */ |
| public class BlazeCreateResourceDirectoryDialog extends CreateResourceDirectoryDialogBase { |
| |
| private JComboBox myResourceTypeComboBox; |
| private JPanel myDeviceConfiguratorWrapper; |
| private JTextField myDirectoryNameTextField; |
| private JPanel myContentPanel; |
| private JBLabel myErrorLabel; |
| private ComboboxWithBrowseButton myResDirCombo; |
| private JBLabel myResDirLabel; |
| |
| private final DeviceConfiguratorPanel myDeviceConfiguratorPanel; |
| private ElementCreatingValidator myValidator; |
| private ValidatorFactory myValidatorFactory; |
| private PsiDirectory myResDirectory; |
| private DataContext myDataContext; |
| |
| public BlazeCreateResourceDirectoryDialog( |
| Project project, |
| @Nullable Module module, |
| @Nullable ResourceFolderType resType, |
| @Nullable PsiDirectory resDirectory, |
| @Nullable DataContext dataContext, |
| ValidatorFactory validatorFactory) { |
| super(project); |
| setupUi(); |
| myResDirectory = resDirectory; |
| myDataContext = dataContext; |
| myValidatorFactory = validatorFactory; |
| myResourceTypeComboBox.setModel(new EnumComboBoxModel<>(ResourceFolderType.class)); |
| myResourceTypeComboBox.setRenderer( |
| new ListCellRendererWrapper() { |
| @Override |
| public void customize( |
| JList list, Object value, int index, boolean selected, boolean hasFocus) { |
| if (value instanceof ResourceFolderType) { |
| setText(((ResourceFolderType) value).getName()); |
| } |
| } |
| }); |
| |
| myDeviceConfiguratorPanel = |
| setupDeviceConfigurationPanel( |
| myResourceTypeComboBox, myDirectoryNameTextField, myErrorLabel); |
| myDeviceConfiguratorWrapper.add(myDeviceConfiguratorPanel, BorderLayout.CENTER); |
| myResourceTypeComboBox.addActionListener(e -> myDeviceConfiguratorPanel.applyEditors()); |
| |
| if (resType != null) { |
| myResourceTypeComboBox.setSelectedItem(resType); |
| myResourceTypeComboBox.setEnabled(false); |
| } else { |
| // Select values by default if not otherwise specified |
| myResourceTypeComboBox.setSelectedItem(ResourceFolderType.VALUES); |
| } |
| |
| // If myResDirectory is known before this, just use that. |
| myResDirLabel.setVisible(false); |
| myResDirCombo.setVisible(false); |
| myResDirCombo.addBrowseFolderListener( |
| project, FileChooserDescriptorFactory.createSingleFolderDescriptor()); |
| if (myResDirectory == null) { |
| assert dataContext != null; |
| assert module != null; |
| // Try to figure out from context (e.g., right click in project view). |
| VirtualFile contextFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); |
| if (contextFile != null) { |
| PsiManager manager = PsiManager.getInstance(project); |
| VirtualFile virtualDirectory = |
| BlazeCreateResourceUtils.getResDirFromDataContext(contextFile); |
| PsiDirectory directory = |
| virtualDirectory != null ? manager.findDirectory(virtualDirectory) : null; |
| if (directory != null) { |
| myResDirectory = directory; |
| } else { |
| // As a last resort, if we have poor context |
| // e.g., from File > New w/ a .java file open, set up the UI. |
| BlazeCreateResourceUtils.setupResDirectoryChoices( |
| module.getProject(), contextFile, myResDirLabel, myResDirCombo); |
| } |
| } |
| } |
| |
| myDeviceConfiguratorPanel.updateAll(); |
| setOKActionEnabled(myDirectoryNameTextField.getText().length() > 0); |
| init(); |
| } |
| |
| @Override |
| protected void doOKAction() { |
| final String dirName = myDirectoryNameTextField.getText(); |
| assert dirName != null; |
| PsiDirectory resourceDirectory = getResourceDirectory(); |
| if (resourceDirectory == null) { |
| Module module = LangDataKeys.MODULE.getData(myDataContext); |
| Messages.showErrorDialog( |
| AndroidBundle.message("check.resource.dir.error", module), CommonBundle.getErrorTitle()); |
| // Not much the user can do, just close the dialog. |
| super.doOKAction(); |
| return; |
| } |
| myValidator = myValidatorFactory.create(resourceDirectory); |
| if (myValidator.checkInput(dirName) && myValidator.canClose(dirName)) { |
| super.doOKAction(); |
| } |
| } |
| |
| @Override |
| protected String getDimensionServiceKey() { |
| return "BlazeCreateResourceDirectoryDialog"; |
| } |
| |
| @Override |
| public JComponent getPreferredFocusedComponent() { |
| if (myResourceTypeComboBox.isEnabled()) { |
| return myResourceTypeComboBox; |
| } else { |
| return myDirectoryNameTextField; |
| } |
| } |
| |
| @Override |
| @NotNull |
| public PsiElement[] getCreatedElements() { |
| return myValidator != null ? myValidator.getCreatedElements() : PsiElement.EMPTY_ARRAY; |
| } |
| |
| @Nullable |
| private PsiDirectory getResourceDirectory() { |
| if (myResDirectory != null) { |
| return myResDirectory; |
| } |
| if (myResDirCombo.isVisible()) { |
| Module contextModule = LangDataKeys.MODULE.getData(myDataContext); |
| assert contextModule != null; |
| return BlazeCreateResourceUtils.getResDirFromUI(contextModule.getProject(), myResDirCombo); |
| } |
| return null; |
| } |
| |
| @Nullable |
| @Override |
| protected JComponent createCenterPanel() { |
| return myContentPanel; |
| } |
| |
| /** Initially generated by IntelliJ from a .form file. */ |
| private void setupUi() { |
| myContentPanel = new JPanel(); |
| myContentPanel.setLayout(new GridLayoutManager(5, 2, new Insets(0, 0, 0, 0), -1, -1)); |
| myContentPanel.setPreferredSize(new Dimension(800, 400)); |
| myResourceTypeComboBox = new JComboBox(); |
| myContentPanel.add( |
| myResourceTypeComboBox, |
| new GridConstraints( |
| 1, |
| 1, |
| 1, |
| 1, |
| GridConstraints.ANCHOR_WEST, |
| GridConstraints.FILL_HORIZONTAL, |
| GridConstraints.SIZEPOLICY_CAN_GROW, |
| GridConstraints.SIZEPOLICY_FIXED, |
| null, |
| null, |
| null, |
| 0, |
| false)); |
| final JBLabel jBLabel1 = new JBLabel(); |
| jBLabel1.setText("Resource type:"); |
| jBLabel1.setDisplayedMnemonic('R'); |
| jBLabel1.setDisplayedMnemonicIndex(0); |
| myContentPanel.add( |
| jBLabel1, |
| new GridConstraints( |
| 1, |
| 0, |
| 1, |
| 1, |
| GridConstraints.ANCHOR_WEST, |
| GridConstraints.FILL_NONE, |
| GridConstraints.SIZEPOLICY_FIXED, |
| GridConstraints.SIZEPOLICY_FIXED, |
| null, |
| null, |
| null, |
| 0, |
| false)); |
| myDeviceConfiguratorWrapper = new JPanel(); |
| myDeviceConfiguratorWrapper.setLayout(new BorderLayout(0, 0)); |
| myContentPanel.add( |
| myDeviceConfiguratorWrapper, |
| new GridConstraints( |
| 3, |
| 0, |
| 1, |
| 2, |
| GridConstraints.ANCHOR_CENTER, |
| GridConstraints.FILL_BOTH, |
| GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, |
| GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, |
| null, |
| null, |
| null, |
| 0, |
| false)); |
| final JLabel label1 = new JLabel(); |
| label1.setText("Directory name:"); |
| label1.setDisplayedMnemonic('D'); |
| label1.setDisplayedMnemonicIndex(0); |
| myContentPanel.add( |
| label1, |
| new GridConstraints( |
| 0, |
| 0, |
| 1, |
| 1, |
| GridConstraints.ANCHOR_WEST, |
| GridConstraints.FILL_NONE, |
| GridConstraints.SIZEPOLICY_FIXED, |
| GridConstraints.SIZEPOLICY_FIXED, |
| null, |
| null, |
| null, |
| 0, |
| false)); |
| myDirectoryNameTextField = new JTextField(); |
| myDirectoryNameTextField.setEnabled(true); |
| myContentPanel.add( |
| myDirectoryNameTextField, |
| new GridConstraints( |
| 0, |
| 1, |
| 1, |
| 1, |
| GridConstraints.ANCHOR_WEST, |
| GridConstraints.FILL_HORIZONTAL, |
| GridConstraints.SIZEPOLICY_WANT_GROW, |
| GridConstraints.SIZEPOLICY_FIXED, |
| null, |
| new Dimension(150, -1), |
| null, |
| 0, |
| false)); |
| myErrorLabel = new JBLabel(); |
| myContentPanel.add( |
| myErrorLabel, |
| new GridConstraints( |
| 4, |
| 0, |
| 1, |
| 2, |
| GridConstraints.ANCHOR_CENTER, |
| GridConstraints.FILL_BOTH, |
| GridConstraints.SIZEPOLICY_FIXED, |
| GridConstraints.SIZEPOLICY_FIXED, |
| null, |
| null, |
| null, |
| 0, |
| false)); |
| myResDirLabel = new JBLabel(); |
| myResDirLabel.setText("Base directory:"); |
| myResDirLabel.setDisplayedMnemonic('B'); |
| myResDirLabel.setDisplayedMnemonicIndex(0); |
| myContentPanel.add( |
| myResDirLabel, |
| new GridConstraints( |
| 2, |
| 0, |
| 1, |
| 1, |
| GridConstraints.ANCHOR_WEST, |
| GridConstraints.FILL_NONE, |
| GridConstraints.SIZEPOLICY_FIXED, |
| GridConstraints.SIZEPOLICY_FIXED, |
| null, |
| null, |
| null, |
| 0, |
| false)); |
| myResDirCombo = new ComboboxWithBrowseButton(); |
| myContentPanel.add( |
| myResDirCombo, |
| new GridConstraints( |
| 2, |
| 1, |
| 1, |
| 1, |
| GridConstraints.ANCHOR_WEST, |
| GridConstraints.FILL_HORIZONTAL, |
| GridConstraints.SIZEPOLICY_CAN_GROW, |
| GridConstraints.SIZEPOLICY_FIXED, |
| null, |
| null, |
| null, |
| 0, |
| false)); |
| jBLabel1.setLabelFor(myResourceTypeComboBox); |
| label1.setLabelFor(myDirectoryNameTextField); |
| myResDirLabel.setLabelFor(myResourceTypeComboBox); |
| } |
| } |