/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.mappingsplugin; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.Document; import org.eclipse.persistence.tools.workbench.framework.context.WorkbenchContext; import org.eclipse.persistence.tools.workbench.framework.ui.dialog.AbstractValidatingDialog; import org.eclipse.persistence.tools.workbench.framework.uitools.RegexpDocument; import org.eclipse.persistence.tools.workbench.framework.uitools.SwingComponentFactory; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClass; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassRepository; import org.eclipse.persistence.tools.workbench.mappingsmodel.project.MWProject; import org.eclipse.persistence.tools.workbench.uitools.app.PropertyValueModel; import org.eclipse.persistence.tools.workbench.uitools.app.ReadOnlyCollectionValueModel; import org.eclipse.persistence.tools.workbench.uitools.app.SimplePropertyValueModel; import org.eclipse.persistence.tools.workbench.uitools.app.swing.ComboBoxModelAdapter; import org.eclipse.persistence.tools.workbench.uitools.app.swing.DocumentAdapter; import org.eclipse.persistence.tools.workbench.utility.CollectionTools; import org.eclipse.persistence.tools.workbench.utility.NameTools; import org.eclipse.persistence.tools.workbench.utility.iterators.TransformationIterator; /** * This dialog will prompt the user for a new class name and, * hopefully, disallow any invalid class names. */ public final class NewClassNameDialog extends AbstractValidatingDialog { private PropertyValueModel shortClassNameHolder; private JTextField shortClassNameTextField; /** The combo box showing all the existing packages in the project. */ private JComboBox packageComboBox; /** The list of current package names. */ protected final Collection packageNames; /** The initially selected package name */ private final String initialPackageName; /** The initially entered class name */ private final String initialShortClassName; /** If this is true the dialog will allow the name of a "stub" type to be entered */ private boolean allowExistingType; private final MWProject project; // ********** constructors ********** NewClassNameDialog(MWProject project, WorkbenchContext context) { this(Collections.EMPTY_SET, project, context); } NewClassNameDialog(Collection packageNames, MWProject project, WorkbenchContext context) { this(packageNames, "", project, context); } public NewClassNameDialog(Collection packageNames, String initialPackageName, MWProject project, WorkbenchContext context) { this(packageNames, initialPackageName, buildInitialShortClassName(initialPackageName, project, context), project, context); } public NewClassNameDialog(Collection packageNames, String initialPackageName, String initialShortClassName, MWProject project, WorkbenchContext context) { super(context); this.packageNames = packageNames; this.initialPackageName = initialPackageName; this.initialShortClassName = initialShortClassName; this.allowExistingType = true; this.project = project; } private static String buildInitialShortClassName(String packageName, MWProject project, WorkbenchContext context) { return NameTools.uniqueNameFor( context.getApplicationContext().getResourceRepository().getString("NEW_CLASS_NAME_DIALOG_INITIAL_CLASS_NAME"), descriptorNamesInPackage(packageName, project) ); } private static Iterator descriptorNamesInPackage(String packageName, MWProject project) { Iterator descriptors = project.descriptorsInPackage(packageName); return new TransformationIterator(descriptors) { protected Object transform(Object next) { return ((MWDescriptor) next).shortName(); } }; } // ********** initialization ********** protected String helpTopicId() { return "dialog.createNewClass"; } protected void initialize() { super.initialize(); this.shortClassNameHolder = new SimplePropertyValueModel(""); this.setTitle(this.resourceRepository().getString("NEW_CLASS_NAME_DIALOG_TITLE")); } protected Component buildMainPanel() { JPanel panel = new JPanel(new GridBagLayout()); GridBagConstraints constraints = new GridBagConstraints(); // package name label JLabel packageLabel = SwingComponentFactory.buildLabel("NEW_CLASS_NAME_DIALOG_PACKAGE_NAME_LABEL", resourceRepository()); constraints.gridx = 0; constraints.gridy = 0; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.weightx = 0; constraints.weighty = 0; constraints.fill = GridBagConstraints.NONE; constraints.anchor = GridBagConstraints.LINE_START; constraints.insets = new Insets(0, 0, 0, 0); panel.add(packageLabel, constraints); // package name combo-box this.packageComboBox = this.buildPackageComboBox(); constraints.gridx = 1; constraints.gridy = 0; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.weightx = 1; constraints.weighty = 0; constraints.fill = GridBagConstraints.HORIZONTAL; constraints.anchor = GridBagConstraints.CENTER; constraints.insets = new Insets(0, 5, 0, 0); panel.add(this.packageComboBox, constraints); packageLabel.setLabelFor(this.packageComboBox); // short class name label JLabel shortClassNameLabel = SwingComponentFactory.buildLabel("NEW_CLASS_NAME_DIALOG_CLASS_NAME_LABEL", resourceRepository()); constraints.gridx = 0; constraints.gridy = 1; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.weightx = 0; constraints.weighty = 0; constraints.fill = GridBagConstraints.NONE; constraints.anchor = GridBagConstraints.LINE_START; constraints.insets = new Insets(5, 0, 0, 0); panel.add(shortClassNameLabel, constraints); // short class name text field this.shortClassNameTextField = new JTextField(buildShortClassNameDocumentAdapter(), null, 40); constraints.gridx = 1; constraints.gridy = 1; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.weightx = 1; constraints.weighty = 0; constraints.fill = GridBagConstraints.HORIZONTAL; constraints.anchor = GridBagConstraints.CENTER; constraints.insets = new Insets(5, 5, 0, 0); panel.add(this.shortClassNameTextField, constraints); shortClassNameLabel.setLabelFor(this.shortClassNameTextField); return panel; } private JComboBox buildPackageComboBox() { JComboBox comboBox = new JComboBox(); comboBox.setEditable(true); JTextField textField = this.packageComboBoxTextField(comboBox); textField.setDocument(new RegexpDocument(RegexpDocument.RE_PACKAGE)); textField.getDocument().addDocumentListener(this.buildShortClassNameDocumentListener()); comboBox.setModel( new ComboBoxModelAdapter( new ReadOnlyCollectionValueModel(this.packageNames), new SimplePropertyValueModel(this.initialPackageName) ) ); return comboBox; } private JTextField packageComboBoxTextField() { return this.packageComboBoxTextField(this.packageComboBox); } private JTextField packageComboBoxTextField(JComboBox comboBox) { return (JTextField) comboBox.getEditor().getEditorComponent(); } protected Component initialFocusComponent() { return this.shortClassNameTextField; } private Document buildShortClassNameDocumentAdapter() { DocumentAdapter adapter = new DocumentAdapter(this.shortClassNameHolder, this.buildShortClassNameDocument()); adapter.addDocumentListener(this.buildShortClassNameDocumentListener()); return adapter; } private RegexpDocument buildShortClassNameDocument() { return new RegexpDocument(RegexpDocument.RE_CLASS); } private DocumentListener buildShortClassNameDocumentListener() { return new DocumentListener() { public void changedUpdate(DocumentEvent e) { this.validateClassName(); } public void insertUpdate(DocumentEvent e) { this.validateClassName(); } public void removeUpdate(DocumentEvent e) { this.validateClassName(); } private void validateClassName() { if (NewClassNameDialog.this.isVisible()) { NewClassNameDialog.this.validateClassName(); } } }; } protected void prepareToShow() { super.prepareToShow(); this.shortClassNameHolder.setValue(this.initialShortClassName); this.shortClassNameTextField.selectAll(); this.validateClassName(); } // ********** public API ********** /** * Set whether the dialog will allow the user to enter the name * of an existing type. An existing type is OK for a new class/descriptor; * but it's not allowed for a renamed class/descriptor. */ public void setAllowExistingType(boolean allowExistingType) { this.allowExistingType = allowExistingType; } public String packageName() { String packageName = this.packageComboBoxTextField().getText().trim(); if (packageName.endsWith(".")) { packageName = packageName.substring(0, packageName.length() - 1); } return packageName; } public String shortClassName() { return this.shortClassNameTextField.getText().trim(); } public String className() { String packageName = this.packageName(); String className = this.shortClassName(); return (packageName.length() == 0) ? className : packageName + '.' + className; } // ********** internal methods ********** void validateClassName() { String shortClassName = this.shortClassName(); String className = this.className(); String classNameToLowerCase = className.toLowerCase(); String message = null; if (shortClassName.length() == 0) { // no short class name specified message = this.resourceRepository().getString("NEW_CLASS_NAME_DIALOG_NO_CLASS_NAME_SPECIFIED"); } else if (NameTools.javaReservedWordsContains(shortClassName)) { // the class name cannot be a Java reserved word message = this.resourceRepository().getString("NEW_CLASS_NAME_DIALOG_CLASS_NAME_INVALID", shortClassName); } else if (MWClassRepository.coreClassNamesContains(className)) { // "core" classes are reserved message = this.resourceRepository().getString("NEW_CLASS_NAME_DIALOG_CLASS_NAME_RESERVED", className); } else { String collisionCoreTypeName = MWClassRepository.coreClassNameIgnoreCase(className); if (collisionCoreTypeName != null) { // "core" classes are reserved message = this.resourceRepository().getString("NEW_CLASS_NAME_DIALOG_CLASS_NAME_RESERVED_DIFFERENT_CASE", collisionCoreTypeName); } else if (className.toLowerCase().equals(this.initialClassName().toLowerCase())) { // no problem - the user can change the class name's case } else { if (CollectionTools.contains(this.descriptorNames(), className) && ! className.equals(this.initialClassName())) { // the descriptor already exists message = this.resourceRepository().getString("NEW_CLASS_NAME_DIALOG_DESCRIPTOR_ALREADY_EXISTS", shortClassName); } else if (CollectionTools.contains(this.descriptorNamesToLowerCase(), classNameToLowerCase)) { // the descriptor already exists with different case message = this.resourceRepository().getString("NEW_CLASS_NAME_DIALOG_DESCRIPTOR_ALREADY_EXISTS_DIFFERENT_CASE"); } else { MWClass collisionType = this.project.getRepository().typeNamedIgnoreCase(className); if (collisionType != null) { if (collisionType.getName().equals(className)) { // the class already exists if ( ! this.allowExistingType) { message = this.resourceRepository().getString("NEW_CLASS_NAME_DIALOG_CLASS_ALREADY_EXISTS", className); } } else { // the class already exists with different case message = this.resourceRepository().getString("NEW_CLASS_NAME_DIALOG_CLASS_ALREADY_EXISTS_DIFFERENT_CASE"); } } else { String[] pkgSegments = this.packageName().split("\\."); for (int i = 0; i < pkgSegments.length; i++) { String pkgSegment = pkgSegments[i]; if (NameTools.javaReservedWordsContains(pkgSegment)) { // the package name cannot contain a Java reserved word message = this.resourceRepository().getString("NEW_CLASS_NAME_DIALOG_CLASS_NAME_INVALID", pkgSegment); break; } } } } } } this.setErrorMessage(message); this.getOKAction().setEnabled(message == null); } private Iterator descriptorNames() { return new TransformationIterator(this.project.descriptors()) { protected Object transform(Object next) { return ((MWDescriptor) next).getName(); } }; } private Iterator descriptorNamesToLowerCase() { return new TransformationIterator(this.descriptorNames()) { protected Object transform(Object next) { return ((String) next).toLowerCase(); } }; } private String initialClassName() { return this.initialPackageName + '.' + this.initialShortClassName; } }