/*
* 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.ui.actions;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.ISaveableFilter;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.Saveable;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.core.workspace.WorkspaceResourceFinderUtil;
import org.teiid.designer.ui.UiConstants;
import org.teiid.designer.ui.UiPlugin;
import org.teiid.designer.ui.actions.workers.DeleteWorker;
import org.teiid.designer.ui.common.util.UiUtil;
import org.teiid.designer.ui.common.widget.ListMessageDialog;
import org.teiid.designer.ui.editors.ModelEditorManager;
import org.teiid.designer.ui.refactor.RefactorCommandProcessorDialog;
import org.teiid.designer.ui.viewsupport.ModelUtilities;
/**
* The <code>DeleteEObjectAction</code> class is the action that handles the global delete.
* @since 8.0
*/
public class DeleteEObjectAction extends ModelObjectAction {
//============================================================================================================================
// Constants
//============================================================================================================================
// Fields
/** The child type descriptor. */
private DeleteWorker worker;
private static final String CANNOT_UNDO_TITLE = "DeleteAction.cannotUndoTitle"; //$NON-NLS-1$
private static final String CANNOT_UNDO_MSG = "DeleteAction.cannotUndoMsg"; //$NON-NLS-1$
private static final String READ_ONLY_DEPENDENCIES_TITLE = "DeleteAction.readOnlyDependenciesTitle"; //$NON-NLS-1$
private static final String READ_ONLY_DEPENDENCIES_MSG = "DeleteAction.readOnlyDependenciesMsg"; //$NON-NLS-1$
private static final String MODIFY_DEPENDENCIES_TITLE = "DeleteAction.modifyDependenciesTitle"; //$NON-NLS-1$
private static final String MODIFY_DEPENDENCIES_MSG = "DeleteAction.modifyDependenciesMsg"; //$NON-NLS-1$
private static final String FIND_RESOURCE_ERROR_MSG = "DeleteAction.findResourceErrorMsg"; //$NON-NLS-1$
//============================================================================================================================
// Constructors
public DeleteEObjectAction() {
super(UiPlugin.getDefault());
final ISharedImages imgs = PlatformUI.getWorkbench().getSharedImages();
setImageDescriptor(imgs.getImageDescriptor(ISharedImages.IMG_TOOL_DELETE));
setDisabledImageDescriptor(imgs.getImageDescriptor(ISharedImages.IMG_TOOL_DELETE_DISABLED));
worker = new DeleteWorker(true);
setActionWorker(worker);
}
@Override
public void doRun() {
worker.createObjectDeleteCommand();
// cleanup modified files before starting this operation
boolean bContinue = UiUtil.saveDirtyEditors(null, getResourcesFilter(), true);
if ( bContinue ) {
super.doRun();
// if there are problems, use the common error dialog to report them
if ( worker.getObjectDeleteCommand().getPostExecuteMessages() != null
&& worker.getObjectDeleteCommand().getPostExecuteMessages().size() > 0 ) {
RefactorCommandProcessorDialog rcpdDialog
= new RefactorCommandProcessorDialog( getShell(), worker.getObjectDeleteCommand() );
rcpdDialog.open();
}
} else {
MessageDialog.openInformation(getShell(),
UiConstants.Util.getString("DeleteAction.operationCanceledDialogTitle"), //$NON-NLS-1$
UiConstants.Util.getString("DeleteAction.operationCanceledDialogMessage")); //$NON-NLS-1$
}
// worker.selectionChanged(getSelection());
}
private Shell getShell() {
return UiPlugin.getDefault().getCurrentWorkbenchWindow().getShell();
}
private ISaveableFilter getResourcesFilter() {
// first get the dependent resources
final Collection<ModelResource> ignoredResources = new HashSet<ModelResource>();
ignoredResources.addAll(worker.getObjectDeleteCommand().getDependentResources());
// then get the resources that own the selected objects
ModelResource mrTemp = null;
for (EObject modelObject : this.worker.getSelectedEObjects()) {
mrTemp = ModelUtilities.getModelResourceForModelObject(modelObject);
// do not allow duplicates
if (!ignoredResources.contains(mrTemp)) {
ignoredResources.add(mrTemp);
}
}
ISaveableFilter filter = new ISaveableFilter() {
/**
* {@inheritDoc}
*
* @see org.eclipse.ui.ISaveableFilter#select(org.eclipse.ui.Saveable, org.eclipse.ui.IWorkbenchPart[])
*/
@Override
public boolean select( Saveable saveable,
IWorkbenchPart[] containingParts ) {
// make sure first part is an editor
if ((containingParts != null) && (containingParts.length != 0) && (containingParts[0] instanceof IEditorPart)) {
IEditorInput input = ((IEditorPart)containingParts[0]).getEditorInput();
if (input instanceof IFileEditorInput) {
ModelResource model = ModelUtilities.getModelResourceForIFile(((IFileEditorInput)input).getFile(),
false);
// don't select if an ignored resource
if (model != null) {
return !ignoredResources.contains(model);
}
}
}
// if no part or part is not an editor don't force save
return false;
}
};
return filter;
}
/**
* 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() {
/*
* 1. set the selected objects on the worker. Must be done prior to opening any dependent
* model editors since the selection may change if 'link with editor' is checked
* 2. create the transactionsettings object
* 3. call canDelete and canUndoDelete methods in the helper
* -- put result of these calls in the TranSettings object
* 4. if canUndo == false,
* present warning dialog
* if user wants to continue,
* make sure we use the value of TxnSettings.canUndo in the
* canUndo arg of the startTxn method
* 5. if canUndo was true, return true
* if canUndo was false, return true if user wishes to continue
* return false if user does NOT wish to continue
*/
worker.setSelectedObjects();
if( ! resourceDependencyCheckOK() ) {
return false;
}
// create the settings object
TransactionSettings ts = getTransactionSettings();
worker.setTransactionSettings( ts );
worker.initTransactionSettings();
// if not undoable, give user a chance to bail out
if ( !ts.isUndoable() ) {
String sTitle = UiConstants.Util.getString( CANNOT_UNDO_TITLE );
String sMsg = UiConstants.Util.getString( CANNOT_UNDO_MSG );
boolean bDoAnyway
= MessageDialog.openQuestion( getShell(), sTitle, sMsg );
if ( !bDoAnyway ) {
return false;
}
}
// if we are to continue, pass the settings object to the worker
if( requiresEditorForRun() ) {
boolean okToContinue = false;
try {
okToContinue = openEditorsForDependentModels();
} catch (ModelWorkspaceException theException) {
UiConstants.Util.log(IStatus.ERROR, theException.getMessage());
}
if( !okToContinue ) {
return false;
}
// Need to cache the active part if we open/activate a model editor. Opening an editor
// will grab focus. Need to return it to the original active part.
IWorkbenchPart activePart = null;
Object cachedSelection = worker.getSelection();
if( worker.getFocusedObject() != null ) {
if( !ModelEditorManager.isOpen(worker.getFocusedObject()) ) {
activePart = UiPlugin.getDefault().getCurrentWorkbenchWindow().getPartService().getActivePart();
if( worker.getModelResource() != null ) {
ModelEditorManager.activate(worker.getModelResource(), true);
} else {
ModelEditorManager.open(worker.getFocusedObject(), true);
}
}
} else if( worker.getModelResource() != null ) {
activePart = UiPlugin.getDefault().getCurrentWorkbenchWindow().getPartService().getActivePart();
ModelEditorManager.activate(worker.getModelResource(), true);
}
// Reset the selection on the worker
if( activePart != null ) {
activePart.setFocus();
}
worker.selectionChanged(cachedSelection);
}
return true;
}
@Override
protected void postRun() {
worker.selectionChanged( getSelection() );
worker.setTransactionSettings( null );
super.postRun();
}
/* (non-Javadoc)
* @see org.teiid.designer.ui.actions.ModelObjectAction#requiresEditorForRun()
*/
@Override
protected boolean requiresEditorForRun() {
return true;
}
private boolean resourceDependencyCheckOK() {
boolean isOkToDelete = true;
List<EObject> eObjects = worker.getSelectedEObjects();
List readOnlyDependencies = new ArrayList(getReadOnlyDependentResources(eObjects));
if( !readOnlyDependencies.isEmpty() ) {
String sTitle = UiConstants.Util.getString( READ_ONLY_DEPENDENCIES_TITLE );
String sMsg = UiConstants.Util.getString( READ_ONLY_DEPENDENCIES_MSG );
List resourceList = new ArrayList(readOnlyDependencies.size());
for(Iterator iter = readOnlyDependencies.iterator(); iter.hasNext(); ) {
IPath shortPath = ((IResource)iter.next()).getFullPath().makeRelative();
resourceList.add(shortPath);
}
ListMessageDialog.openWarning( getShell(), sTitle, null, sMsg, resourceList, null );
isOkToDelete = false;
}
return isOkToDelete;
}
/* (non-Javadoc)
* Overridden to collect up only the models that actually reference the object to be deleted.
*/
private Collection getReadOnlyDependentResources(List<EObject> eObjects) {
Collection allDependentModelFiles = getAllDependentResources(eObjects);
Collection visitedResources = new HashSet();
Collection readOnlyResources = new HashSet();
for ( Iterator iter2 = allDependentModelFiles.iterator() ; iter2.hasNext() ; ) {
IResource resource = (IResource) iter2.next();
if ( !ModelUtilities.isVdbFile(resource) && ! visitedResources.contains(resource) ) {
visitedResources.add(resource);
if( resource.getResourceAttributes().isReadOnly() )
readOnlyResources.add(resource);
}
}
return readOnlyResources;
}
/* (non-Javadoc)
* Overridden to collect up only the models that actually reference the object to be deleted.
*/
private Collection<IFile> getAllDependentResources(List<EObject> eObjects) {
Collection<IResource> resourcesToDelete = new HashSet<IResource>();
Collection<IFile> dependentResources = new HashSet<IFile>();
ModelResource mr = null;
try {
for (EObject eObject : eObjects) {
mr = ModelUtilities.getModelResourceForModelObject(eObject);
if( mr == null)
continue;
IResource objectResource = mr.getCorrespondingResource();
resourcesToDelete.add(objectResource);
Collection<IFile> dependents =
WorkspaceResourceFinderUtil.getResourcesThatUse(objectResource, IResource.DEPTH_ZERO);
for (IFile dependent : dependents) {
// Not deleting vdb files since they carry a copy of the resource
// so not strictly a dependency
if(ModelUtilities.isVdbFile(dependent))
continue;
dependentResources.add(dependent);
}
}
} catch (ModelWorkspaceException err) {
UiConstants.Util.log(IStatus.ERROR, err, UiConstants.Util.getString(FIND_RESOURCE_ERROR_MSG, mr) );
}
// Remove any object to delete resources from the dependencies
dependentResources.removeAll(resourcesToDelete);
return dependentResources;
}
private boolean openEditorsForDependentModels() throws ModelWorkspaceException {
boolean okToDelete = true;
List<EObject> eObjects = worker.getSelectedEObjects();
Collection allDepResources = getAllDependentResources(eObjects);
if( !allDepResources.isEmpty()) {
String sTitle = UiConstants.Util.getString( MODIFY_DEPENDENCIES_TITLE );
String sMsg = UiConstants.Util.getString( MODIFY_DEPENDENCIES_MSG );
List resourceList = new ArrayList(allDepResources.size());
for(Iterator iter = allDepResources.iterator(); iter.hasNext(); ) {
IPath shortPath = ((IResource)iter.next()).getFullPath().makeRelative();
resourceList.add(shortPath);
}
okToDelete = ListMessageDialog.openWarningQuestion( getShell(), sTitle, null, sMsg, resourceList, null );
if( okToDelete ) {
for (Iterator iter = allDepResources.iterator(); iter.hasNext(); ) {
IFile nextRes = (IFile)iter.next();
if( !ModelEditorManager.isOpen(nextRes) )
ModelEditorManager.activate(nextRes, true);
}
}
}
if( okToDelete ) {
// Now open editors for all eObject's resources
ModelResource mr = null;
// Create a unique list of ModelResources that will be losing objects
Collection eObjectResources = new HashSet(eObjects.size());
for (EObject eObject : eObjects) {
mr = ModelUtilities.getModelResourceForModelObject(eObject);
eObjectResources.add(mr);
}
// Insure the affected resources are open in editors
for( Iterator iter = eObjectResources.iterator(); iter.hasNext(); ) {
mr = (ModelResource)iter.next();
if( mr != null && ! ModelEditorManager.isOpen((IFile)mr.getCorrespondingResource()) ) {
ModelEditorManager.activate(mr, true, true);
}
}
}
return okToDelete;
}
}