/*******************************************************************************
* Copyright (c) 2004, 2010 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.client.ui.rcp.editors;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.jubula.client.core.businessprocess.CompNamesBP;
import org.eclipse.jubula.client.core.businessprocess.TestExecution;
import org.eclipse.jubula.client.core.businessprocess.db.TestCaseBP;
import org.eclipse.jubula.client.core.commands.CAPRecordedCommand;
import org.eclipse.jubula.client.core.events.DataEventDispatcher;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.DataState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.RecordModeState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.UpdateState;
import org.eclipse.jubula.client.core.events.IRecordListener;
import org.eclipse.jubula.client.core.model.IAUTMainPO;
import org.eclipse.jubula.client.core.model.ICapPO;
import org.eclipse.jubula.client.core.model.IEventExecTestCasePO;
import org.eclipse.jubula.client.core.model.IEventHandlerContainer;
import org.eclipse.jubula.client.core.model.IExecTestCasePO;
import org.eclipse.jubula.client.core.model.INodePO;
import org.eclipse.jubula.client.core.model.IPersistentObject;
import org.eclipse.jubula.client.core.model.ISpecTestCasePO;
import org.eclipse.jubula.client.core.model.NodeMaker;
import org.eclipse.jubula.client.core.persistence.EditSupport;
import org.eclipse.jubula.client.core.persistence.GeneralStorage;
import org.eclipse.jubula.client.core.persistence.NodePM;
import org.eclipse.jubula.client.core.persistence.ObjectMappingManager;
import org.eclipse.jubula.client.core.persistence.PMDirtyVersionException;
import org.eclipse.jubula.client.core.persistence.PMException;
import org.eclipse.jubula.client.core.persistence.PMObjectDeletedException;
import org.eclipse.jubula.client.core.persistence.locking.LockManager;
import org.eclipse.jubula.client.core.utils.StringHelper;
import org.eclipse.jubula.client.ui.constants.CommandIDs;
import org.eclipse.jubula.client.ui.constants.ContextHelpIds;
import org.eclipse.jubula.client.ui.constants.IconConstants;
import org.eclipse.jubula.client.ui.provider.DecoratingCellLabelProvider;
import org.eclipse.jubula.client.ui.rcp.Plugin;
import org.eclipse.jubula.client.ui.rcp.actions.ActivateEditorForSpecTCAction;
import org.eclipse.jubula.client.ui.rcp.businessprocess.UINodeBP;
import org.eclipse.jubula.client.ui.rcp.controllers.PMExceptionHandler;
import org.eclipse.jubula.client.ui.rcp.controllers.TestExecutionContributor;
import org.eclipse.jubula.client.ui.rcp.controllers.dnd.EventHandlerDropTargetListener;
import org.eclipse.jubula.client.ui.rcp.controllers.dnd.TCEditorDropTargetListener;
import org.eclipse.jubula.client.ui.rcp.dialogs.AddEventHandlerDialog;
import org.eclipse.jubula.client.ui.rcp.i18n.Messages;
import org.eclipse.jubula.client.ui.rcp.provider.ControlDecorator;
import org.eclipse.jubula.client.ui.rcp.provider.contentprovider.EventHandlerContentProvider;
import org.eclipse.jubula.client.ui.rcp.provider.labelprovider.TooltipLabelProvider;
import org.eclipse.jubula.client.ui.rcp.provider.selectionprovider.SelectionProviderIntermediate;
import org.eclipse.jubula.client.ui.rcp.utils.UIIdentitiyElementComparer;
import org.eclipse.jubula.client.ui.utils.CommandHelper;
import org.eclipse.jubula.client.ui.utils.DialogUtils;
import org.eclipse.jubula.client.ui.utils.ErrorHandlingUtil;
import org.eclipse.jubula.tools.internal.exception.InvalidDataException;
import org.eclipse.jubula.tools.internal.exception.ProjectDeletedException;
import org.eclipse.jubula.tools.internal.i18n.I18n;
import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs;
import org.eclipse.jubula.tools.internal.objects.IComponentIdentifier;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IWorkbenchPartConstants;
/**
* Editor for SpecTestCases
*
* @author BREDEX GmbH
* @created 05.09.2005
*/
@SuppressWarnings("synthetic-access")
public class TestCaseEditor extends AbstractTestCaseEditor
implements IRecordListener, IDoubleClickListener {
/** Constants for the editor segmentation */
private static final int[] SASH_WEIGHT = {75, 25};
/** the OM manager for this editor */
private ObjectMappingManager m_objectMappingManager =
new ObjectMappingManager();
/** TreeViewer for ErrorHandling */
private TreeViewer m_eventHandlerTreeViewer;
/** the current TreeViewer */
private TreeViewer m_currentTreeViewer;
/** the selection provider to handle both TreeViewer **/
private SelectionProviderIntermediate m_selectionProviderDelegate;
/** {@inheritDoc} */
public void createPartControlImpl(Composite parent) {
super.createPartControlImpl(parent);
getMainTreeViewer().addDoubleClickListener(this);
m_eventHandlerTreeViewer.setContentProvider(
new EventHandlerContentProvider());
m_eventHandlerTreeViewer.getControl().setMenu(
createContextMenu());
addDoubleClickListener(CommandIDs.OPEN_SPECIFICATION_COMMAND_ID,
m_eventHandlerTreeViewer);
if (!Plugin.getDefault().anyDirtyStar()) {
checkAndRemoveUnusedTestData();
}
m_currentTreeViewer = getMainTreeViewer();
m_selectionProviderDelegate = new SelectionProviderIntermediate();
m_selectionProviderDelegate
.setSelectionProviderDelegate(m_currentTreeViewer);
getSite().setSelectionProvider(m_selectionProviderDelegate);
}
/**
* when objectmapping exists, then lock OM
* @param monitor
* IProgressMonitor
*/
public void doSave(IProgressMonitor monitor) {
IPersistentObject inputTC =
getEditorHelper().getEditSupport().getWorkVersion();
ISpecTestCasePO recordTC = CAPRecordedCommand.getRecSpecTestCase();
boolean isStillObserving = CAPRecordedCommand.isObserving();
if (isStillObserving && inputTC.equals(recordTC)) {
int returnCode = showSaveInObservModeDialog();
if (returnCode == Window.OK) {
TestExecutionContributor.getInstance().
getClientTest().resetToTesting();
DataEventDispatcher.getInstance()
.fireRecordModeStateChanged(RecordModeState.notRunning);
isStillObserving = false;
}
}
if (!isStillObserving) {
try {
m_objectMappingManager.saveMappings();
refreshOMProfilesForAUTS();
removeIncorrectCompNamePairsInExecTcs();
super.doSave(monitor);
} catch (PMException e) {
PMExceptionHandler.handlePMExceptionForMasterSession(e);
} catch (ProjectDeletedException e) {
PMExceptionHandler.handleProjectDeletedException();
}
}
}
/**
* Removes incorrect CompNamePairs from all referencing Test Cases for
* which a lock can be acquired.
*/
private void removeIncorrectCompNamePairsInExecTcs() {
// Find all Test Case References in this project that reference this
// Test Case
INodePO workVersion =
(INodePO)getEditorHelper().getEditSupport().getWorkVersion();
List<Long> parentProjectIds = new ArrayList<Long>();
parentProjectIds.add(workVersion.getParentProjectId());
EntityManager editorSession =
getEditorHelper().getEditSupport().getSession();
List<IExecTestCasePO> execTcRefs =
NodePM.getExecTestCases(workVersion.getGuid(),
parentProjectIds, editorSession);
if (execTcRefs == null) {
return;
}
Set<INodePO> lockedNodePOs = new HashSet<INodePO>();
for (IExecTestCasePO execTc : execTcRefs) {
try {
INodePO parentNode = execTc.getSpecAncestor();
if (parentNode != null) {
INodePO editorSessionParentNode = editorSession.find(
parentNode.getClass(), parentNode.getId());
if (LockManager.instance().lockPO(editorSession,
editorSessionParentNode, true)) {
lockedNodePOs.add(editorSessionParentNode);
}
} else {
LOG.info("The parent of ExecTestCase (GUID " + execTc.getGuid() //$NON-NLS-1$
+ ") is null. Skipped removal of incorrect compNamePairs."); //$NON-NLS-1$
}
} catch (PMDirtyVersionException e) {
// Unable to successfully acquire lock
// Pairs for this node will not be updated
// Do nothing
} catch (PMObjectDeletedException e) {
// Unable to successfully acquire lock
// Pairs for this node will not be updated
// Do nothing
}
}
// Remove incorrect pairs for nodes for which we were able to acquire
// a lock.
for (INodePO node : lockedNodePOs) {
CompNamesBP.removeIncorrectCompNamePairs(getCompNameCache(), node);
}
}
/**
* Refresh all AUTs for the current project, so that we can avoid
* NonUniqueObjectException for same ObjectMappingProfilePO for multiple
* AUTs
*/
private void refreshOMProfilesForAUTS() {
EntityManager sess = GeneralStorage.getInstance().getMasterSession();
for (IAUTMainPO aut
: GeneralStorage.getInstance().getProject()
.getAutMainList()) {
sess.refresh(aut.getObjMap().getProfile());
}
}
/**
* {@inheritDoc}
*/
public String getEditorPrefix() {
return Messages.PluginTC;
}
/**
* {@inheritDoc}
*/
public void capRecorded(final ICapPO newCap,
final IComponentIdentifier ci, final boolean hasDefaultMapping) {
if (newCap == null) {
ErrorHandlingUtil.createMessageDialog(
MessageIDs.E_TEST_STEP_NOT_CREATED);
} else {
final IAUTMainPO recordAut =
TestExecution.getInstance().getConnectedAut();
Plugin.getDisplay().syncExec(new Runnable() {
public void run() {
if (getEditorHelper().requestEditableState()
!= JBEditorHelper.EditableState.OK) {
return;
}
// Cap added to model
// recorded action with default mapping not being
// added to objmap
if (!hasDefaultMapping) {
String capComponentName =
m_objectMappingManager.addMapping(
recordAut, ci, newCap.getComponentName());
newCap.setComponentName(capComponentName);
}
getTreeViewer().refresh(false);
getTreeViewer().setSelection(
new StructuredSelection(newCap), true);
getEditorHelper().setDirty(true);
}
});
}
}
/**
* @author BREDEX GmbH
* @created 02.06.2005
* Sets the actual tree selection of this editor depending of the selected tree.
*/
private class TreeFocusListener extends FocusAdapter {
/** {@inheritDoc} */
public void focusGained(FocusEvent e) {
Tree tree = (Tree)e.getSource();
if (getMainTreeViewer().getTree() == tree) {
m_currentTreeViewer = getMainTreeViewer();
} else if (getEventHandlerTreeViewer().getTree() == tree) {
m_currentTreeViewer = getEventHandlerTreeViewer();
}
if (m_selectionProviderDelegate != null) {
m_selectionProviderDelegate
.setSelectionProviderDelegate(m_currentTreeViewer);
}
}
}
/**
* {@inheritDoc}
*/
public Image getDisabledTitleImage() {
return IconConstants.DISABLED_TC_EDITOR_IMAGE;
}
/** {@inheritDoc}
* @see org.eclipse.jubula.client.ui.rcp.editors.TestCaseEditor#reOpenEditor(org.eclipse.jubula.client.core.model.IPersistentObject)
*/
public void reOpenEditor(IPersistentObject node) throws PMException {
m_objectMappingManager.clear();
super.reOpenEditor(node);
if (node instanceof ISpecTestCasePO) {
CAPRecordedCommand.setRecSpecTestCase((ISpecTestCasePO)node);
}
}
/**
* Sets the help to the HelpSystem.
* @param parent the parent composite to set the help id to
*/
protected void setHelp(Composite parent) {
Plugin.getHelpSystem().setHelp(parent,
ContextHelpIds.JB_SPEC_TESTCASE_EDITOR);
}
/**
* Shows information dialog that saving on observation mode is not allowed
* @return returnCode of Dialog
*/
private int showSaveInObservModeDialog() {
MessageDialog dialog = new MessageDialog(
Plugin.getActiveWorkbenchWindowShell(),
Messages.SaveInObservationModeDialogTitle,
null, Messages.SaveInObservationModeDialogQuestion,
MessageDialog.QUESTION, new String[] {
Messages.DialogMessageButton_YES,
Messages.DialogMessageButton_NO }, 0);
dialog.create();
DialogUtils.setWidgetNameForModalDialog(dialog);
dialog.open();
return dialog.getReturnCode();
}
@Override
public ISelection getSelection() {
if (m_currentTreeViewer == null) {
return StructuredSelection.EMPTY;
}
return m_currentTreeViewer.getSelection();
}
/**
* Creates the EventHandler part of the editor
* @param parent Composite
*/
private void createEventHandlerPart(Composite parent) {
Composite headLineComposite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(1, true);
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.marginBottom = 0;
layout.marginTop = 0;
headLineComposite.setLayout(layout);
Label headLine = new Label(headLineComposite, SWT.NONE);
headLine.setText(Messages.TestCaseEditorEHAreaHeadline);
ControlDecorator.createInfo(headLine,
I18n.getString("ControlDecorator.EventHandler"), //$NON-NLS-1$
false);
GridData ehTvGridData = new GridData();
ehTvGridData.grabExcessHorizontalSpace = true;
ehTvGridData.grabExcessVerticalSpace = true;
ehTvGridData.horizontalAlignment = SWT.FILL;
ehTvGridData.verticalAlignment = SWT.FILL;
ehTvGridData.verticalSpan = 100;
GridLayout ehTvLayout = new GridLayout(1, true);
ehTvLayout.marginWidth = 0;
ehTvLayout.marginHeight = 0;
ehTvLayout.marginBottom = 0;
ehTvLayout.marginTop = 0;
m_eventHandlerTreeViewer = new TreeViewer(headLineComposite);
m_eventHandlerTreeViewer.getTree().setLayout(ehTvLayout);
m_eventHandlerTreeViewer.getTree().setLayoutData(ehTvGridData);
ColumnViewerToolTipSupport.enableFor(m_eventHandlerTreeViewer);
DecoratingCellLabelProvider lp = new DecoratingCellLabelProvider (
new TooltipLabelProvider(), Plugin.getDefault().getWorkbench()
.getDecoratorManager().getLabelDecorator());
m_eventHandlerTreeViewer.setLabelProvider(lp);
m_eventHandlerTreeViewer.setComparer(new UIIdentitiyElementComparer());
m_eventHandlerTreeViewer.setUseHashlookup(true);
firePropertyChange(IWorkbenchPartConstants.PROP_INPUT);
}
/**
* {@inheritDoc}
*/
protected void addInternalSelectionListeners(
final ISelectionChangedListener editorSelectionChangedListener) {
super.addInternalSelectionListeners(editorSelectionChangedListener);
m_eventHandlerTreeViewer.addSelectionChangedListener(
editorSelectionChangedListener);
}
@Override
protected void addDragAndDropSupport(
int operations, Transfer[] transfers) {
super.addDragAndDropSupport(operations, transfers);
m_eventHandlerTreeViewer.addDropSupport(operations, transfers,
new EventHandlerDropTargetListener(this));
}
/**
* @return Returns the eventHandlerTreeViewer.
*/
public TreeViewer getEventHandlerTreeViewer() {
return m_eventHandlerTreeViewer;
}
/**
* Adds the given eventHandlerInput to the given eventHandlerOwner
* as an eventHandler.
* @param eventHandlerInput the ISpecTestCasePO to be the EventHandler
* @param evHandlerOwner the ISpecTestCasePO to own the EventHandler
*/
public void addEventHandler(ISpecTestCasePO eventHandlerInput,
ISpecTestCasePO evHandlerOwner) {
final EditSupport editSupport = getEditorHelper().getEditSupport();
ISpecTestCasePO workSpecTcPO = (ISpecTestCasePO)editSupport
.getWorkVersion();
ISpecTestCasePO eventHandlerInputPO = eventHandlerInput;
IEventExecTestCasePO eventHandlerPO = null;
try {
ISpecTestCasePO eventHandlerWorkV = (ISpecTestCasePO)editSupport
.createWorkVersion(eventHandlerInputPO);
eventHandlerPO = NodeMaker.createEventExecTestCasePO(
eventHandlerWorkV, workSpecTcPO);
final int status = openAddEventHandlerDlg(evHandlerOwner,
eventHandlerPO);
if (Window.OK == status) {
editSupport.lockWorkVersion();
TestCaseBP.addEventHandler(editSupport, workSpecTcPO,
eventHandlerPO);
getEditorHelper().setDirty(true);
DataEventDispatcher.getInstance().fireDataChangedListener(
eventHandlerPO, DataState.Added,
UpdateState.onlyInEditor);
}
} catch (InvalidDataException e) {
// no log entry, because it is a use case!
ErrorHandlingUtil.createMessageDialog(
MessageIDs.E_DOUBLE_EVENT, null,
new String[]{NLS.bind(
Messages.TestCaseEditorDoubleEventTypeErrorDetail,
new Object[]{evHandlerOwner.getName(),
I18n.getString(eventHandlerPO.getEventType())})});
} catch (PMException e) {
PMExceptionHandler.handlePMExceptionForMasterSession(e);
}
}
/**
* opens the AddEventHandlerDlg.
* @param eventHandlerCont the SpecTestCasePO
* @param eventHandler the EventExecTestCasePO
* @return status the window return code.
*/
private int openAddEventHandlerDlg(
IEventHandlerContainer eventHandlerCont,
final IEventExecTestCasePO eventHandler) {
AddEventHandlerDialog dialog =
new AddEventHandlerDialog(Plugin.getActiveWorkbenchWindowShell(),
eventHandler.getSpecTestCase().getName(), eventHandlerCont);
dialog.addListener(new AddEventHandlerDialog.Listener() {
public void notifySelected(String refName, String eventType,
String reentryType, Integer maxRetries) {
String evType = StringHelper.getInstance().getMap()
.get(eventType);
setEventHandlerProperties(eventHandler, refName, evType,
reentryType, maxRetries);
}
});
int status = dialog.open();
dialog.close();
return status;
}
/**
* {@inheritDoc}
*/
public void handlePropertyChanged(boolean isCompNameChanged) {
super.handlePropertyChanged(isCompNameChanged);
Plugin.getDisplay().syncExec(new Runnable() {
public void run() {
getEventHandlerTreeViewer().refresh();
}
});
}
@Override
protected SashForm createSashForm(Composite parent) {
SashForm form = super.createSashForm(parent);
createEventHandlerPart(form);
form.setWeights(SASH_WEIGHT);
return form;
}
@Override
public void setInitialInput() {
super.setInitialInput();
m_eventHandlerTreeViewer.setContentProvider(
new EventHandlerContentProvider());
ISpecTestCasePO workVersion = getWorkVersion();
m_eventHandlerTreeViewer.setInput(workVersion);
m_eventHandlerTreeViewer.expandAll();
m_eventHandlerTreeViewer.getTree().addFocusListener(
new TreeFocusListener());
}
@Override
protected void initTopTreeViewer(INodePO root) {
super.initTopTreeViewer(root);
getMainTreeViewer().getTree().addFocusListener(
new TreeFocusListener());
}
@Override
public void refresh() {
super.refresh();
Plugin.getDisplay().syncExec(new Runnable() {
public void run() {
getEventHandlerTreeViewer().refresh();
}
});
}
/** {@inheritDoc} */
protected DropTargetListener getViewerDropAdapter() {
return new TCEditorDropTargetListener(this);
}
/**
* @return the work version to use for this editor
*/
protected ISpecTestCasePO getWorkVersion() {
return (ISpecTestCasePO)super.getWorkVersion();
}
/** {@inheritDoc} */
public void setSelectionImpl(ISelection selection) {
if (selection instanceof StructuredSelection) {
StructuredSelection ss = (StructuredSelection) selection;
Object firstElement = ss.getFirstElement();
if (firstElement instanceof IEventExecTestCasePO) {
UINodeBP.setFocusAndSelection(ss, getEventHandlerTreeViewer());
} else {
super.setSelectionImpl(selection);
}
}
}
/** {@inheritDoc} */
public void setFocus() {
m_currentTreeViewer.getTree().setFocus();
Plugin.showStatusLine(this);
}
@Override
public void doubleClick(DoubleClickEvent event) {
if ((event.getSelection() instanceof IStructuredSelection)) {
Object selObj = ((IStructuredSelection) event.getSelection()).
getFirstElement();
if (selObj != null && selObj.equals(getWorkVersion())) {
ActivateEditorForSpecTCAction.activateEditor(
getWorkVersion());
}
}
CommandHelper.executeCommand(CommandIDs.OPEN_SPECIFICATION_COMMAND_ID,
getSite());
}
/** {@inheritDoc} */
public Image getIcon() {
return IconConstants.TC_EDITOR_IMAGE;
}
}