/*******************************************************************************
* 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.ui.project;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import javax.swing.Icon;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import javax.swing.filechooser.FileFilter;
import org.eclipse.persistence.tools.workbench.framework.action.FrameworkAction;
import org.eclipse.persistence.tools.workbench.framework.app.ApplicationNode;
import org.eclipse.persistence.tools.workbench.framework.app.CompositeIconBuilder;
import org.eclipse.persistence.tools.workbench.framework.app.GroupContainerDescription;
import org.eclipse.persistence.tools.workbench.framework.app.IconBuilder;
import org.eclipse.persistence.tools.workbench.framework.app.MenuGroupDescription;
import org.eclipse.persistence.tools.workbench.framework.app.NavigatorSelectionModel;
import org.eclipse.persistence.tools.workbench.framework.app.RootMenuDescription;
import org.eclipse.persistence.tools.workbench.framework.app.ToolBarDescription;
import org.eclipse.persistence.tools.workbench.framework.context.ApplicationContext;
import org.eclipse.persistence.tools.workbench.framework.context.WorkbenchContext;
import org.eclipse.persistence.tools.workbench.framework.resources.ResourceRepository;
import org.eclipse.persistence.tools.workbench.mappingsio.ProjectIOManager;
import org.eclipse.persistence.tools.workbench.mappingsio.ReadOnlyFilesException;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWDescriptor;
import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWMapping;
import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClass;
import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassAttribute;
import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassRepository;
import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWMethod;
import org.eclipse.persistence.tools.workbench.mappingsmodel.project.MWProject;
import org.eclipse.persistence.tools.workbench.mappingsmodel.project.relational.MWRelationalProject;
import org.eclipse.persistence.tools.workbench.mappingsmodel.project.xml.MWEisProject;
import org.eclipse.persistence.tools.workbench.mappingsmodel.project.xml.MWOXProject;
import org.eclipse.persistence.tools.workbench.mappingsplugin.AddOrRefreshClassesAction;
import org.eclipse.persistence.tools.workbench.mappingsplugin.AutomappableNode;
import org.eclipse.persistence.tools.workbench.mappingsplugin.CreateNewClassAction;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ExportDeploymentXmlAction;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ExportDeploymentXmlAndInitializeRuntimeDescriptorsAction;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ExportModelJavaSourceAction;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ManageNonDescriptorClassesAction;
import org.eclipse.persistence.tools.workbench.mappingsplugin.MappingsPlugin;
import org.eclipse.persistence.tools.workbench.mappingsplugin.RefreshClassesAction;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.common.MappingsApplicationNode;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.common.UiCommonBundle;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.descriptor.DescriptorNode;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.descriptor.DescriptorPackageNode;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.descriptor.MappingDescriptorNode;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.descriptor.UiDescriptorBundle;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.descriptor.DescriptorPackageNode.DescriptorNodeBuilder;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.mapping.UiMappingBundle;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.project.relational.RelationalProjectNode;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.project.xml.EisProjectNode;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.project.xml.OXProjectNode;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.query.UiQueryBundle;
import org.eclipse.persistence.tools.workbench.uitools.LabelArea;
import org.eclipse.persistence.tools.workbench.uitools.app.CollectionValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.CompositeCollectionValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.ItemPropertyListValueModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.ListValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.PropertyCollectionValueModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.PropertyValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.SimpleCollectionValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.SimplePropertyValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.SortedListValueModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.swing.BlockIcon;
import org.eclipse.persistence.tools.workbench.utility.ClassTools;
import org.eclipse.persistence.tools.workbench.utility.CollectionTools;
import org.eclipse.persistence.tools.workbench.utility.Transformer;
import org.eclipse.persistence.tools.workbench.utility.events.CollectionChangeEvent;
import org.eclipse.persistence.tools.workbench.utility.events.CollectionChangeListener;
import org.eclipse.persistence.tools.workbench.utility.io.FileTools;
import org.eclipse.persistence.tools.workbench.utility.iterators.CompositeIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.TransformationIterator;
import org.eclipse.persistence.tools.workbench.utility.string.StringTools;
/**
* This node is a bit different from the typical node in that its children
* do not correspond 1:1 with its value's children. This node's children
* consists of a database node and a collection of descriptor package
* nodes; while the MWProject holds on to a database, it does not
* have descriptor packages - it holds on to the descriptors directly.
*/
public abstract class ProjectNode
extends MappingsApplicationNode
implements AutomappableNode
{
/** this is passed to new descriptor package nodes */
private DescriptorNodeBuilder descriptorNodeBuilder;
/** this listens for descriptors being added or removed */
private CollectionChangeListener descriptorsListener;
/**
* this listens for descriptor name changes, which can
* result in a descriptor changing its package
*/
private PropertyChangeListener descriptorNameListener;
/**
* we control the descriptor package nodes directly by
* listening to the project's 'descriptors' collection and
* the descriptors' 'name's
*/
private CollectionValueModel descriptorPackageNodesHolder;
/**
* subclasses will build the node that goes in here
*/
private PropertyValueModel metaDataRepositoryNodeHolder;
/**
* this will be a composite of the descriptor package nodes and
* the meta-data repository node
*/
private ListValueModel childrenModel;
/**
* used to temporarily disable our prompting the user
* to update the ejb-jar.xml file
*/
private boolean promptsForEjbJarXmlWrite;
protected static final String[] PROJECT_ICON_PROPERTY_NAMES = (String[]) CollectionTools.addAll(DEFAULT_ICON_PROPERTY_NAMES, new String[] {MWProject.VALIDATING_PROPERTY});
protected static final Icon VALIDATING_ICON = new BlockIcon(2);
protected static final String[] PROJECT_DISPLAY_STRING_PROPERTY_NAMES = {MWProject.NAME_PROPERTY};
// ********** preferences ********
public static final String WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE = "write ejb-jar.xml on save ";
public static final String WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE_ALWAYS = "Yes";
public static final String WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE_NEVER = "No";
public static final String WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE_PROMPT = "Prompt";
public static final String WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE_DEFAULT = WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE_PROMPT;
// ********** Static Methods **********
public static ProjectNode forProject(MWProject project, ApplicationContext context, MappingsPlugin plugin) {
if (project instanceof MWRelationalProject) {
return new RelationalProjectNode((MWRelationalProject) project, context, plugin);
} else if (project instanceof MWOXProject) {
return new OXProjectNode((MWOXProject) project, context, plugin);
} else if (project instanceof MWEisProject) {
return new EisProjectNode((MWEisProject) project, context, plugin);
} else {
throw new IllegalArgumentException(project.toString());
}
}
// ********** constructors/initialization **********
protected ProjectNode(MWProject project, MappingsPlugin plugin, ApplicationContext context) {
super(project, context.getNodeManager().getRootNode(), plugin, context);
}
protected void initialize() {
super.initialize();
this.descriptorNodeBuilder = this.buildDescriptorNodeBuilder();
this.descriptorsListener = this.buildDescriptorsListener();
this.descriptorNameListener = this.buildDescriptorNameListener();
this.descriptorPackageNodesHolder = new SimpleCollectionValueModel();
this.metaDataRepositoryNodeHolder = new SimplePropertyValueModel();
this.childrenModel = this.buildChildrenModel();
this.promptsForEjbJarXmlWrite = true;
}
protected abstract DescriptorNodeBuilder buildDescriptorNodeBuilder();
private CollectionChangeListener buildDescriptorsListener() {
return new CollectionChangeListener() {
public void itemsAdded(CollectionChangeEvent e) {
ProjectNode.this.addDescriptorNodesFor(e.items());
}
public void itemsRemoved(CollectionChangeEvent e) {
ProjectNode.this.removeDescriptorNodesFor(e.items());
}
public void collectionChanged(CollectionChangeEvent e) {
ProjectNode.this.rebuildDescriptorNodes();
}
public String toString() {
return "descriptors listener";
}
};
}
private PropertyChangeListener buildDescriptorNameListener() {
return new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
String oldPackageName = ClassTools.packageNameForClassNamed((String) e.getOldValue());
String newPackageName = ClassTools.packageNameForClassNamed((String) e.getNewValue());
if ( ! newPackageName.equals(oldPackageName)) {
ProjectNode.this.descriptorChangedPackage((MWDescriptor) e.getSource(), oldPackageName, newPackageName);
}
}
public String toString() {
return "descriptor name listener";
}
};
}
private ListValueModel buildChildrenModel() {
return new SortedListValueModelAdapter(this.buildChildrenDisplayStringAdapter(), Child.COMPARATOR) {
protected int indexToAddItems() {
//add new items before the metaDataRepositoryNode so it doesn't resort
//LDD of course if the item happens to be the metaDataRepository, this response throws an indexOutOfBoundsException
//so we need to account for that case.
int index = super.indexToAddItems();
return (index > 0) ? --index : index;
}
public String toString() {
return "children model";
}
};
}
/**
* the display string (name) of each child node can change
* and trigger a re-sort of the list; actually, the it is unlikely
* the display strings will change in a way that requires the
* list to be re-sorted, but we need to listen to them or
* they will be null
*/
private ListValueModel buildChildrenDisplayStringAdapter() {
return new ItemPropertyListValueModelAdapter(this.buildUnsortedChildrenModel(), DISPLAY_STRING_PROPERTY);
}
private CollectionValueModel buildUnsortedChildrenModel() {
CollectionValueModel container = new SimpleCollectionValueModel();
container.addItem(new PropertyCollectionValueModelAdapter(this.metaDataRepositoryNodeHolder));
container.addItem(this.descriptorPackageNodesHolder);
return new CompositeCollectionValueModel(container, Transformer.NULL_INSTANCE);
}
protected ApplicationContext expandContext(ApplicationContext context) {
return super.expandContext(context).
buildExpandedResourceRepositoryContext(UiProjectBundle.class).
buildExpandedResourceRepositoryContext(UiQueryBundle.class).
buildExpandedResourceRepositoryContext(UiMappingBundle.class).
buildExpandedResourceRepositoryContext(UiDescriptorBundle.class).
buildExpandedResourceRepositoryContext(UiCommonBundle.class);
}
// ********** MappingsApplicationNode overrides **********
private Iterator descriptors() {
return new CompositeIterator(
new TransformationIterator(this.descriptorPackageNodes()) {
protected Object transform(Object next) {
return ((DescriptorPackageNode) next).descriptors();
}
}
);
}
public void addDescriptorsTo(Collection descriptors) {
CollectionTools.addAll(descriptors, this.descriptors());
}
public boolean isAutoMappable() {
return true;
}
// ********** AbstractApplicationNode overrides **********
protected void engageValue() {
super.engageValue();
this.getProject().addCollectionChangeListener(MWProject.DESCRIPTORS_COLLECTION, this.descriptorsListener);
this.addDescriptorNodesFor(this.getProject().descriptors());
this.metaDataRepositoryNodeHolder.setValue(this.buildMetaDataRepositoryNode());
}
/**
* Build the appropriate node to represent the project's "meta-data
* repository".
*/
protected abstract Child buildMetaDataRepositoryNode();
protected void disengageValue() {
this.metaDataRepositoryNodeHolder.setValue(null);
this.removeDescriptorNodesFor(this.getProject().descriptors());
this.getProject().removeCollectionChangeListener(MWProject.DESCRIPTORS_COLLECTION, this.descriptorsListener);
super.disengageValue();
}
protected String[] iconPropertyNames() {
return PROJECT_ICON_PROPERTY_NAMES;
}
protected IconBuilder buildIconBuilder() {
IconBuilder ib = super.buildIconBuilder();
return this.getApplicationContext().getApplication().isDevelopmentMode() ?
this.buildDevelopmentModeIconBuilder(ib)
:
ib;
}
private IconBuilder buildDevelopmentModeIconBuilder(IconBuilder ib) {
return new CompositeIconBuilder(
ib,
this.getProject().isValidating(),
VALIDATING_ICON,
-17, // gap - overlay the "leading" edge of the unadorned icon
SwingConstants.HORIZONTAL, // orientation
SwingConstants.TOP, // alignment
null // description
);
}
protected String[] displayStringPropertyNames() {
return PROJECT_DISPLAY_STRING_PROPERTY_NAMES;
}
// ********** ApplicationNode implementation **********
public GroupContainerDescription buildMenuDescription(WorkbenchContext context) {
GroupContainerDescription desc = new RootMenuDescription();
context = this.buildLocalWorkbenchContext(context);
this.addToMenuDescription(desc, context);
return desc;
}
protected abstract void addToMenuDescription(GroupContainerDescription menuDescription, WorkbenchContext context);
protected MenuGroupDescription buildClassActionGroup(WorkbenchContext context) {
MenuGroupDescription classActionGroup = new MenuGroupDescription();
classActionGroup.add(this.getRefreshClassesAction(context));
classActionGroup.add(this.getAddOrRefreshClassesAction(context));
classActionGroup.add(this.getCreateNewClassAction(context));
classActionGroup.add(this.getManageNonDescriptorClassesAction(context));
return classActionGroup;
}
protected MenuGroupDescription buildCloseDeleteActionGroup(WorkbenchContext context) {
MenuGroupDescription closeDeleteActionGroup = new MenuGroupDescription();
closeDeleteActionGroup.add(getCloseAction(context));
closeDeleteActionGroup.add(getDeleteProjectAction(context));
return closeDeleteActionGroup;
}
protected MenuGroupDescription buildSaveActionGroup(WorkbenchContext context) {
MenuGroupDescription saveGroup = new MenuGroupDescription();
saveGroup.add(getSaveAction(context));
saveGroup.add(getSaveAsAction(context));
return saveGroup;
}
protected MenuGroupDescription buildExportActionGroup(WorkbenchContext context) {
MenuGroupDescription exportGroup = new MenuGroupDescription();
exportGroup.add(this.buildExportMenuDescription(context));
return exportGroup;
}
protected abstract GroupContainerDescription buildExportMenuDescription(WorkbenchContext context);
public ListValueModel getChildrenModel() {
return this.childrenModel;
}
public String helpTopicID() {
return "project";
}
public GroupContainerDescription buildToolBarDescription(WorkbenchContext workbenchContext) {
return new ToolBarDescription();
}
protected final FrameworkAction getDeleteProjectAction(WorkbenchContext context) {
return new DeleteProjectAction(context);
}
protected ExportDeploymentXmlAction getExportDeploymentXmlAction(WorkbenchContext context) {
return this.getMappingsPlugin().getExportDeploymentXmlAction(context);
}
protected ExportDeploymentXmlAndInitializeRuntimeDescriptorsAction getExportDeploymentXmlAndInitializeRuntimeDescriptorsAction(WorkbenchContext context) {
return this.getMappingsPlugin().getExportDeploymentXmlAndInitializeRuntimeDescriptorsAction(context);
}
protected RefreshClassesAction getRefreshClassesAction(WorkbenchContext context) {
return this.getMappingsPlugin().getRefreshClassesAction(context);
}
protected AddOrRefreshClassesAction getAddOrRefreshClassesAction(WorkbenchContext context) {
return this.getMappingsPlugin().getAddOrRefreshClassesAction(context);
}
protected CreateNewClassAction getCreateNewClassAction(WorkbenchContext context) {
return this.getMappingsPlugin().getCreateNewClassAction(context);
}
protected ManageNonDescriptorClassesAction getManageNonDescriptorClassesAction(WorkbenchContext context) {
return this.getMappingsPlugin().getManageNonDescriptorClassesAction(context);
}
protected ExportModelJavaSourceAction getModelJavaSourceAction(WorkbenchContext context) {
return this.getMappingsPlugin().getExportModelJavaSourceAction(context);
}
protected FrameworkAction getSaveAction(WorkbenchContext workbenchContext) {
return workbenchContext.getActionRepository().getSaveAction();
}
protected FrameworkAction getSaveAsAction(WorkbenchContext workbenchContext) {
return workbenchContext.getActionRepository().getSaveAsAction();
}
protected FrameworkAction getCloseAction(WorkbenchContext workbenchContext) {
return workbenchContext.getActionRepository().getCloseAction();
}
public File saveFile() {
return this.getProject().saveFile();
}
public boolean save(File mostRecentSaveDirectory, WorkbenchContext workbenchContext) {
boolean persistLastRefresh = preferences().getBoolean(MWClassRepository.PERSIST_LAST_REFRESH_PREFERENCE, MWClassRepository.PERSIST_LAST_REFRESH_PREFERENCE_DEFAULT);
this.getProject().getClassRepository().setPersistLastRefresh(persistLastRefresh);
File saveFile = this.saveFile();
if (saveFile == null) {
// the save file will be null on new and legacy projects
if (this.getProject().isLegacyProject()) {
JOptionPane.showMessageDialog(
workbenchContext.getCurrentWindow(),
this.resourceRepository().getString("PROJECT_SAVED_IN_NEW_FILE_FORMAT_DIALOG")
);
}
return this.saveAs(mostRecentSaveDirectory, workbenchContext);
}
workbenchContext = this.buildLocalWorkbenchContext(workbenchContext);
return this.saveInternal(saveFile, workbenchContext);
}
private boolean promptToWriteEjbJarXml(WorkbenchContext workbenchContext) {
if (preferences().get(WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE, WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE_DEFAULT).equals(WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE_ALWAYS)) {
return true;
} else if (preferences().get(WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE, WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE_DEFAULT).equals(WRITE_EJB_JAR_XML_ON_SAVE_PREFERENCE_NEVER)) {
return false;
}
int option =
JOptionPane.showConfirmDialog(
workbenchContext.getCurrentWindow(),
resourceRepository().getString("WRITE_PROJECT_EJB_JAR_ON_SAVE_DIALOG"),
resourceRepository().getString("WRITE_PROJECT_EJB_JAR_ON_SAVE_DIALOG.title"),
JOptionPane.YES_NO_OPTION
);
return option == JOptionPane.YES_OPTION;
}
public boolean saveAs(File mostRecentSaveDirectory, WorkbenchContext workbenchContext) {
File saveFile = this.saveFile();
File directory = this.getProject().getSaveDirectory();
if (directory == null) {
directory = mostRecentSaveDirectory;
saveFile = new File(mostRecentSaveDirectory, this.getProject().getName() + MWProject.FILE_NAME_EXTENSION);
}
workbenchContext = this.buildLocalWorkbenchContext(workbenchContext);
LocalFileChooser chooser = new LocalFileChooser(workbenchContext);
chooser.setDialogTitle(this.resourceRepository().getString("SAVE_AS_DIALOG_TITLE"));
chooser.setCurrentDirectory(directory);
chooser.setSelectedFile(saveFile);
chooser.setMultiSelectionEnabled(false);
chooser.setFileFilter(this.buildSaveAsDialogFileFilter(workbenchContext));
int result = chooser.showSaveDialog(workbenchContext.getCurrentWindow());
if (result != JFileChooser.APPROVE_OPTION) {
return false;
}
saveFile = chooser.getSelectedFile();
File saveDir = saveFile.getParentFile();
this.getProject().setSaveDirectory(saveDir);
String projectName = saveFile.getName();
if (projectName.toLowerCase().endsWith(MWProject.FILE_NAME_EXTENSION)) {
projectName = FileTools.stripExtension(projectName);
}
this.getProject().setName(projectName);
workbenchContext.getNavigatorSelectionModel().pushExpansionState();
boolean saved = saveInternal(saveFile, workbenchContext);
workbenchContext.getNavigatorSelectionModel().popAndRestoreExpansionState();
return saved;
}
private FileFilter buildSaveAsDialogFileFilter(final WorkbenchContext workbenchContext) {
return new FileFilter () {
public String getDescription() {
return workbenchContext.getApplicationContext().getResourceRepository().getString("SAVE_AS_DIALOG_MWP_FILE_FILTER");
}
public boolean accept(File file) {
return file.isDirectory() || MWProject.FILE_NAME_EXTENSION.equals(FileTools.extension(file));
}
};
}
private boolean saveInternal(File saveFile, WorkbenchContext workbenchContext) {
boolean saved = false;
ProjectIOManager ioMgr = this.getMappingsPlugin().getIOManager();
try {
ioMgr.write(this.getProject());
saved = true;
} catch (ReadOnlyFilesException exception) {
ReadOnlyFileDialog dialog = new ReadOnlyFileDialog(
workbenchContext,
CollectionTools.collection(exception.getFiles())
);
dialog.show();
if (dialog.saveAsWasPressed()) {
return this.saveAs(null, workbenchContext);
}
if (dialog.saveWasPressed()) {
// try again: recurse...
return this.saveInternal(saveFile, workbenchContext);
}
}
return saved;
}
// ********** AutomappableNode implementation **********
public String getAutomapSuccessfulStringKey() {
return "AUTOMAP_PROJECT_SUCCESSFUL";
}
public boolean canAutomapDescriptors() {
return this.getProject().canAutomapDescriptors();
}
public abstract String getCannotAutomapDescriptorsStringKey();
// ********** queries **********
public MWProject getProject() {
return (MWProject) this.getValue();
}
private Iterator descriptorPackageNodes() {
return (Iterator) this.descriptorPackageNodesHolder.getValue();
}
private DescriptorPackageNode descriptorPackageNodeFor(MWDescriptor descriptor) {
return this.descriptorPackageNodeNamed(descriptor.packageName());
}
/**
* return null if the node is not found
*/
public DescriptorPackageNode descriptorPackageNodeNamed(String name) {
for (Iterator stream = this.descriptorPackageNodes(); stream.hasNext(); ) {
DescriptorPackageNode descriptorPackageNode = (DescriptorPackageNode) stream.next();
if (descriptorPackageNode.getName().equals(name)) {
return descriptorPackageNode;
}
}
return null;
}
public DescriptorNode descriptorNodeFor(MWDescriptor descriptor) {
return descriptorPackageNodeNamed(descriptor.packageName()).descriptorNodeFor(descriptor);
}
public abstract boolean supportsExportProjectJavaSource();
public abstract boolean supportsExportTableCreatorJavaSource();
protected DescriptorNodeBuilder getDescriptorNodeBuilder() {
return this.descriptorNodeBuilder;
}
// ********** behavior **********
public void selectDescriptorNodeFor(MWDescriptor descriptor, NavigatorSelectionModel navigatorSelectionModel) {
selectDescriptorNode(descriptorNodeFor(descriptor), navigatorSelectionModel);
}
public void selectDescriptorNode(DescriptorNode descriptorNode, NavigatorSelectionModel navigatorSelectionModel) {
navigatorSelectionModel.setSelectedNode(descriptorNode);
}
public void selectMappingNodeFor(MWMapping mapping, NavigatorSelectionModel nsm) {
MappingDescriptorNode descriptorNode = (MappingDescriptorNode) descriptorNodeFor(mapping.getParentDescriptor());
descriptorNode.selectMappingNodeFor(mapping, nsm);
}
public void selectMappingNodeFor(MWClassAttribute attribute, NavigatorSelectionModel nsm) {
MappingDescriptorNode descriptorNode = (MappingDescriptorNode) descriptorNodeFor(getProject().descriptorForType((MWClass) attribute.getParent()));
descriptorNode.selectMappingNodeFor(attribute, nsm);
}
public void selectMethod(MWMethod method, WorkbenchContext context) {
MWDescriptor descriptor = getProject().descriptorForType((MWClass) method.getParent());
if (descriptor != null) {
MappingDescriptorNode descriptorNode = (MappingDescriptorNode) descriptorNodeFor(descriptor);
selectDescriptorNode(descriptorNode, context.getNavigatorSelectionModel());
descriptorNode.selectMethod(method, context);
}
}
/**
* this allows a client to temporarily disable our prompting the user
* to update the ejb-jar.xml file
*/
public void setPromptsForEjbJarXmlWrite(boolean b) {
this.promptsForEjbJarXmlWrite = b;
}
protected abstract DescriptorPackageNode buildDescriptorPackageNodeFor(MWDescriptor descriptor);
void addDescriptorNodesFor(Iterator descriptors) {
while (descriptors.hasNext()) {
this.addDescriptorNodeFor((MWDescriptor) descriptors.next());
}
}
private void addDescriptorNodeFor(MWDescriptor descriptor) {
descriptor.addPropertyChangeListener(MWDescriptor.NAME_PROPERTY, this.descriptorNameListener);
this.addDescriptorNodeTo(descriptor, this.descriptorPackageNodeFor(descriptor));
}
private void addDescriptorNodeTo(MWDescriptor descriptor, DescriptorPackageNode dpn) {
if (dpn == null) {
dpn = this.buildDescriptorPackageNodeFor(descriptor);
this.descriptorPackageNodesHolder.addItem(dpn);
}
dpn.addDescriptorNodeFor(descriptor);
}
void removeDescriptorNodesFor(Iterator descriptors) {
while (descriptors.hasNext()) {
this.removeDescriptorNodeFor((MWDescriptor) descriptors.next());
}
}
private void removeDescriptorNodeFor(MWDescriptor descriptor) {
this.removeDescriptorNodeFrom(descriptor, this.descriptorPackageNodeFor(descriptor));
descriptor.removePropertyChangeListener(MWDescriptor.NAME_PROPERTY, this.descriptorNameListener);
}
private void removeDescriptorNodeFrom(MWDescriptor descriptor, DescriptorPackageNode dpn) {
dpn.removeDescriptorNodeFor(descriptor);
if (dpn.descriptorNodesSize() == 0) {
this.descriptorPackageNodesHolder.removeItem(dpn);
}
}
void rebuildDescriptorNodes() {
Collection descriptors = CollectionTools.list(this.descriptors()); // make a copy before removing them
this.removeDescriptorNodesFor(descriptors.iterator());
this.addDescriptorNodesFor(this.getProject().descriptors());
}
void descriptorChangedPackage(MWDescriptor descriptor, String oldPackageName, String newPackageName) {
this.removeDescriptorNodeFrom(descriptor, this.descriptorPackageNodeNamed(oldPackageName));
// keep listening to the descriptor's name property
this.addDescriptorNodeTo(descriptor, this.descriptorPackageNodeNamed(newPackageName));
}
// ********** nested interface **********
/**
* This interface defines the information a ProjectNode requires
* of its children so it can sort them.
*/
public interface Child extends Comparable {
/**
* Return a priority that can be used to sort the nodes under
* a ProjectNode. Nodes of the same priority will be compared
* directly, via java.util.Comparable#compareTo(Object).
*/
int getProjectNodeChildPriority();
Comparator COMPARATOR =
new Comparator() {
public int compare(Object o1, Object o2) {
int priority1 = ((Child) o1).getProjectNodeChildPriority();
int priority2 = ((Child) o2).getProjectNodeChildPriority();
if (priority1 == priority2) {
return ((Comparable) o1).compareTo(o2);
}
return priority1 - priority2;
}
public String toString() {
return "ProjectNode.Child.COMPARATOR";
}
};
}
private class LocalFileChooser extends JFileChooser {
private WorkbenchContext workbenchContext;
private LocalFileChooser(WorkbenchContext workbenchContext) {
super();
this.workbenchContext = workbenchContext;
}
/**
* Determines whether the selected file can be used as the new location to
* persist the document.
*/
public void approveSelection() {
int result = canReplaceExistingFile();
if (result == JOptionPane.YES_OPTION)
super.approveSelection();
else if (result == JOptionPane.CANCEL_OPTION)
cancelSelection();
}
private ResourceRepository resourceRepository() {
return this.workbenchContext.getApplicationContext().getResourceRepository();
}
/**
* Verifies if the file (which is currently selected) can be replaced with
* the document to be saved.
*
* @return <code>JOptionPane.YES_OPTION</code> if the file is not
* Read-Only, not opened or can be replaced, <code>JOptionPane.NO_OPTION</code>
* if the document can't be saved because the selected file is Read-Only
* or the user said no to replace it, or <code><code>JOptionPane.NO_OPTION</code></code>
* if the user does not want to replace the file and canceled the confirm
* dialog
*/
private int canReplaceExistingFile() {
File file = getSelectedFile();
String applicationName = this.workbenchContext.getApplicationContext().getApplication().getShortProductName();
// The file is actually opened
if (this.isDocumentOpened(file)) {
String message = this.resourceRepository().getString("SAVE_AS_DIALOG_ALREADY_OPENED", applicationName, file, StringTools.CR);
LabelArea label = new LabelArea(message);
label.setPreferredWidth(800);
JOptionPane.showMessageDialog (
this.workbenchContext.getCurrentWindow(),
label,
applicationName,
JOptionPane.WARNING_MESSAGE
);
return JOptionPane.NO_OPTION;
}
// The file exist but is marked as Read-Only, show we can't save it
if (file.exists() && !file.canWrite()) {
String message = this.resourceRepository().getString("SAVE_AS_DIALOG_CANT_SAVE", file, StringTools.CR);
LabelArea label = new LabelArea(message);
label.setPreferredWidth(800);
JOptionPane.showMessageDialog (
this.workbenchContext.getCurrentWindow(),
label,
applicationName,
JOptionPane.WARNING_MESSAGE
);
return JOptionPane.NO_OPTION;
}
// The file exists and is the file to save, ask to replace it
if ((saveFile() != null) &&
file.exists() &&
saveFile().equals(file)) {
String message = this.resourceRepository().getString("SAVE_AS_DIALOG_REPLACE", getSelectedFile().getPath());
LabelArea label = new LabelArea(message);
label.setPreferredWidth(800);
return JOptionPane.showConfirmDialog (
this.workbenchContext.getCurrentWindow(),
label,
applicationName,
JOptionPane.YES_NO_CANCEL_OPTION
);
}
// The directory contains another TopLink Map project
if (!this.isValidSaveDirectory(file.getParentFile())) {
String message = this.resourceRepository().getString("NEED_EMPTY_DIRECTORY_TO_SAVE_DIALOG.message");
LabelArea label = new LabelArea(message);
label.setPreferredWidth(800);
JOptionPane.showMessageDialog (
this.workbenchContext.getCurrentWindow(),
label,
this.resourceRepository().getString("NEED_EMPTY_DIRECTORY_TO_SAVE_DIALOG.title"),
JOptionPane.ERROR_MESSAGE
);
return JOptionPane.NO_OPTION;
}
return JOptionPane.YES_OPTION;
}
private boolean isValidSaveDirectory(File saveDirectory) {
File[] files = saveDirectory.listFiles();
if (files == null || files.length == 0) {
return true; // an empty directory is OK
}
for (int i = files.length; i-- > 0; ) {
File file = files[i];
// if the file is not a directory and has the extension .mwp we disallow the save
if ( ! file.isDirectory() && file.getName().endsWith(MWProject.FILE_NAME_EXTENSION)) {
return false;
}
}
return true;
}
/**
* Determines whether a file with the given path is already opened. The
* location of this document is not considered during the check.
*/
private boolean isDocumentOpened(File file) {
ApplicationNode[] appNodes = nodeManager().projectNodesFor(getPlugin());
for (int i = 0; i < appNodes.length; i++) {
ProjectNode node = (ProjectNode) appNodes[i];
// This is this node, continue
if (node == ProjectNode.this) {
continue;
}
File anotherOpenedFile = node.saveFile();
if ((anotherOpenedFile != null) &&
file.equals(anotherOpenedFile)) {
return true;
}
}
return false;
}
}
}