/******************************************************************************* * 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.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.persistence.EntityManager; import org.apache.commons.lang.StringUtils; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.util.LocalSelectionTransfer; import org.eclipse.jface.viewers.DecoratingLabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ViewerDropAdapter; import org.eclipse.jubula.client.core.businessprocess.CentralTestDataBP; import org.eclipse.jubula.client.core.businessprocess.TestDataCubeBP; 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.events.DataEventDispatcher.IParamChangedListener; import org.eclipse.jubula.client.core.events.DataEventDispatcher.UpdateState; import org.eclipse.jubula.client.core.model.INodePO; import org.eclipse.jubula.client.core.model.IPersistentObject; import org.eclipse.jubula.client.core.model.ITDManager; import org.eclipse.jubula.client.core.model.ITestDataCategoryPO; import org.eclipse.jubula.client.core.model.ITestDataCubePO; import org.eclipse.jubula.client.core.persistence.EditSupport; import org.eclipse.jubula.client.core.persistence.GeneralStorage; 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.constants.RCPCommandIDs; import org.eclipse.jubula.client.ui.rcp.controllers.PMExceptionHandler; import org.eclipse.jubula.client.ui.rcp.controllers.dnd.objectmapping.LimitingDragSourceListener; import org.eclipse.jubula.client.ui.rcp.editors.JBEditorHelper.EditableState; import org.eclipse.jubula.client.ui.rcp.events.GuiEventDispatcher; import org.eclipse.jubula.client.ui.rcp.filter.JBBrowserPatternFilter; import org.eclipse.jubula.client.ui.rcp.filter.JBFilteredTree; import org.eclipse.jubula.client.ui.rcp.i18n.Messages; import org.eclipse.jubula.client.ui.rcp.provider.contentprovider.CentralTestDataContentProvider; import org.eclipse.jubula.client.ui.rcp.provider.labelprovider.CentralTestDataLabelProvider; import org.eclipse.jubula.client.ui.utils.CommandHelper; import org.eclipse.jubula.tools.internal.exception.ProjectDeletedException; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.dnd.TransferData; 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.widgets.Composite; import org.eclipse.ui.IWorkbenchPartConstants; import org.eclipse.ui.dialogs.FilteredTree; import org.eclipse.ui.menus.CommandContributionItem; /** * @author BREDEX GmbH * @created Jun 28, 2010 */ public class CentralTestDataEditor extends AbstractJBEditor implements IParamChangedListener { /** * <code>m_elementsToRefresh</code> set of elements to refresh after saving * the editor */ private Set<ITestDataCubePO> m_elementsToRefresh = new HashSet<ITestDataCubePO>(); /** * * @author Zeb Ford-Reitz * @created Nov 03, 2011 */ private class CentralTestDataDropSupport extends ViewerDropAdapter { /** * Constructor * * @param viewer The viewer. */ public CentralTestDataDropSupport(Viewer viewer) { super(viewer); } @Override public boolean validateDrop(Object target, int operation, TransferData transferType) { ISelection selection = LocalSelectionTransfer.getTransfer().getSelection(); if (getTargetCategory(target) != null && selection instanceof IStructuredSelection) { for (Object element : ((IStructuredSelection)selection).toArray()) { if (!(element instanceof ITestDataCategoryPO || element instanceof ITestDataCubePO)) { return false; } } return true; } return false; } @Override public boolean performDrop(Object data) { if (getEditorHelper().requestEditableState() != EditableState.OK) { return false; } ITestDataCategoryPO targetCategory = getTargetCategory(getCurrentTarget()); ISelection selection = LocalSelectionTransfer.getTransfer().getSelection(); Set<ITestDataCategoryPO> structuresToUpdate = new HashSet<ITestDataCategoryPO>(); structuresToUpdate.add(targetCategory); for (Object element : ((IStructuredSelection)selection).toArray()) { if (element instanceof ITestDataCategoryPO) { ITestDataCategoryPO category = (ITestDataCategoryPO)element; if (!CentralTestDataBP.getAncestors(targetCategory) .contains(category) && category.getParent() != targetCategory) { ITestDataCategoryPO oldParent = category.getParent(); structuresToUpdate.add(oldParent); oldParent.removeCategory(category); targetCategory.addCategory(category); } } else if (element instanceof ITestDataCubePO) { ITestDataCubePO testData = (ITestDataCubePO)element; ITestDataCategoryPO oldParent = testData.getParent(); structuresToUpdate.add(oldParent); oldParent.removeTestData(testData); targetCategory.addTestData(testData); } } List<DataChangedEvent> events = new LinkedList<DataChangedEvent>(); for (ITestDataCategoryPO categoryToUpdate : structuresToUpdate) { events.add(new DataChangedEvent(categoryToUpdate, DataState.StructureModified, UpdateState.onlyInEditor)); } DataEventDispatcher.getInstance().fireDataChangedListener( events.toArray(new DataChangedEvent[events.size()])); return true; } /** * * @param target The drop target. * @return the adjusted drop target. For example, the top-level category * if <code>target</code> is null. Returns <code>null</code> * if no valid drop target can be computed. */ private ITestDataCategoryPO getTargetCategory(Object target) { if (target == null) { return (ITestDataCategoryPO)getViewer().getInput(); } if (target instanceof ITestDataCategoryPO) { return (ITestDataCategoryPO)target; } return null; } } /** {@inheritDoc} */ protected void createPartControlImpl(Composite parent) { createMainPart(parent); GridData gridData = new GridData(GridData.FILL_BOTH); getMainTreeViewer().getControl().setLayoutData(gridData); setControl(getMainTreeViewer().getControl()); getMainTreeViewer().setContentProvider( new CentralTestDataContentProvider()); DecoratingLabelProvider lp = new DecoratingLabelProvider( new CentralTestDataLabelProvider(), Plugin.getDefault() .getWorkbench().getDecoratorManager() .getLabelDecorator()); getMainTreeViewer().setLabelProvider(lp); getMainTreeViewer().setComparator(new ViewerComparator() { @Override public int category(Object element) { if (element instanceof ITestDataCategoryPO) { return 0; } if (element instanceof ITestDataCubePO) { return 1; } return 2; } }); int ops = DND.DROP_MOVE; Transfer[] transfers = new Transfer[] { LocalSelectionTransfer.getTransfer()}; ViewerDropAdapter dropSupport = new CentralTestDataDropSupport(getMainTreeViewer()); dropSupport.setFeedbackEnabled(false); getMainTreeViewer().addDragSupport(ops, transfers, new LimitingDragSourceListener(getMainTreeViewer(), null)); getMainTreeViewer().addDropSupport(ops, transfers, dropSupport); addDoubleClickListener(RCPCommandIDs.EDIT_PARAMETERS, getMainTreeViewer()); addFocusListener(getMainTreeViewer()); getEditorHelper().addListeners(); setActionHandlers(); setInitialInput(); DataEventDispatcher ded = DataEventDispatcher.getInstance(); ded.addPropertyChangedListener(this, true); ded.addParamChangedListener(this, true); GuiEventDispatcher.getInstance() .addEditorDirtyStateListener(this, true); } /** {@inheritDoc} */ public void dispose() { DataEventDispatcher ded = DataEventDispatcher.getInstance(); ded.removeParamChangedListener(this); getElementsToRefresh().clear(); super.dispose(); } /** * creates and sets the partName */ protected void createPartName() { setPartName(Messages.CentralTestDataEditorName); } /** * @param mainTreeViewer * the tree viewer */ private void addFocusListener(TreeViewer mainTreeViewer) { mainTreeViewer.getTree().addFocusListener(new FocusAdapter() { /** {@inheritDoc} */ public void focusGained(FocusEvent e) { getMainTreeViewer().setSelection( getMainTreeViewer().getSelection(), true); } }); } /** {@inheritDoc} */ protected void fillContextMenu(IMenuManager mgr) { CommandHelper.createContributionPushItem(mgr, RCPCommandIDs.NEW_TESTDATACUBE); CommandHelper.createContributionPushItem(mgr, RCPCommandIDs.NEW_CATEGORY); CommandHelper.createContributionPushItem(mgr, RCPCommandIDs.RENAME); CommandHelper.createContributionPushItem(mgr, RCPCommandIDs.EDIT_PARAMETERS); mgr.add(new Separator()); CommandHelper.createContributionPushItem(mgr, RCPCommandIDs.SHOW_WHERE_USED); CommandHelper.createContributionPushItem(mgr, RCPCommandIDs.REVERT_CHANGES); CommandHelper.createContributionPushItem(mgr, CommandIDs.DELETE_COMMAND_ID); mgr.add(CommandHelper.createContributionItem( RCPCommandIDs.FIND, null, Messages.FindContextMenu, CommandContributionItem.STYLE_PUSH)); mgr.add(new Separator()); CommandHelper.createContributionPushItem(mgr, RCPCommandIDs.IMPORT_TEST_DATA_SET); } /** {@inheritDoc} */ protected void setHelp(Composite parent) { Plugin.getHelpSystem().setHelp(parent, ContextHelpIds.CENTRAL_TESTDATA_EDITOR); } /** {@inheritDoc} */ protected void setInitialInput() { final ITestDataCategoryPO rootPOTop = (ITestDataCategoryPO) getEditorHelper().getEditSupport().getWorkVersion(); Plugin.getDisplay().syncExec(new Runnable() { public void run() { try { getTreeViewer().getTree().getParent().setRedraw(false); getTreeViewer().setInput(rootPOTop); getTreeViewer().expandAll(); } finally { getTreeViewer().getTree().getParent().setRedraw(true); } } }); } /** {@inheritDoc} */ public void doSave(IProgressMonitor monitor) { monitor.beginTask(Messages.EditorsSaveEditors, IProgressMonitor.UNKNOWN); EditSupport editSupport = getEditorHelper().getEditSupport(); try { editSupport.saveWorkVersion(); final EntityManager masterSession = GeneralStorage.getInstance() .getMasterSession(); IPersistentObject original = editSupport.getOriginal(); if (original != null) { masterSession.refresh(original); if (original instanceof ITestDataCategoryPO) { refreshChilds(masterSession, original); } } updateReferencedParamNodes(); getEditorHelper().resetEditableState(); getEditorHelper().setDirty(false); } catch (PMException e) { PMExceptionHandler.handlePMExceptionForMasterSession(e); try { reOpenEditor( ((PersistableEditorInput)getEditorInput()).getNode()); } catch (PMException e1) { PMExceptionHandler.handlePMExceptionForEditor(e, this); } } catch (ProjectDeletedException e) { PMExceptionHandler.handleProjectDeletedException(); } finally { monitor.done(); } } /** * Does the refresh cascading manually * @param session * the session in which you want to refresh * @param testDataCategory * the category which child's should be refreshed */ private void refreshChilds(final EntityManager session, IPersistentObject testDataCategory) { for (ITestDataCategoryPO catergory : ((ITestDataCategoryPO) testDataCategory) .getCategoryChildren()) { session.refresh(catergory); refreshChilds(session, catergory); } for (ITestDataCubePO dataCube : ((ITestDataCategoryPO) testDataCategory) .getTestDataChildren()) { session.refresh(dataCube); ITDManager manager = dataCube.getDataManager(); session.refresh(manager); } } /** * update the param nodes which reference test data cube, e.g. because of * renaming of test data cube */ private void updateReferencedParamNodes() { Set<INodePO> nodesToRefresh = new HashSet<INodePO>(); for (ITestDataCubePO tdc : getElementsToRefresh()) { nodesToRefresh.addAll(TestDataCubeBP.getReuser(tdc)); } EntityManager masterSession = GeneralStorage.getInstance().getMasterSession(); for (INodePO node : nodesToRefresh) { masterSession.refresh(node); } getElementsToRefresh().clear(); } /** {@inheritDoc} */ public Image getDisabledTitleImage() { return IconConstants.DISABLED_CTD_EDITOR_IMAGE; } /** {@inheritDoc} */ public String getEditorPrefix() { return Messages.PluginCTD; } /** {@inheritDoc} */ public void handlePropertyChanged(boolean isCompNameChanged) { Plugin.getDisplay().syncExec(new Runnable() { public void run() { getMainTreeViewer().refresh(); } }); } /** {@inheritDoc} */ public void handleParamChanged(Object caller) { // assuming that the currently selected element (or rather, // all currently selected elements) have had some kind of param change Plugin.getDisplay().syncExec(new Runnable() { public void run() { ISelection currentSelection = getMainTreeViewer() .getSelection(); if (currentSelection instanceof IStructuredSelection) { for (Object selectedObj : ((IStructuredSelection) currentSelection).toArray()) { if (selectedObj instanceof ITestDataCubePO) { getElementsToRefresh().add( (ITestDataCubePO)selectedObj); } } } getMainTreeViewer().refresh(); } }); } /** {@inheritDoc} */ public void handleDataChanged(final DataChangedEvent... events) { Plugin.getDisplay().syncExec(new Runnable() { public void run() { getMainTreeViewer().getTree().setRedraw(false); } }); try { for (DataChangedEvent e : events) { handleDataChanged(e.getPo(), e.getDataState(), e.getUpdateState()); } } finally { Plugin.getDisplay().syncExec(new Runnable() { public void run() { getMainTreeViewer().getTree().setRedraw(true); } }); } } /** {@inheritDoc} */ public void handleDataChanged(IPersistentObject po, DataState dataState, UpdateState updateState) { if (po instanceof ITestDataCubePO) { if (updateState == UpdateState.onlyInEditor) { getEditorHelper().setDirty(true); } ITestDataCubePO tdc = (ITestDataCubePO)po; handleDataChanged(dataState, tdc); } else if (po instanceof ITestDataCategoryPO) { if (updateState == UpdateState.onlyInEditor) { getEditorHelper().setDirty(true); } handleDataChanged(dataState, (ITestDataCategoryPO)po); } } /** * @param dataState * the data state * @param testData * the data cube */ private void handleDataChanged( DataState dataState, ITestDataCubePO testData) { switch (dataState) { case Added: getTreeViewer().refresh(); getTreeViewer().add(testData.getParent(), testData); getTreeViewer().setSelection(new StructuredSelection(testData)); break; case Deleted: getTreeViewer().remove(testData); break; case Renamed: getTreeViewer().update(testData, null); getElementsToRefresh().add(testData); break; case ReuseChanged: break; case StructureModified: getTreeViewer().update(testData, null); getTreeViewer().setSelection(new StructuredSelection(testData)); break; default: break; } } /** * @param dataState * the data state * @param category * the category */ private void handleDataChanged(final DataState dataState, final ITestDataCategoryPO category) { Plugin.getDisplay().syncExec(new Runnable() { public void run() { switch (dataState) { case Added: getTreeViewer().add(category.getParent(), category); getTreeViewer().setSelection( new StructuredSelection(category)); break; case Deleted: getTreeViewer().remove(category); break; case Renamed: getTreeViewer().update(category, null); break; case ReuseChanged: break; case StructureModified: getTreeViewer().refresh(category); break; default: break; } } }); } /** * Creates the specification part of the editor * * @param parent * Composite. */ protected void createMainPart(Composite parent) { final FilteredTree ft = new JBFilteredTree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER, new JBBrowserPatternFilter(), true); setMainTreeViewer(ft.getViewer()); getMainTreeViewer().setUseHashlookup(true); getSite().setSelectionProvider(this); firePropertyChange(IWorkbenchPartConstants.PROP_INPUT); } /** * @return the elementsToRefresh */ private Set<ITestDataCubePO> getElementsToRefresh() { return m_elementsToRefresh; } @Override public String getTitleToolTip() { return StringUtils.EMPTY; } /** * Sets all necessary global action handlers for this editor. This * ensures that the editor's actions control the enablement of the * corresponding actions in the main menu. */ protected void setActionHandlers() { getSite().setSelectionProvider(this); getEditorSite().getActionBars().updateActionBars(); } }