/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.diagram.ui.custom.actions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.dialogs.ISelectionStatusValidator;
import org.teiid.core.designer.util.I18nUtil;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.diagram.ui.DiagramUiConstants;
import org.teiid.designer.diagram.ui.DiagramUiPlugin;
import org.teiid.designer.diagram.ui.PluginConstants;
import org.teiid.designer.diagram.ui.actions.DiagramAction;
import org.teiid.designer.diagram.ui.connection.UmlRelationshipHelper;
import org.teiid.designer.diagram.ui.custom.CustomDiagramContentHelper;
import org.teiid.designer.diagram.ui.custom.CustomDiagramModelFactory;
import org.teiid.designer.diagram.ui.editor.DiagramEditor;
import org.teiid.designer.diagram.ui.editor.DiagramEditorUtil;
import org.teiid.designer.diagram.ui.model.DiagramModelNode;
import org.teiid.designer.diagram.ui.util.DiagramUiUtilities;
import org.teiid.designer.metamodels.diagram.Diagram;
import org.teiid.designer.ui.common.eventsupport.SelectionUtilities;
import org.teiid.designer.ui.common.util.WidgetUtil;
import org.teiid.designer.ui.editors.ModelEditorManager;
import org.teiid.designer.ui.explorer.ModelExplorerContentProvider;
import org.teiid.designer.ui.explorer.ModelExplorerLabelProvider;
import org.teiid.designer.ui.viewsupport.ModelUtilities;
import org.teiid.designer.ui.viewsupport.ModelWorkspaceViewerFilter;
/**
* @since 8.0
*/
public class AddToNewCustomDiagramAction extends DiagramAction implements DiagramUiConstants {
private static final String I18N_PREFIX = I18nUtil.getPropertyPrefix(AddToNewCustomDiagramAction.class);
private static final String TARGET_SELECTION_DIALOG_TITLE = getString("containerSelectionDialogTitle"); //$NON-NLS-1$
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
private static final String TARGET_SELECTION_DIALOG_MESSAGE = getString("containerSelectionDialogMessage"); //$NON-NLS-1$
static final String INVALID_SELECTION_MESSAGE = getString("invalidSelectionMessage"); //$NON-NLS-1$
static final String READ_ONLY_MODEL_SELECTION_MESSAGE = getString("readOnlyModelSelectionMessage"); //$NON-NLS-1$
static final String READ_ONLY_OBJECT_SELECTION_MESSAGE = getString("readOnlyObjectSelectionMessage"); //$NON-NLS-1$
private static final String LEVELS_SELECTION_DIALOG_TITLE = getString("levelsDialogTitle"); //$NON-NLS-1$
private static final boolean PERSIST_CUSTOM_DIAGRAMS = true;
private static final String THIS_CLASS = "AddToNewCustomDiagramAction"; //$NON-NLS-1$
/**
* @since 4.0
*/
private static String getString( final String id ) {
return Util.getString(I18N_PREFIX + id);
}
/**
* Construct an instance of NewCustomDiagramAction.
*/
public AddToNewCustomDiagramAction() {
super();
}
/**
* Construct an instance of NewCustomDiagramAction.
*
* @param theStyle
*/
public AddToNewCustomDiagramAction( int theStyle ) {
super(theStyle);
}
/**
* @see org.eclipse.ui.ISelectionListener#selectionChanged(IWorkbenchPart, ISelection)
* @since 4.0
*/
@Override
public void selectionChanged( final IWorkbenchPart part,
final ISelection selection ) {
super.selectionChanged(part, selection);
determineEnablement();
}
/**
* @see org.eclipse.jface.action.Action#run()
* @since 4.0
*/
@Override
protected void doRun() {
// once that is returned, then we can go ahead and create custom diagram and
// add objects to diagram.
List selectedEObjects = SelectionUtilities.getSelectedEObjects(getSelection());
if (selectedEObjects != null && !selectedEObjects.isEmpty()) {
// Ask user to select model or package to create custom diagram in (and model)
Object selectedContainer = getTargetForDiagram();
Diagram newDiagram = null;
boolean diagramWasConstructed = false;
if (selectedContainer != null) {
verifyResouceOpen(selectedContainer);
DiagramEditor dEditor = null;
boolean requiredStart = false;
boolean succeeded = false;
try {
// -------------------------------------------------
// Let's wrap this in a transaction!!!
// -------------------------------------------------
requiredStart = ModelerCore.startTxn(true, false, "Add To New Custom Diagram", this); //$NON-NLS-1$$
newDiagram = createDiagram(selectedContainer);
if (newDiagram != null) {
diagramWasConstructed = true;
ModelEditorManager.open(newDiagram, true);
// Get Visible Diagram Editor (should be loaded with an empty diagram.
dEditor = DiagramEditorUtil.getVisibleDiagramEditor();
// Need to get the current diagram
DiagramModelNode diagramNode = dEditor.getCurrentModel();
// Need to get ahold of the CustomDiagramModelFactory
CustomDiagramModelFactory modelFactory = (CustomDiagramModelFactory)dEditor.getModelFactory();
// And call add(SelectionUtilities.getSelectedEObjects(getSelection())
if (diagramNode != null && modelFactory != null) {
DiagramEditorUtil.setDiagramUnderConstruction(newDiagram);
// Now we can add to diagram
List applicableDiagramObjects = CustomDiagramContentHelper.getApplicableDiagramEObjects(selectedEObjects);
modelFactory.add(applicableDiagramObjects, diagramNode);
int levels = getAssociationLevels();
addAssociatedObjects(dEditor, modelFactory, diagramNode, selectedEObjects, levels);
dEditor.autoLayout();
}
}
succeeded = true;
} catch (ModelWorkspaceException e) {
String message = Util.getString("AddToNewCustomDiagramAction.createCustomDiagramError", selectedContainer.toString()); //$NON-NLS-1$
Util.log(IStatus.ERROR, e, message);
} catch (Exception ex) {
DiagramUiConstants.Util.log(IStatus.ERROR, ex, ex.getClass().getName() + ":" + THIS_CLASS + ".doRun()"); //$NON-NLS-1$ //$NON-NLS-2$
} finally {
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
if (diagramWasConstructed) {
DiagramEditorUtil.setDiagramConstructionComplete(newDiagram, true);
// For some reason, this still isn't sufficient to complete the layout of Classifiers within the custom
// diagram. Easiest to just call open context again here to insure it's done properly.
if (dEditor != null) {
dEditor.openContext(newDiagram, true);
}
}
}
}
}
determineEnablement();
}
/**
* @since 4.0
*/
private void determineEnablement() {
boolean enable = false;
if (!SelectionUtilities.getSelectedEObjects(getSelection()).isEmpty()) {
// Check that no eObjects are "Diagrams" themselves
List allEObjs = SelectionUtilities.getSelectedEObjects(getSelection());
enable = true;
Iterator iter = allEObjs.iterator();
while (iter.hasNext() && enable) {
if (iter.next() instanceof Diagram) {
enable = false;
}
}
}
setEnabled(enable);
}
/**
* This method is called in the run() method of AbstractAction to give the actions a hook into canceling the run at the last
* minute. This overrides the AbstractAction preRun() method.
*/
@Override
protected boolean preRun() {
return true;
}
/**
* @see org.teiid.designer.ui.actions.ModelObjectAction#requiresEditorForRun()
*/
@Override
protected boolean requiresEditorForRun() {
return true;
}
private void verifyResouceOpen( Object targetContainer ) {
if (requiresEditorForRun()) {
final Object selectedObject = SelectionUtilities.getSelectedObject(getSelection());
ModelResource modelResource = null;
if ((targetContainer instanceof IResource) && ModelUtilities.isModelFile((IResource)targetContainer)) {
try {
modelResource = ModelUtil.getModelResource((IFile)targetContainer, false);
} catch (ModelWorkspaceException e) {
String message = Util.getString("AddToNewCustomDiagramAction.createCustomDiagramError", selectedObject.toString()); //$NON-NLS-1$
Util.log(IStatus.ERROR, e, message);
}
} else {
modelResource = ModelUtilities.getModelResourceForModelObject((EObject)targetContainer);
}
if (modelResource != null) {
ModelEditorManager.activate(modelResource, true);
}
}
}
private Diagram createDiagram( Object targetContainer ) throws ModelWorkspaceException {
Diagram result = null;
if ((targetContainer instanceof IResource) && ModelUtilities.isModelFile((IResource)targetContainer)) {
ModelResource modelResource = ModelUtil.getModelResource((IFile)targetContainer, false);
if (modelResource != null) {
result = modelResource.getModelDiagrams().createNewDiagram(null, PERSIST_CUSTOM_DIAGRAMS);
result.setType(PluginConstants.CUSTOM_DIAGRAM_TYPE_ID);
}
} else {
ModelResource modelResource = ModelUtilities.getModelResourceForModelObject((EObject)targetContainer);
if (modelResource != null) {
result = modelResource.getModelDiagrams().createNewDiagram((EObject)targetContainer, PERSIST_CUSTOM_DIAGRAMS);
result.setType(PluginConstants.CUSTOM_DIAGRAM_TYPE_ID);
}
}
return result;
}
public int getAssociationLevels() {
int levels = 0;
Shell shell = DiagramUiPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell();
AssociatedLevelsDialog dialog = new AssociatedLevelsDialog(shell, LEVELS_SELECTION_DIALOG_TITLE);
if (dialog.open() == Window.OK) {
levels = dialog.getLevels();
}
return levels;
}
private Object getTargetForDiagram() {
final ViewerFilter filter = new ModelWorkspaceViewerFilter(true) {
@Override
public boolean select( final Viewer viewer,
final Object parent,
final Object element ) {
// first make sure workspace filter would select element
boolean doSelect = super.select(viewer, parent, element);
// now make sure element can be handled by UML
if (doSelect && (element instanceof EObject)) {
if (!DiagramUiUtilities.isStandardUmlPackage(element)) {
return false;
}
}
// only allow containers and resources
return doSelect && ((element instanceof IContainer) || (element instanceof IResource));
}
};
final ISelectionStatusValidator validator = new ISelectionStatusValidator() {
@Override
public IStatus validate( final Object[] selection ) {
if (selection.length == 1) {
if (selection[0] instanceof IResource) {
if (ModelUtilities.isModelFile((IResource)selection[0]) && !ModelUtil.isXsdFile((IResource)selection[0])) {
ModelResource mr = null;
try {
mr = ModelUtil.getModelResource((IFile)selection[0], false);
} catch (ModelWorkspaceException err) {
String message = Util.getString("AddToNewCustomDiagramAction.findModelResourceError", selection[0].toString()); //$NON-NLS-1$
Util.log(IStatus.ERROR, err, message);
}
if (mr != null && mr.isReadOnly()) return new Status(IStatus.ERROR, PLUGIN_ID, 0,
READ_ONLY_MODEL_SELECTION_MESSAGE, null);
return new Status(IStatus.OK, PLUGIN_ID, 0, EMPTY_STRING, null);
}
} else if (selection[0] instanceof EObject) {
if (DiagramUiUtilities.isStandardUmlPackage(selection[0])) {
ModelResource mr = ModelUtilities.getModelResourceForModelObject((EObject)selection[0]);
if (mr != null && mr.isReadOnly()) return new Status(IStatus.ERROR, PLUGIN_ID, 0,
READ_ONLY_OBJECT_SELECTION_MESSAGE, null);
return new Status(IStatus.OK, PLUGIN_ID, 0, EMPTY_STRING, null);
}
}
}
return new Status(IStatus.ERROR, PLUGIN_ID, 0, INVALID_SELECTION_MESSAGE, null);
}
};
final Object[] targets = WidgetUtil.showWorkspaceObjectSelectionDialog(TARGET_SELECTION_DIALOG_TITLE,
TARGET_SELECTION_DIALOG_MESSAGE,
true,
null,
filter,
validator,
new ModelExplorerLabelProvider(),
new ModelExplorerContentProvider());
if (targets.length > 0) {
// Need to check if the
return targets[0];
}
return null;
}
private void addAssociatedObjects( DiagramEditor editor,
CustomDiagramModelFactory modelFactory,
DiagramModelNode diagramNode,
List startingList,
int levels ) {
List currentContents = new ArrayList(startingList);
for (int i = 0; i < levels; i++) {
List newObjects = getAssociatedObjectsNotInDiagram(editor, currentContents);
if (newObjects.isEmpty()) break;
modelFactory.add(newObjects, diagramNode);
currentContents = DiagramEditorUtil.getCurrentDiagramNodeEObjects();
}
}
private List getAssociatedObjectsNotInDiagram( DiagramEditor editor,
List objectList ) {
List newObjects = new ArrayList();
if (editor != null && editor.getCurrentModel() != null) {
DiagramModelNode diagramNode = editor.getCurrentModel();
List allAssociatedToAdd = UmlRelationshipHelper.getRelatedObjects(objectList);
Iterator iter = allAssociatedToAdd.iterator();
EObject nextEObj = null;
while (iter.hasNext()) {
nextEObj = (EObject)iter.next();
if (editor.getCurrentModel() != null) {
if (!(DiagramUiUtilities.diagramContainsEObject(nextEObj, diagramNode))) newObjects.add(nextEObj);
}
}
}
if (newObjects.isEmpty()) return Collections.EMPTY_LIST;
return newObjects;
}
}