/******************************************************************************* * 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.Iterator; import java.util.List; import org.apache.commons.collections.IteratorUtils; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jubula.client.core.businessprocess.db.TimestampBP; import org.eclipse.jubula.client.core.events.DataChangedEvent; import org.eclipse.jubula.client.core.events.DataEventDispatcher; import org.eclipse.jubula.client.core.events.DataEventDispatcher.DataState; import org.eclipse.jubula.client.core.model.INodePO; import org.eclipse.jubula.client.core.model.IPersistentObject; import org.eclipse.jubula.client.core.model.IProjectPO; import org.eclipse.jubula.client.core.model.IRefTestSuitePO; import org.eclipse.jubula.client.core.model.ITestSuitePO; import org.eclipse.jubula.client.core.model.ITimestampPO; import org.eclipse.jubula.client.core.persistence.EditSupport; import org.eclipse.jubula.client.core.persistence.NodePM; import org.eclipse.jubula.client.core.persistence.PMException; 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.rcp.Plugin; import org.eclipse.jubula.client.ui.rcp.businessprocess.UINodeBP; import org.eclipse.jubula.client.ui.rcp.constants.RCPCommandIDs; import org.eclipse.jubula.client.ui.rcp.controllers.PMExceptionHandler; import org.eclipse.jubula.client.ui.rcp.controllers.dnd.LocalSelectionTransfer; import org.eclipse.jubula.client.ui.rcp.controllers.dnd.TJEditorDropTargetListener; import org.eclipse.jubula.client.ui.rcp.controllers.dnd.TreeViewerContainerDragSourceListener; import org.eclipse.jubula.client.ui.rcp.events.GuiEventDispatcher; import org.eclipse.jubula.client.ui.rcp.i18n.Messages; import org.eclipse.jubula.client.ui.rcp.provider.contentprovider.TestJobEditorContentProvider; import org.eclipse.jubula.client.ui.utils.CommandHelper; import org.eclipse.jubula.client.ui.utils.ErrorHandlingUtil; import org.eclipse.jubula.tools.internal.exception.Assert; import org.eclipse.jubula.tools.internal.exception.ProjectDeletedException; import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IWorkbenchCommandConstants; import org.eclipse.ui.menus.CommandContributionItem; /** * The Test Job Editor * * @author BREDEX GmbH * @created Mar 17, 2010 */ public class TestJobEditor extends AbstractJBEditor { /** * {@inheritDoc} */ public String getEditorPrefix() { return Messages.PluginTJ; } /** * {@inheritDoc} */ public void createPartControlImpl(Composite parent) { createMainPart(parent); GridData gridData = new GridData(GridData.FILL_BOTH); getMainTreeViewer().getControl().setLayoutData(gridData); setControl(getMainTreeViewer().getControl()); getMainTreeViewer().setContentProvider( new TestJobEditorContentProvider()); addDragAndDropSupport(); getEditorHelper().addListeners(); setActionHandlers(); addDoubleClickListener(CommandIDs.OPEN_SPECIFICATION_COMMAND_ID, getMainTreeViewer()); setInitialInput(); DataEventDispatcher ded = DataEventDispatcher.getInstance(); ded.addPropertyChangedListener(this, true); GuiEventDispatcher.getInstance().addEditorDirtyStateListener( this, true); } @Override public void setInitialInput() { INodePO root = (INodePO)getEditorHelper().getEditSupport().getWorkVersion(); try { getTreeViewer().getTree().getParent().setRedraw(false); getTreeViewer().setInput(new INodePO[] {root}); getTreeViewer().expandAll(); } finally { getTreeViewer().getTree().getParent().setRedraw(true); } } /** * adds Drag and Drop support for the trees. */ protected void addDragAndDropSupport() { int ops = DND.DROP_MOVE; Transfer[] transfers = new Transfer[] { LocalSelectionTransfer .getInstance() }; getMainTreeViewer().addDragSupport(ops, transfers, new TreeViewerContainerDragSourceListener(getTreeViewer())); getMainTreeViewer().addDropSupport(ops, transfers, new TJEditorDropTargetListener(this)); } /** * {@inheritDoc} */ protected void fillContextMenu(IMenuManager mgr) { CommandHelper.createContributionPushItem(mgr, IWorkbenchCommandConstants.EDIT_COPY); CommandHelper.createContributionPushItem(mgr, IWorkbenchCommandConstants.EDIT_PASTE); mgr.add(new Separator()); mgr.add(new GroupMarker("editing")); //$NON-NLS-1$ CommandHelper.createContributionPushItem(mgr, RCPCommandIDs.REVERT_CHANGES); mgr.add(new Separator()); CommandHelper.createContributionPushItem(mgr, CommandIDs.DELETE_COMMAND_ID); mgr.add(CommandHelper.createContributionItem( RCPCommandIDs.FIND, null, Messages.FindContextMenu, CommandContributionItem.STYLE_PUSH)); CommandHelper.createContributionPushItem(mgr, CommandIDs.OPEN_SPECIFICATION_COMMAND_ID); CommandHelper.createContributionPushItem(mgr, CommandIDs.SHOW_SPECIFICATION_COMMAND_ID); CommandHelper.createContributionPushItem(mgr, CommandIDs.EXPAND_TREE_ITEM_COMMAND_ID); mgr.add(new Separator()); CommandHelper.createContributionPushItem(mgr, RCPCommandIDs.NEW_COMMENT); CommandHelper.createContributionPushItem(mgr, RCPCommandIDs.EDIT_COMMENT); } /** * {@inheritDoc} */ protected void setHelp(Composite parent) { Plugin.getHelpSystem().setHelp(parent, ContextHelpIds.TEST_JOB_EDITOR); } /** * {@inheritDoc} */ public void doSave(IProgressMonitor monitor) { monitor.beginTask(Messages.EditorsSaveEditors, IProgressMonitor.UNKNOWN); try { EditSupport editSupport = getEditorHelper().getEditSupport(); final IPersistentObject perObj = editSupport.getWorkVersion(); TimestampBP.refreshTimestamp((ITimestampPO)perObj); editSupport.saveWorkVersion(); getEditorHelper().resetEditableState(); getEditorHelper().setDirty(false); } catch (PMException e) { PMExceptionHandler.handlePMExceptionForMasterSession(e); try { reOpenEditor(((NodeEditorInput)getEditorInput()).getNode()); } catch (PMException e1) { PMExceptionHandler.handlePMExceptionForEditor(e, this); } } catch (ProjectDeletedException e) { PMExceptionHandler.handleProjectDeletedException(); } finally { monitor.done(); } } /** * {@inheritDoc} */ public Image getDisabledTitleImage() { return IconConstants.DISABLED_TJ_EDITOR_IMAGE; } /** {@inheritDoc} */ public void handleDataChanged(final DataChangedEvent... events) { Plugin.getDisplay().syncExec(new Runnable() { @Override public void run() { for (DataChangedEvent e : events) { handleDataChanged(e.getPo(), e.getDataState()); } } }); } /** * {@inheritDoc} */ public void handleDataChanged(IPersistentObject po, DataState dataState) { if (po instanceof INodePO) { TreeViewer tv = getTreeViewer(); switch (dataState) { case Added: INodePO addedNode = (INodePO)po; INodePO editorNode = (INodePO)getEditorHelper() .getEditSupport().getWorkVersion(); if (editorNode.indexOf(addedNode) > -1) { getTreeViewer().refresh(); getTreeViewer().expandAll(); UINodeBP.setFocusAndSelection(new StructuredSelection( addedNode), tv); } break; case Deleted: if (!(po instanceof IProjectPO)) { getTreeViewer().refresh(); setFocus(); } break; case Renamed: createPartName(); break; case StructureModified: if (!handleStructureModified(po)) { return; } break; case ReuseChanged: // nothing yet! break; default: Assert.notReached(); } getEditorHelper().handleDataChanged(po, dataState); } } /** * Handles a PO that has been modified. * * @param po * The modified object. * @return <code>false</code> if an error occurs during handling. Otherwise, * <code>true</code>. */ private boolean handleStructureModified(IPersistentObject po) { if (po instanceof ITestSuitePO) { final ITestSuitePO testsuitePO = (ITestSuitePO)po; final INodePO workVersion = (INodePO)getEditorHelper() .getEditSupport().getWorkVersion(); final List<IRefTestSuitePO> refTestSuites = NodePM .getInternalRefTestSuites(testsuitePO.getGuid(), testsuitePO.getParentProjectId()); if (!refTestSuites.isEmpty() && containsWorkVersionReuses(workVersion, testsuitePO)) { if (Plugin.getActiveEditor() != this && isDirty()) { ErrorHandlingUtil.createMessageDialog( MessageIDs.I_SAVE_AND_REOPEN_EDITOR, new Object[] { getTitle(), testsuitePO.getName() }, null); return false; } try { reOpenEditor(getEditorHelper().getEditSupport() .getOriginal()); } catch (PMException e) { ErrorHandlingUtil.createMessageDialog( MessageIDs.E_REFRESH_FAILED, null, new String[] { Messages.ErrorMessageEDITOR_CLOSE }); getSite().getPage().closeEditor(this, false); } return false; } } return true; } /** * @param root * node, where starts the validation * @param ts * changed test suite * @return if editor contains an reusing testcase for given specTestCase */ @SuppressWarnings("unchecked") private static boolean containsWorkVersionReuses(INodePO root, ITestSuitePO ts) { final Iterator it = root.getNodeListIterator(); final List<INodePO> childList = IteratorUtils.toList(it); for (INodePO child : childList) { if (child instanceof IRefTestSuitePO) { final IRefTestSuitePO refTs = (IRefTestSuitePO)child; if (ts.getGuid().equals(refTs.getTestSuiteGuid())) { return true; } if (containsWorkVersionReuses(refTs, ts)) { return true; } } } return false; } }