Java tutorial
/* * 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); } }