com.google.idea.blaze.android.resources.actions.BlazeCreateResourceFileDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.google.idea.blaze.android.resources.actions.BlazeCreateResourceFileDialog.java

Source

/*
 * 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.ide.common.resources.configuration.FolderConfiguration;
import com.android.resources.ResourceConstants;
import com.android.resources.ResourceFolderType;
import com.android.tools.idea.res.ResourceNameValidator;
import com.google.common.annotations.VisibleForTesting;
import com.intellij.CommonBundle;
import com.intellij.ide.actions.TemplateKindCombo;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
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.DocumentAdapter;
import com.intellij.ui.TextFieldWithAutoCompletion;
import com.intellij.ui.TextFieldWithAutoCompletion.StringsCompletionProvider;
import com.intellij.ui.components.JBLabel;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.util.PlatformIcons;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Insets;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import org.jetbrains.android.actions.CreateResourceFileDialogBase;
import org.jetbrains.android.actions.CreateTypedResourceFileAction;
import org.jetbrains.android.actions.ElementCreatingValidator;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.uipreview.DeviceConfiguratorPanel;
import org.jetbrains.android.util.AndroidBundle;

/**
 * Dialog to decide where and how to create a resource file of a given type (which base res/
 * directory, which subdirectory, and how to name the new file).
 */
public class BlazeCreateResourceFileDialog extends CreateResourceFileDialogBase {
    private JTextField myFileNameField;
    private TemplateKindCombo myResourceTypeCombo;
    private JPanel myPanel;
    private JLabel myUpDownHint;
    private JLabel myResTypeLabel;
    private JPanel myDeviceConfiguratorWrapper;
    private JBLabel myErrorLabel;
    private JTextField myDirectoryNameTextField;
    private JPanel myRootElementFieldWrapper;
    private JBLabel myRootElementLabel;
    private JLabel myFileNameLabel;
    private ComboboxWithBrowseButton myResDirCombo;
    private JBLabel myResDirLabel;
    private TextFieldWithAutoCompletion<String> myRootElementField;
    private ElementCreatingValidator myValidator;
    private ValidatorFactory myValidatorFactory;

    private final DeviceConfiguratorPanel myDeviceConfiguratorPanel;
    private final AndroidFacet myFacet;
    private PsiDirectory myResDirectory;

    public BlazeCreateResourceFileDialog(AndroidFacet facet, Collection<CreateTypedResourceFileAction> actions,
            ResourceFolderType folderType, String filename, String rootElement,
            FolderConfiguration folderConfiguration, boolean chooseFileName, boolean chooseModule,
            PsiDirectory resDirectory, DataContext dataContext, ValidatorFactory validatorFactory) {
        super(facet.getModule().getProject());
        setupUi();
        myFacet = facet;
        myResDirectory = resDirectory;
        myValidatorFactory = validatorFactory;

        myResTypeLabel.setLabelFor(myResourceTypeCombo);
        myResourceTypeCombo.registerUpDownHint(myFileNameField);
        myUpDownHint.setIcon(PlatformIcons.UP_DOWN_ARROWS);
        String selectedTemplate = setupSubActions(actions, myResourceTypeCombo, folderType);

        myDeviceConfiguratorPanel = setupDeviceConfigurationPanel(myDirectoryNameTextField, myResourceTypeCombo,
                myErrorLabel);
        if (folderConfiguration != null) {
            myDeviceConfiguratorPanel.init(folderConfiguration);
        }

        myResourceTypeCombo.getComboBox().addActionListener(e -> {
            myDeviceConfiguratorPanel.applyEditors();
            updateRootElementTextField();
        });

        if (folderType != null && selectedTemplate != null) {
            final boolean v = folderType == ResourceFolderType.LAYOUT;
            myRootElementLabel.setVisible(v);
            myRootElementFieldWrapper.setVisible(v);

            myResTypeLabel.setVisible(false);
            myResourceTypeCombo.setVisible(false);
            myUpDownHint.setVisible(false);
            myResourceTypeCombo.setSelectedName(selectedTemplate);
        } else {
            // Select values by default if not otherwise specified
            myResourceTypeCombo.setSelectedName(ResourceConstants.FD_RES_VALUES);
        }

        boolean validateImmediately = false;
        if (filename != null && getNameError(filename) != null) {
            chooseFileName = true;
            validateImmediately = true;
        }

        if (filename != null) {
            if (!chooseFileName) {
                myFileNameField.setVisible(false);
                myFileNameLabel.setVisible(false);
            }
            myFileNameField.setText(filename);
        }

        Project project = myFacet.getModule().getProject();
        // Set up UI to choose the base directory if needed (use context to prune selection).
        // There may be a resource directory already pre-selected, in which case hide the UI by default.
        myResDirLabel.setVisible(false);
        myResDirCombo.setVisible(false);
        myResDirCombo.addBrowseFolderListener(project, FileChooserDescriptorFactory.createSingleFolderDescriptor());
        if (myResDirectory == 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(project, contextFile, myResDirLabel,
                            myResDirCombo);
                }
            } else {
                // As a last resort, if we have no context, set up the UI.
                BlazeCreateResourceUtils.setupResDirectoryChoices(project, null, myResDirLabel, myResDirCombo);
            }
        }

        myDeviceConfiguratorPanel.updateAll();
        myDeviceConfiguratorWrapper.add(myDeviceConfiguratorPanel, BorderLayout.CENTER);
        updateOkAction();
        updateRootElementTextField();

        if (rootElement != null) {
            myRootElementLabel.setVisible(false);
            myRootElementFieldWrapper.setVisible(false);
            myRootElementField.setText(rootElement);
        }
        init();

        setTitle(AndroidBundle.message("new.resource.dialog.title"));

        myFileNameField.getDocument().addDocumentListener(new DocumentAdapter() {
            @Override
            public void textChanged(DocumentEvent event) {
                validateName();
            }
        });
        myResourceTypeCombo.getComboBox().addActionListener(actionEvent -> validateName());
        if (validateImmediately) {
            validateName();
        }
    }

    @Override
    protected void updateOkAction() {
        boolean enabled = myDirectoryNameTextField.getText().length() > 0;
        enabled = enabled && getNameError(myFileNameField.getText()) == null;
        setOKActionEnabled(enabled);
    }

    @Nullable
    private String getNameError(String fileName) {
        String typeName = myResourceTypeCombo.getSelectedName();
        if (typeName != null) {
            ResourceFolderType type = ResourceFolderType.getFolderType(typeName);
            if (type != null) {
                ResourceNameValidator validator = ResourceNameValidator.create(true, type);
                return validator.getErrorText(fileName);
            }
        }

        return null;
    }

    private void validateName() {
        setErrorText(getNameError(myFileNameField.getText()));
        updateOkAction();
    }

    private void updateRootElementTextField() {
        final CreateTypedResourceFileAction action = getSelectedAction(myResourceTypeCombo);

        if (action != null) {
            final List<String> allowedTagNames = action.getSortedAllowedTagNames(myFacet);
            myRootElementField = new TextFieldWithAutoCompletion<>(myFacet.getModule().getProject(),
                    new StringsCompletionProvider(allowedTagNames, null), true, null);
            myRootElementField.setEnabled(allowedTagNames.size() > 1);
            myRootElementField.setText(!action.isChooseTagName() ? action.getDefaultRootTag() : "");
            myRootElementFieldWrapper.removeAll();
            myRootElementFieldWrapper.add(myRootElementField, BorderLayout.CENTER);
            myRootElementLabel.setLabelFor(myRootElementField);
        }
    }

    @VisibleForTesting
    @Override
    public String getFileName() {
        return myFileNameField.getText().trim();
    }

    @Override
    protected void doOKAction() {
        String fileName = myFileNameField.getText().trim();
        final CreateTypedResourceFileAction action = getSelectedAction(myResourceTypeCombo);
        assert action != null;

        if (fileName.length() == 0) {
            Messages.showErrorDialog(myPanel, AndroidBundle.message("file.name.not.specified.error"),
                    CommonBundle.getErrorTitle());
            return;
        }

        String rootElement = getRootElement();
        if (!action.isChooseTagName() && rootElement.length() == 0) {
            Messages.showErrorDialog(myPanel, AndroidBundle.message("root.element.not.specified.error"),
                    CommonBundle.getErrorTitle());
            return;
        }

        final String subdirName = getSubdirName();
        if (subdirName.length() == 0) {
            Messages.showErrorDialog(myPanel, AndroidBundle.message("directory.not.specified.error"),
                    CommonBundle.getErrorTitle());
            return;
        }

        final String errorMessage = getNameError(fileName);
        if (errorMessage != null) {
            Messages.showErrorDialog(myPanel, errorMessage, CommonBundle.getErrorTitle());
            return;
        }
        PsiDirectory resDir = getResourceDirectory();
        if (resDir == null) {
            Messages.showErrorDialog(myPanel,
                    AndroidBundle.message("check.resource.dir.error", myFacet.getModule()),
                    CommonBundle.getErrorTitle());
            super.doOKAction();
            return;
        }

        myValidator = myValidatorFactory.create(resDir, subdirName, rootElement);
        if (myValidator.checkInput(fileName) && myValidator.canClose(fileName)) {
            super.doOKAction();
        }
    }

    @Override
    public PsiElement[] getCreatedElements() {
        return myValidator != null ? myValidator.getCreatedElements() : PsiElement.EMPTY_ARRAY;
    }

    @Override
    protected String getDimensionServiceKey() {
        return "BlazeCreateResourceFileDialog";
    }

    @Nullable
    private PsiDirectory getResourceDirectory() {
        if (myResDirectory != null) {
            return myResDirectory;
        }
        return BlazeCreateResourceUtils.getResDirFromUI(myFacet.getModule().getProject(), myResDirCombo);
    }

    private String getSubdirName() {
        return myDirectoryNameTextField.getText().trim();
    }

    protected String getRootElement() {
        return myRootElementField.getText().trim();
    }

    @Override
    protected JComponent createCenterPanel() {
        return myPanel;
    }

    @Override
    public JComponent getPreferredFocusedComponent() {
        String name = myFileNameField.getText();
        if (name.length() == 0 || getNameError(name) != null) {
            return myFileNameField;
        } else if (myResourceTypeCombo.isVisible()) {
            return myResourceTypeCombo;
        } else if (myRootElementFieldWrapper.isVisible()) {
            return myRootElementField;
        }
        return myDirectoryNameTextField;
    }

    /** Initially generated by IntelliJ from a .form file. */
    private void setupUi() {
        myPanel = new JPanel();
        myPanel.setLayout(new GridLayoutManager(7, 3, new Insets(0, 0, 0, 0), -1, -1));
        myPanel.setPreferredSize(new Dimension(800, 400));
        myFileNameLabel = new JLabel();
        myFileNameLabel.setText("File name:");
        myFileNameLabel.setDisplayedMnemonic('F');
        myFileNameLabel.setDisplayedMnemonicIndex(0);
        myPanel.add(myFileNameLabel,
                new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
                        false));
        myFileNameField = new JTextField();
        myPanel.add(myFileNameField,
                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));
        myResTypeLabel = new JLabel();
        myResTypeLabel.setText("Resource type:");
        myResTypeLabel.setDisplayedMnemonic('R');
        myResTypeLabel.setDisplayedMnemonicIndex(0);
        myPanel.add(myResTypeLabel,
                new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
                        false));
        myUpDownHint = new JLabel();
        myUpDownHint.setToolTipText("Pressing Up or Down arrows while in editor changes the kind");
        myPanel.add(myUpDownHint,
                new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
                        false));
        myResourceTypeCombo = new TemplateKindCombo();
        myPanel.add(myResourceTypeCombo,
                new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        myDeviceConfiguratorWrapper = new JPanel();
        myDeviceConfiguratorWrapper.setLayout(new BorderLayout(0, 0));
        myPanel.add(myDeviceConfiguratorWrapper,
                new GridConstraints(5, 0, 1, 3, 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));
        myErrorLabel = new JBLabel();
        myPanel.add(myErrorLabel,
                new GridConstraints(6, 0, 1, 3, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
                        GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
                        false));
        final JBLabel jBLabel1 = new JBLabel();
        jBLabel1.setText("Sub-directory:");
        jBLabel1.setDisplayedMnemonic('Y');
        jBLabel1.setDisplayedMnemonicIndex(12);
        myPanel.add(jBLabel1,
                new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
                        false));
        myDirectoryNameTextField = new JTextField();
        myDirectoryNameTextField.setEditable(true);
        myDirectoryNameTextField.setEnabled(true);
        myPanel.add(myDirectoryNameTextField,
                new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
                        GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null,
                        new Dimension(150, -1), null, 0, false));
        myRootElementLabel = new JBLabel();
        myRootElementLabel.setText("Root element:");
        myRootElementLabel.setDisplayedMnemonic('E');
        myRootElementLabel.setDisplayedMnemonicIndex(5);
        myPanel.add(myRootElementLabel,
                new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
                        false));
        myRootElementFieldWrapper = new JPanel();
        myRootElementFieldWrapper.setLayout(new BorderLayout(0, 0));
        myPanel.add(myRootElementFieldWrapper,
                new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        myResDirLabel = new JBLabel();
        myResDirLabel.setText("Base directory:");
        myResDirLabel.setDisplayedMnemonic('B');
        myResDirLabel.setDisplayedMnemonicIndex(0);
        myPanel.add(myResDirLabel,
                new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
                        false));
        myResDirCombo = new ComboboxWithBrowseButton();
        myPanel.add(myResDirCombo,
                new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
                        GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
                        false));
        myFileNameLabel.setLabelFor(myFileNameField);
        jBLabel1.setLabelFor(myDirectoryNameTextField);
    }
}