/*******************************************************************************
* 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.scplugin.ui.session.basic;
// JDK
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.Document;
import org.eclipse.persistence.tools.workbench.framework.context.WorkbenchContext;
import org.eclipse.persistence.tools.workbench.framework.ui.dialog.AbstractDialog;
import org.eclipse.persistence.tools.workbench.framework.uitools.ComponentAligner;
import org.eclipse.persistence.tools.workbench.framework.uitools.GroupBox;
import org.eclipse.persistence.tools.workbench.framework.uitools.Pane;
import org.eclipse.persistence.tools.workbench.framework.uitools.RegexpDocument;
import org.eclipse.persistence.tools.workbench.framework.uitools.SwingComponentFactory;
import org.eclipse.persistence.tools.workbench.scplugin.model.adapter.DatabaseSessionAdapter;
import org.eclipse.persistence.tools.workbench.scplugin.model.adapter.TopLinkSessionsAdapter;
import org.eclipse.persistence.tools.workbench.scplugin.ui.tools.ClassChooserTools;
import org.eclipse.persistence.tools.workbench.uitools.ComponentEnabler;
import org.eclipse.persistence.tools.workbench.uitools.app.PropertyAspectAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.PropertyValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.TransformationPropertyValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.DocumentAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.RadioButtonModelAdapter;
import org.eclipse.persistence.tools.workbench.utility.AbstractModel;
import org.eclipse.persistence.tools.workbench.utility.io.FileTools;
// Mapping Workbench
/**
* @version 10.1.3
* @author Pascal Filion
*/
final class ProjectTypeEditDialog extends AbstractDialog
{
/**
* The <code>DatabaseSessionAdapter</code> where a project is either edited
* or added.
*/
private DatabaseSessionAdapter databaseSession;
/**
* Keeps a reference in order to set the initial focus.
*/
private JComponent projectClassWidgets;
/**
*
*/
private ProjectTypeEditor projectType;
private String helpTopicId;
/**
* Keeps a reference in order to set the initial focus.
*/
private JComponent projectXmlWidgets;
/**
* Creates a new <code>ProjectTypeEditDialog</code>.
*
* @param context The context to be used by this pane
* @param title
* @param databaseSession
* @param projectType
*/
ProjectTypeEditDialog(WorkbenchContext context,
String title,
DatabaseSessionAdapter databaseSession,
ProjectTypeUpdater projectType, String helpTopicId)
{
super(context, title);
initialize(databaseSession, projectType, helpTopicId);
}
/**
* Shows the file chooser in order to choose an XML file.
*/
private void addProjectXML()
{
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileFilter(new XmlFileFilter());
fileChooser.setCurrentDirectory(retrieveLastDirectory());
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int result = fileChooser.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION)
{
File selectedFile = fileChooser.getSelectedFile();
preferences().put("location", selectedFile.getParent());
projectType.setProjectXml(selectedFile.getAbsolutePath());
}
}
/**
* Creates the <code>ActionListener</code> responsible to show the class
* chooser dialog in order to add an additional project class.
*
* @return A new <code>ActionListener</code>
*/
private ActionListener buildClassBrowseAction()
{
return new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
ClassChooserTools.promptForType
(
getWorkbenchContext(),
databaseSession.getClassRepository(),
buildProjectClassHolder()
);
}
};
}
private void buildClassComponentEnabler(JComponent component)
{
new ComponentEnabler(buildProjectTypeClassHolder(), component.getComponents());
}
/**
* Creates a container that has a label and the given chooser.
*
* @param key The key used to retrieve the localized string
* @param component The component that is labeled
* @param rightComponent A component to be added to the right of the labeled
* component, usually a browse button would be passed, <code>null</code> can
* also be passed so that no filler will be added by default
* @return A new component containing a label and the chooser
*/
private JComponent buildLabeledComponent(String key,
JComponent component,
JComponent rightComponent,
ComponentAligner leftAligner,
ComponentAligner rightAligner)
{
Pane pane = new Pane(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
// Left component
JLabel label = SwingComponentFactory.buildLabel(key, resourceRepository());
pane.add(label, constraints);
leftAligner.add(label);
// Center component
constraints.weightx = 1;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.insets = new Insets(0, 5, 0, 0);
pane.add(component, constraints);
component.setName(key);
label.setLabelFor(component);
// Right component
if (rightComponent != null)
{
constraints.weightx = 0;
constraints.fill = GridBagConstraints.NONE;
pane.add(rightComponent, constraints);
rightComponent.setName(key);
rightAligner.add(rightComponent);
}
return pane;
}
/**
* Creates a container that has a label and a text field.
*
* @param key The key used to retrieve the localized string
* @param document The document of the text field
* @param rightComponent A component to be added to the right of the labeled
* component, usually a browse button would be passed
* @return A new component containing a label and a text field
*/
private JComponent buildLabeledTextField(String key,
Document document,
JComponent rightComponent,
ComponentAligner leftAligner,
ComponentAligner rightAligner)
{
JTextField textField = new JTextField(document, null, 40);
return buildLabeledComponent(key, textField, rightComponent, leftAligner, rightAligner);
}
/**
* Creates the widgets and layout of the main pane.
*
* @return The container with all its widgets
*/
protected Component buildMainPanel()
{
GridBagConstraints constraints = new GridBagConstraints();
ComponentAligner leftAligner = new ComponentAligner();
ComponentAligner rightAligner = new ComponentAligner();
JPanel container = new JPanel(new GridBagLayout());
container.setBorder(SwingComponentFactory.buildStandardEmptyBorder());
// XML Project Type widgets
JRadioButton xmlFileButton = SwingComponentFactory.buildRadioButton
(
"PROJECT_TYPE_EDIT_DIALOG_XML_RADIO_BUTTON",
buildProjectTypeButtonModel(Boolean.TRUE),
resourceRepository()
);
JButton xmlBrowseButton = SwingComponentFactory.buildButton("PROJECT_TYPE_EDIT_DIALOG_XML_BROWSE_BUTTON", resourceRepository());
xmlBrowseButton.addActionListener(buildXMLBrowseAction());
projectXmlWidgets = buildLabeledTextField
(
"PROJECT_TYPE_EDIT_DIALOG_XML_FIELD",
buildProjectXmlDocumentAdapter(),
xmlBrowseButton,
leftAligner,
rightAligner
);
GroupBox groupBox = new GroupBox(xmlFileButton, projectXmlWidgets);
buildXmlFileComponentEnabler(projectXmlWidgets);
constraints.gridx = 0;
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, 0, 0, 0);
container.add(groupBox, constraints);
// Class Project Type widgets
JRadioButton classTypeButton = SwingComponentFactory.buildRadioButton
(
"PROJECT_TYPE_EDIT_DIALOG_CLASS_RADIO_BUTTON",
buildProjectTypeButtonModel(Boolean.FALSE),
resourceRepository()
);
JButton classBrowseButton = SwingComponentFactory.buildButton("PROJECT_TYPE_EDIT_DIALOG_CLASS_BROWSE_BUTTON", resourceRepository());
classBrowseButton.addActionListener(buildClassBrowseAction());
projectClassWidgets = buildLabeledTextField
(
"PROJECT_TYPE_EDIT_DIALOG_CLASS_FIELD",
buildProjectClassDocumentAdapter(),
classBrowseButton,
leftAligner,
rightAligner
);
groupBox = new GroupBox(classTypeButton, projectClassWidgets);
buildClassComponentEnabler(projectClassWidgets);
constraints.gridx = 0;
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, 0, 0, 0);
container.add(groupBox, constraints);
return container;
}
/**
* Creates the <code>DocumentAdapter</code> that keeps the value from the
* text field in sync with the Project value in the model and vice
* versa.
*
* @return A new <code>Document</code>
*/
private Document buildProjectClassDocumentAdapter()
{
return new DocumentAdapter(buildProjectClassHolder(), RegexpDocument.buildDocument(RegexpDocument.RE_FULLY_QUALIFIED_CLASS_NAME));
}
private PropertyValueModel buildProjectClassHolder()
{
return new PropertyAspectAdapter(ProjectTypeEditor.PROJECT_CLASS_PROPERTY, projectType)
{
protected Object getValueFromSubject()
{
ProjectTypeEditor projectType = (ProjectTypeEditor) subject;
return projectType.getProjectClass();
}
protected void setValueOnSubject(Object value)
{
ProjectTypeEditor projectType = (ProjectTypeEditor) subject;
projectType.setProjectClass((String) value);
}
};
}
private ButtonModel buildProjectTypeButtonModel(Object buttonValue)
{
return new RadioButtonModelAdapter(buildProjectTypeHolder(),
buttonValue);
}
private PropertyValueModel buildProjectTypeClassHolder()
{
return new TransformationPropertyValueModel(buildProjectTypeHolder())
{
protected Object transform(Object value)
{
return Boolean.valueOf(! Boolean.TRUE.equals(value));
}
};
}
private PropertyValueModel buildProjectTypeHolder()
{
return new PropertyAspectAdapter(ProjectTypeEditor.PROJECT_TYPE_XML_PROPERTY, projectType)
{
protected Object getValueFromSubject()
{
ProjectTypeEditor projectType = (ProjectTypeEditor) subject;
return Boolean.valueOf(projectType.isProjectTypeXml());
}
protected void setValueOnSubject(Object value)
{
ProjectTypeEditor projectType = (ProjectTypeEditor) subject;
projectType.setProjectTypeXml(Boolean.TRUE.equals(value));
}
};
}
/**
* Creates the <code>DocumentAdapter</code> that keeps the value from the
* text field in sync with the Project value in the model and vice
* versa.
*
* @return A new <code>Document</code>
*/
private Document buildProjectXmlDocumentAdapter()
{
return new DocumentAdapter(buildProjectXmlHolder());
}
private PropertyValueModel buildProjectXmlHolder()
{
return new PropertyAspectAdapter(ProjectTypeEditor.PROJECT_XML_PROPERTY, projectType)
{
protected Object getValueFromSubject()
{
ProjectTypeEditor projectType = (ProjectTypeEditor) subject;
return projectType.getProjectXml();
}
protected void setValueOnSubject(Object value)
{
ProjectTypeEditor projectType = (ProjectTypeEditor) subject;
projectType.setProjectXml((String) value);
}
};
}
/**
* Creates the <code>ActionListener</code> responsible to show the file
* chooser dialog in order to add an additional project XML.
*
* @return A new <code>ActionListener</code>
*/
private ActionListener buildXMLBrowseAction()
{
return new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
addProjectXML();
}
};
}
/**
* Creates
*
* @param component
*/
private void buildXmlFileComponentEnabler(JComponent component)
{
new ComponentEnabler(buildProjectTypeHolder(), component.getComponents());
}
/**
* Returns
*
* @return
*/
protected String helpTopicId()
{
return helpTopicId;
}
/**
* Returns the component that should receive the initial focus. Depending on
* the selected project type, the corresponding text field will be returned.
*
* @return Either the text field of the XML or the Class widgets
*/
protected Component initialFocusComponent()
{
if (databaseSession.isPrimaryProjectXml())
return projectXmlWidgets.getComponent(1);
return projectClassWidgets.getComponent(1);
}
/**
* Initializes this <code>ProjectTypeEditDialog</code>.
*
* @param databaseSession The session to be edited for its project
* @param projectType
*/
private void initialize(DatabaseSessionAdapter databaseSession,
ProjectTypeUpdater updater, String helpTopicId)
{
this.databaseSession = databaseSession;
this.helpTopicId = helpTopicId;
projectType = new ProjectTypeEditor(updater);
}
/**
*
*/
public void okConfirmed()
{
super.okConfirmed();
projectType.apply();
}
/**
* Retrieves the last saved location from the preferences if one exists
* otherwise return the user home directory.
*
* @return The location where the file chooser will be at
*/
private File retrieveLastDirectory()
{
TopLinkSessionsAdapter topLinkSessions = (TopLinkSessionsAdapter) databaseSession.getParent();
File saveDirectory = topLinkSessions.getSaveDirectory();
// This happens when the sessions.xml is an untitled file
if (saveDirectory == null)
saveDirectory = FileTools.userHomeDirectory();
return new File(preferences().get("location", saveDirectory.getPath()));
}
/**
*
*/
private static class ProjectTypeEditor extends AbstractModel
{
private String projectClass;
private boolean projectTypeXml;
private String projectXml;
private ProjectTypeUpdater updater;
public static final String PROJECT_CLASS_PROPERTY = "ProjectClass";
public static final String PROJECT_TYPE_XML_PROPERTY = "projectTypeXml";
public static final String PROJECT_XML_PROPERTY = "ProjectXml";
public ProjectTypeEditor(ProjectTypeUpdater updater)
{
super();
initialize(updater);
}
public void apply()
{
updater.apply(projectTypeXml, projectTypeXml ? projectXml : projectClass);
}
public String getProjectClass()
{
return projectClass;
}
public String getProjectXml()
{
return projectXml;
}
private void initialize(ProjectTypeUpdater updater)
{
this.updater = updater;
setProjectTypeXml(updater.isProjectXml());
if (projectTypeXml)
{
setProjectXml(updater.getProjectName());
}
else
{
setProjectClass(updater.getProjectName());
}
}
public boolean isProjectTypeXml()
{
return projectTypeXml;
}
public void setProjectClass(String projectClass)
{
String oldProjectClass = getProjectClass();
this.projectClass = projectClass;
firePropertyChanged(PROJECT_CLASS_PROPERTY, oldProjectClass, projectClass);
}
public void setProjectTypeXml(boolean projectTypeXml)
{
boolean oldProjectTypeXml = isProjectTypeXml();
this.projectTypeXml = projectTypeXml;
firePropertyChanged(PROJECT_TYPE_XML_PROPERTY, oldProjectTypeXml, projectTypeXml);
}
public void setProjectXml(String projectXml)
{
String oldProjectXml = getProjectXml();
this.projectXml = projectXml;
firePropertyChanged(PROJECT_XML_PROPERTY, oldProjectXml, projectXml);
}
}
public interface ProjectTypeUpdater
{
public void apply(boolean projectTypeXml, String projectName);
public String getProjectName();
public boolean isProjectXml();
}
/**
* The <code>FileFilter</code> used by the File chooser to restrict the
* selection to be XML files only.
*/
private class XmlFileFilter extends FileFilter
{
public boolean accept(File file)
{
return file.isDirectory() || ".xml".equalsIgnoreCase(FileTools.extension(file));
}
public String getDescription()
{
return resourceRepository().getString("SESSION_PROJECT_ADVANCED_FILE_CHOOSER_DESCRIPTION");
}
}
}