com.intellij.uiDesigner.propertyInspector.editors.string.StringEditorDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.uiDesigner.propertyInspector.editors.string.StringEditorDialog.java

Source

/*
 * Copyright 2000-2009 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 com.intellij.uiDesigner.propertyInspector.editors.string;

import java.awt.CardLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;

import javax.swing.AbstractAction;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;

import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.CommonBundle;
import com.intellij.ide.util.TreeClassChooserFactory;
import com.intellij.ide.util.TreeFileChooser;
import com.intellij.lang.properties.IProperty;
import com.intellij.lang.properties.PropertiesFileType;
import com.intellij.lang.properties.PropertiesReferenceManager;
import com.intellij.lang.properties.PropertiesUtil;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.lang.properties.psi.Property;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.undo.UndoUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressManager;
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.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.uiDesigner.FormEditingUtil;
import com.intellij.uiDesigner.StringDescriptorManager;
import com.intellij.uiDesigner.UIDesignerBundle;
import com.intellij.uiDesigner.binding.FormReferenceProvider;
import com.intellij.uiDesigner.compiler.AsmCodeGenerator;
import com.intellij.uiDesigner.designSurface.GuiEditor;
import com.intellij.uiDesigner.lw.StringDescriptor;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;

/**
 * @author Anton Katilin
 * @author Vladimir Kondratyev
 */
public final class StringEditorDialog extends DialogWrapper {
    private static final Logger LOG = Logger
            .getInstance("#com.intellij.uiDesigner.propertyInspector.editors.string.StringEditorDialog");

    @NonNls
    private static final String CARD_STRING = "string";
    @NonNls
    private static final String CARD_BUNDLE = "bundle";

    private final GuiEditor myEditor;
    /** Descriptor to be edited */
    private StringDescriptor myValue;
    private final MyForm myForm;
    private final Locale myLocale;
    private boolean myDefaultBundleInitialized = false;

    StringEditorDialog(final Component parent, final StringDescriptor descriptor, @Nullable Locale locale,
            final GuiEditor editor) {
        super(parent, true);
        myLocale = locale;

        myEditor = editor;

        myForm = new MyForm();
        setTitle(UIDesignerBundle.message("title.edit.text"));
        setValue(descriptor);

        init(); /* run initialization proc */
    }

    protected String getDimensionServiceKey() {
        return getClass().getName();
    }

    public JComponent getPreferredFocusedComponent() {
        if (myForm.myRbString.isSelected()) {
            return myForm.myTfValue;
        } else {
            return super.getPreferredFocusedComponent();
        }
    }

    @Override
    protected void doOKAction() {
        if (myForm.myRbResourceBundle.isSelected()) {
            final StringDescriptor descriptor = getDescriptor();
            if (descriptor != null && descriptor.getKey().length() > 0) {
                final String value = myForm.myTfRbValue.getText();
                final PropertiesFile propFile = getPropertiesFile(descriptor);
                if (propFile != null && propFile.findPropertyByKey(descriptor.getKey()) == null) {
                    saveCreatedProperty(propFile, descriptor.getKey(), value, myEditor.getPsiFile());
                } else {
                    final String newKeyName = saveModifiedPropertyValue(myEditor.getModule(), descriptor, myLocale,
                            value, myEditor.getPsiFile());
                    if (newKeyName != null) {
                        myForm.myTfKey.setText(newKeyName);
                    }
                }
            }
        }
        super.doOKAction();
    }

    private PropertiesFile getPropertiesFile(final StringDescriptor descriptor) {
        final PropertiesReferenceManager manager = PropertiesReferenceManager.getInstance(myEditor.getProject());
        return manager.findPropertiesFile(myEditor.getModule(), descriptor.getDottedBundleName(), myLocale);
    }

    @Nullable
    public static String saveModifiedPropertyValue(final Module module, final StringDescriptor descriptor,
            final Locale locale, final String editedValue, final PsiFile formFile) {
        final PropertiesReferenceManager manager = PropertiesReferenceManager.getInstance(module.getProject());
        final PropertiesFile propFile = manager.findPropertiesFile(module, descriptor.getDottedBundleName(),
                locale);
        if (propFile != null) {
            final IProperty propertyByKey = propFile.findPropertyByKey(descriptor.getKey());
            if (propertyByKey instanceof Property && !editedValue.equals(propertyByKey.getValue())) {
                final Collection<PsiReference> references = findPropertyReferences((Property) propertyByKey,
                        module);

                String newKeyName = null;
                if (references.size() > 1) {
                    final int rc = Messages.showYesNoCancelDialog(module.getProject(),
                            UIDesignerBundle.message("edit.text.multiple.usages", propertyByKey.getUnescapedKey(),
                                    references.size()),
                            UIDesignerBundle.message("edit.text.multiple.usages.title"),
                            UIDesignerBundle.message("edit.text.change.all"),
                            UIDesignerBundle.message("edit.text.make.unique"), CommonBundle.getCancelButtonText(),
                            Messages.getWarningIcon());
                    if (rc == 2) {
                        return null;
                    }
                    if (rc == 1) {
                        newKeyName = promptNewKeyName(module.getProject(), propFile, descriptor.getKey());
                        if (newKeyName == null)
                            return null;
                    }
                }
                final ReadonlyStatusHandler.OperationStatus operationStatus = ReadonlyStatusHandler
                        .getInstance(module.getProject()).ensureFilesWritable(propFile.getVirtualFile());
                if (operationStatus.hasReadonlyFiles()) {
                    return null;
                }
                final String newKeyName1 = newKeyName;
                CommandProcessor.getInstance().executeCommand(module.getProject(), new Runnable() {
                    public void run() {
                        UndoUtil.markPsiFileForUndo(formFile);
                        ApplicationManager.getApplication().runWriteAction(new Runnable() {
                            public void run() {
                                PsiDocumentManager.getInstance(module.getProject()).commitAllDocuments();
                                try {
                                    if (newKeyName1 != null) {
                                        propFile.addProperty(newKeyName1, editedValue);
                                    } else {
                                        final IProperty propertyByKey = propFile
                                                .findPropertyByKey(descriptor.getKey());
                                        if (propertyByKey != null) {
                                            propertyByKey.setValue(editedValue);
                                        }
                                    }
                                } catch (IncorrectOperationException e) {
                                    LOG.error(e);
                                }
                            }
                        });
                    }
                }, UIDesignerBundle.message("command.update.property"), null);
                return newKeyName;
            }
        }
        return null;
    }

    private static Collection<PsiReference> findPropertyReferences(final Property pproperty, final Module module) {
        final Collection<PsiReference> references = Collections.synchronizedList(new ArrayList<PsiReference>());
        ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
            public void run() {
                ReferencesSearch.search(pproperty).forEach(new Processor<PsiReference>() {
                    public boolean process(final PsiReference psiReference) {
                        PsiMethod method = PsiTreeUtil.getParentOfType(psiReference.getElement(), PsiMethod.class);
                        if (method == null || !AsmCodeGenerator.SETUP_METHOD_NAME.equals(method.getName())) {
                            references.add(psiReference);
                        }
                        return true;
                    }
                });
            }
        }, UIDesignerBundle.message("edit.text.searching.references"), false, module.getProject());
        return references;
    }

    private static String promptNewKeyName(final Project project, final PropertiesFile propFile, final String key) {
        String newName;
        int index = 0;
        do {
            index++;
            newName = key + index;
        } while (propFile.findPropertyByKey(newName) != null);

        InputValidator validator = new InputValidator() {
            public boolean checkInput(String inputString) {
                return inputString.length() > 0 && propFile.findPropertyByKey(inputString) == null;
            }

            public boolean canClose(String inputString) {
                return checkInput(inputString);
            }
        };
        return Messages.showInputDialog(project, UIDesignerBundle.message("edit.text.unique.key.prompt"),
                UIDesignerBundle.message("edit.text.multiple.usages.title"), Messages.getQuestionIcon(), newName,
                validator);
    }

    public static boolean saveCreatedProperty(final PropertiesFile bundle, final String name, final String value,
            final PsiFile formFile) {
        final ReadonlyStatusHandler.OperationStatus operationStatus = ReadonlyStatusHandler
                .getInstance(bundle.getProject()).ensureFilesWritable(bundle.getVirtualFile());
        if (operationStatus.hasReadonlyFiles()) {
            return false;
        }
        CommandProcessor.getInstance().executeCommand(bundle.getProject(), new Runnable() {
            public void run() {
                UndoUtil.markPsiFileForUndo(formFile);
                ApplicationManager.getApplication().runWriteAction(new Runnable() {
                    public void run() {
                        try {
                            bundle.addProperty(name, value);
                        } catch (IncorrectOperationException e1) {
                            LOG.error(e1);
                        }
                    }
                });
            }
        }, UIDesignerBundle.message("command.create.property"), null);
        return true;
    }

    /**
     * @return edited descriptor. If initial descriptor was <code>null</code>
     * and user didn't change anything then this method returns <code>null</code>.
     */
    @Nullable
    StringDescriptor getDescriptor() {
        if (myForm.myRbString.isSelected()) { // plain value
            final String value = myForm.myTfValue.getText();
            if (myValue == null && value.length() == 0) {
                return null;
            } else {
                final StringDescriptor stringDescriptor = StringDescriptor.create(value);
                stringDescriptor.setNoI18n(myForm.myNoI18nCheckbox.isSelected());
                return stringDescriptor;
            }
        } else { // bundled value
            final String bundleName = myForm.myTfBundleName.getText();
            final String key = myForm.myTfKey.getText();
            return new StringDescriptor(bundleName, key);
        }
    }

    /**
     * Applies specified descriptor to the proper card
     */
    private void setValue(final StringDescriptor descriptor) {
        myValue = descriptor;
        final CardLayout cardLayout = (CardLayout) myForm.myCardHolder.getLayout();
        if (descriptor == null || descriptor.getValue() != null) { // trivial descriptor
            myForm.myRbString.setSelected(true);
            myForm.showStringDescriptor(descriptor);
            cardLayout.show(myForm.myCardHolder, CARD_STRING);
        } else { // bundled property
            myForm.myRbResourceBundle.setSelected(true);
            myForm.showResourceBundleDescriptor(descriptor);
            cardLayout.show(myForm.myCardHolder, CARD_BUNDLE);
        }
    }

    protected JComponent createCenterPanel() {
        return myForm.myPanel;
    }

    private final class MyForm {
        private JRadioButton myRbString;
        private JRadioButton myRbResourceBundle;
        private JPanel myCardHolder;
        private JPanel myPanel;
        private JTextArea myTfValue;
        private JCheckBox myNoI18nCheckbox;
        private TextFieldWithBrowseButton myTfBundleName;
        private TextFieldWithBrowseButton myTfKey;
        private JTextField myTfRbValue;
        private JLabel myLblKey;
        private JLabel myLblBundleName;

        public MyForm() {
            myRbString.addActionListener(new ActionListener() {
                public void actionPerformed(final ActionEvent e) {
                    CardLayout cardLayout = (CardLayout) myCardHolder.getLayout();
                    cardLayout.show(myCardHolder, CARD_STRING);
                }
            });

            myRbResourceBundle.addActionListener(new ActionListener() {
                public void actionPerformed(final ActionEvent e) {
                    if (!myDefaultBundleInitialized) {
                        myDefaultBundleInitialized = true;
                        Set<String> bundleNames = FormEditingUtil
                                .collectUsedBundleNames(myEditor.getRootContainer());
                        if (bundleNames.size() > 0) {
                            myTfBundleName.setText(ArrayUtil.toStringArray(bundleNames)[0]);
                        }
                    }
                    CardLayout cardLayout = (CardLayout) myCardHolder.getLayout();
                    cardLayout.show(myCardHolder, CARD_BUNDLE);
                }
            });

            setupResourceBundleCard();
        }

        private void setupResourceBundleCard() {
            // Enable keyboard pressing
            myTfBundleName.registerKeyboardAction(new AbstractAction() {
                public void actionPerformed(final ActionEvent e) {
                    myTfBundleName.getButton().doClick();
                }
            }, KeyStroke.getKeyStroke(myLblBundleName.getDisplayedMnemonic(), KeyEvent.ALT_DOWN_MASK),
                    JComponent.WHEN_IN_FOCUSED_WINDOW);

            myTfBundleName.addActionListener(new ActionListener() {
                public void actionPerformed(final ActionEvent e) {
                    Project project = myEditor.getProject();
                    final String bundleNameText = myTfBundleName.getText().replace('/', '.');
                    PropertiesFile file = PropertiesUtil.getPropertiesFile(bundleNameText, myEditor.getModule(),
                            myLocale);
                    PsiFile initialPropertiesFile = file == null ? null : file.getContainingFile();
                    final GlobalSearchScope moduleScope = GlobalSearchScope
                            .moduleWithDependenciesScope(myEditor.getModule());
                    TreeFileChooser fileChooser = TreeClassChooserFactory.getInstance(project).createFileChooser(
                            UIDesignerBundle.message("title.choose.properties.file"), initialPropertiesFile,
                            PropertiesFileType.INSTANCE, new TreeFileChooser.PsiFileFilter() {
                                public boolean accept(PsiFile file) {
                                    final VirtualFile virtualFile = file.getVirtualFile();
                                    return virtualFile != null && moduleScope.contains(virtualFile);
                                }
                            });
                    fileChooser.showDialog();
                    PropertiesFile propertiesFile = (PropertiesFile) fileChooser.getSelectedFile();
                    if (propertiesFile == null) {
                        return;
                    }
                    final String bundleName = FormReferenceProvider.getBundleName(propertiesFile);
                    if (bundleName == null) {
                        return;
                    }
                    myTfBundleName.setText(bundleName);
                }
            });

            // Enable keyboard pressing
            myTfKey.registerKeyboardAction(new AbstractAction() {
                public void actionPerformed(final ActionEvent e) {
                    myTfKey.getButton().doClick();
                }
            }, KeyStroke.getKeyStroke(myLblKey.getDisplayedMnemonic(), KeyEvent.ALT_DOWN_MASK),
                    JComponent.WHEN_IN_FOCUSED_WINDOW);

            myTfKey.addActionListener(new ActionListener() {
                public void actionPerformed(final ActionEvent e) {
                    // 1. Check that bundle exist. Otherwise we cannot show key chooser
                    final String bundleName = myTfBundleName.getText();
                    if (bundleName.length() == 0) {
                        Messages.showErrorDialog(UIDesignerBundle.message("error.specify.bundle.name"),
                                CommonBundle.getErrorTitle());
                        return;
                    }
                    final PropertiesReferenceManager manager = PropertiesReferenceManager
                            .getInstance(myEditor.getProject());
                    final PropertiesFile bundle = manager.findPropertiesFile(myEditor.getModule(),
                            bundleName.replace('/', '.'), myLocale);
                    if (bundle == null) {
                        Messages.showErrorDialog(
                                UIDesignerBundle.message("error.bundle.does.not.exist", bundleName),
                                CommonBundle.getErrorTitle());
                        return;
                    }

                    // 2. Show key chooser
                    final KeyChooserDialog dialog = new KeyChooserDialog(myTfKey, bundle, bundleName,
                            myTfKey.getText(), // key to preselect
                            myEditor);
                    dialog.show();
                    if (!dialog.isOK()) {
                        return;
                    }

                    // 3. Apply new key/value
                    final StringDescriptor descriptor = dialog.getDescriptor();
                    if (descriptor == null) {
                        return;
                    }
                    myTfKey.setText(descriptor.getKey());
                    myTfRbValue.setText(descriptor.getResolvedValue());
                }
            });
        }

        public void showStringDescriptor(@Nullable final StringDescriptor descriptor) {
            myTfValue.setText(
                    StringDescriptorManager.getInstance(myEditor.getModule()).resolve(descriptor, myLocale));
            myNoI18nCheckbox.setSelected(descriptor != null && descriptor.isNoI18n());
        }

        public void showResourceBundleDescriptor(@NotNull final StringDescriptor descriptor) {
            final String key = descriptor.getKey();
            LOG.assertTrue(key != null);
            myTfBundleName.setText(descriptor.getBundleName());
            myTfKey.setText(key);
            myTfRbValue.setText(
                    StringDescriptorManager.getInstance(myEditor.getModule()).resolve(descriptor, myLocale));
        }
    }
}