/******************************************************************************* * 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.properties; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jubula.client.core.businessprocess.db.TimestampBP; import org.eclipse.jubula.client.core.model.IExecTestCasePO; import org.eclipse.jubula.client.core.model.IProjectPO; import org.eclipse.jubula.client.core.model.IReusedProjectPO; import org.eclipse.jubula.client.core.model.PoMaker; 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.PMException; import org.eclipse.jubula.client.core.persistence.Persistor; import org.eclipse.jubula.client.core.persistence.ProjectPM; 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.i18n.Messages; import org.eclipse.jubula.client.ui.rcp.properties.ProjectGeneralPropertyPage.IOkListener; import org.eclipse.jubula.client.ui.rcp.widgets.ListElementChooserComposite; import org.eclipse.jubula.client.ui.rcp.widgets.TreeElementChooserComposite; import org.eclipse.jubula.client.ui.rcp.widgets.TreeElementChooserComposite.IChooserCompositeGuiObject; import org.eclipse.jubula.client.ui.rcp.widgets.TreeElementChooserComposite.IUsedListModifiedListener; import org.eclipse.jubula.client.ui.utils.ErrorHandlingUtil; import org.eclipse.jubula.client.ui.utils.LayoutUtil; import org.eclipse.jubula.toolkit.common.businessprocess.ToolkitSupportBP; import org.eclipse.jubula.toolkit.common.exception.ToolkitPluginException; import org.eclipse.jubula.tools.internal.constants.StringConstants; import org.eclipse.jubula.tools.internal.exception.JBException; import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs; import org.eclipse.persistence.jpa.JpaEntityManager; import org.eclipse.swt.SWT; 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.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.List; import org.eclipse.swt.widgets.Tree; /** * This is the class for the test data property page of a project. * * @author BREDEX GmbH * @created 08.02.2005 */ public class ProjectUsedPropertyPage extends AbstractProjectPropertyPage implements IOkListener { /** the list field for the available projects */ private Tree m_availableProjectsList; /** the list field for the used projects */ private List m_usedProjectsList; /** mapping between Strings in the selection lists and reused project info objects */ private Map<String, IReusedProjectPO> m_projectMap = new HashMap<String, IReusedProjectPO>(); /** the composite with 2 ListBoxes */ private UsedProjectsChooserComposite m_chooseLists = null; /** The currently selected projects (display strings) for reuse */ private String[] m_listEntries; /** * @param es the editSupport */ public ProjectUsedPropertyPage(EditSupport es) { super(es); } /** * {@inheritDoc} */ protected Control createContents(Composite parent) { Composite composite = createComposite(parent, GridData.FILL, false); noDefaultAndApplyButton(); createLabel(composite, Messages.ProjectPropertyPageSelectReusedProjects); Composite innerComposite = new Composite(composite, SWT.NONE); GridLayout compositeLayout = new GridLayout(); compositeLayout.marginHeight = 0; compositeLayout.marginWidth = 0; innerComposite.setLayout(compositeLayout); GridData compositeData = new GridData(); compositeData.horizontalAlignment = SWT.FILL; compositeData.grabExcessHorizontalSpace = true; innerComposite.setLayoutData(compositeData); try { createProjectLists(innerComposite); getObjects(); resizeLists(); } catch (ToolkitPluginException tpe) { composite.dispose(); composite = createComposite(parent, GridData.FILL, false); new Label(composite, SWT.NONE).setText( Messages.CouldNotLoadReusableProjects + StringConstants.COLON + StringConstants.NEWLINE + StringConstants.TAB + tpe.getLocalizedMessage()); } Plugin.getHelpSystem().setHelp(parent, ContextHelpIds.PROJECT_USED_PROPERTY_PAGE); return composite; } /** * @param innerComposite the parent composite */ private void createProjectLists(Composite innerComposite) throws ToolkitPluginException { Set<IReusedProjectPO> usedProjects = getProject().getUsedProjects(); Set<IChooserCompositeGuiObject> availableGuiObjects = new HashSet<IChooserCompositeGuiObject>(); Set<IChooserCompositeGuiObject> usedGuiObjects = new HashSet<IChooserCompositeGuiObject>(); try { String projectToolkit = getProject().getToolkit(); java.util.List<IProjectPO> reusableProjects = ProjectPM.findReusableProjects( getProject().getGuid(), getProject().getMajorProjectVersion(), getProject().getMinorProjectVersion(), getProject().getMicroProjectVersion(), getProject().getProjectVersionQualifier(), projectToolkit, ToolkitSupportBP.getToolkitLevel(projectToolkit)); for (IProjectPO proj : reusableProjects) { IReusedProjectPO reused = PoMaker.createReusedProjectPO(proj); IChooserCompositeGuiObject reusedGui = new ReusedProjectGuiObject(reused); availableGuiObjects.add(reusedGui); m_projectMap.put(reusedGui.getDisplayString(), reused); } for (IReusedProjectPO reused : usedProjects) { IChooserCompositeGuiObject guiObj = new ReusedProjectGuiObject(reused); usedGuiObjects.add(guiObj); m_projectMap.put(guiObj.getDisplayString(), reused); } m_chooseLists = new UsedProjectsChooserComposite(innerComposite, availableGuiObjects, usedGuiObjects); } catch (JBException gde) { // Loading of a project failed ErrorHandlingUtil.createMessageDialog(gde, null, null); } catch (ToolkitPluginException tpe) { // Toolkit plugin for the current project is not loaded ErrorHandlingUtil.createMessageDialog(MessageIDs.E_READ_PROJECT, null, new String [] { Messages.CannotFindReusableProjects }); throw tpe; } } /** * Resizes the two ListBoxes. */ private void resizeLists() { ((GridData)m_usedProjectsList.getLayoutData()).widthHint = Dialog .convertHeightInCharsToPixels(LayoutUtil .getFontMetrics(m_usedProjectsList), 15); ((GridData)m_availableProjectsList.getLayoutData()).widthHint = Dialog .convertHeightInCharsToPixels(LayoutUtil .getFontMetrics(m_usedProjectsList), 15); } /** * Creates a new composite. * @param parent The parent composite. * @param alignment The horizontalAlignment (grabExcess). * @param horizontalSpace The horizontalSpace. * @return The new composite. */ private Composite createComposite(Composite parent, int alignment, boolean horizontalSpace) { Composite composite = new Composite(parent, SWT.NONE); GridLayout compositeLayout = new GridLayout(); compositeLayout.marginHeight = 0; compositeLayout.marginWidth = 0; composite.setLayout(compositeLayout); GridData compositeData = new GridData(); compositeData.horizontalAlignment = alignment; compositeData.grabExcessHorizontalSpace = horizontalSpace; composite.setLayoutData(compositeData); return composite; } /** * Gets the listBoxes / Buttons from the ListElementChooserComposite composite */ private void getObjects() { m_availableProjectsList = m_chooseLists.getAvailableTree(); m_usedProjectsList = m_chooseLists.getUsedList(); } /** * Updates the used projects of the model. * @param usedProjects The projects that should be used. */ void updateProjects(String [] usedProjects) throws PMException { // Just clearing the list and re-adding all elements leads to // Persistence (JPA / EclipseLink) errors, so we must actually only add/remove the // elements that have changed. Set<IReusedProjectPO> toAdd = new HashSet<IReusedProjectPO>(); Set<IReusedProjectPO> toRemove = new HashSet<IReusedProjectPO>(); for (String displayableProjectId : usedProjects) { toAdd.add(m_projectMap.get(displayableProjectId)); } // toRemove: All elements that are currently used, but not in the new list IProjectPO workProject = getEditSupport().getWorkProject(); toRemove.addAll(workProject.getUsedProjects()); toRemove.removeAll(toAdd); // toAdd: All elements that are in the new list, but are currently used toAdd.removeAll(workProject.getUsedProjects()); for (IReusedProjectPO remove : toRemove) { workProject.removeUsedProject(remove); } boolean isDirty = getEditSupport().getSession().unwrap(JpaEntityManager.class) .getUnitOfWork().hasChanges(); // Prevents constraint violation from Persistence (JPA / EclipseLink) Persistor.instance().flushSession(getEditSupport().getSession()); if (isDirty) { // the session will not be committed if there are no pending changes TimestampBP.refreshTimestamp(workProject); } for (IReusedProjectPO reuse : toAdd) { workProject.addUsedProject(reuse); reuse.setParentProjectId(getProject().getId()); } } /** * GUI representation of a reused project. * * @author BREDEX GmbH * @created Aug 17, 2007 */ private class ReusedProjectGuiObject implements IChooserCompositeGuiObject { /** string for separating major and minor version number */ private static final String VER_SEP = "."; //$NON-NLS-1$ /** string that is show directly before the version number */ private static final String BEGIN_VER = " ["; //$NON-NLS-1$ /** string that is show directly after the version number */ private static final String END_VER = "]"; //$NON-NLS-1$ /** the reused project that this GUI object represents. */ private IReusedProjectPO m_modelObject; /** * Constructor * * @param modelObject the reused project that this GUI object * represents. */ public ReusedProjectGuiObject(IReusedProjectPO modelObject) { m_modelObject = modelObject; } /** * {@inheritDoc} */ public String getDisplayString() { String projectName = m_modelObject.getProjectName(); if (projectName == null) { projectName = m_modelObject.getProjectGuid(); } StringBuffer sb = new StringBuffer(projectName); sb.append(BEGIN_VER); sb.append(m_modelObject.getVersionString()); sb.append(END_VER); return sb.toString(); } /** * {@inheritDoc} */ public Object getModelObject() { return m_modelObject; } /** * {@inheritDoc} */ public String getParent() { return m_modelObject.getProjectName(); } /** * {@inheritDoc} */ public String getTitle() { StringBuffer sb = new StringBuffer(); sb.append(m_modelObject.getVersionString()); return sb.toString(); } /** * * {@inheritDoc} */ public String toString() { return getDisplayString(); } /** * * {@inheritDoc} */ public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof ReusedProjectGuiObject)) { return false; } ReusedProjectGuiObject otherGui = (ReusedProjectGuiObject)obj; return getDisplayString().equals(otherGui.getDisplayString()); } /** * {@inheritDoc} */ public int hashCode() { return getDisplayString().hashCode(); } } /** * @author BREDEX GmbH * @created Dec 20, 2006 */ private final class UsedProjectsChooserComposite extends TreeElementChooserComposite implements IUsedListModifiedListener { /** * Constructor * @param innerComposite The inner composite * @param availableGuiObjects All available objects. * @param usedGuiObjects Objects to be placed in the used list. */ private UsedProjectsChooserComposite(Composite innerComposite, Set<IChooserCompositeGuiObject> availableGuiObjects, Set<IChooserCompositeGuiObject> usedGuiObjects) { super(innerComposite, Messages .ProjectPropertyPageReusableProjectsUpperLabel, availableGuiObjects, Messages .ProjectPropertyPageReusableProjectsBottomLabel, usedGuiObjects, 15, new Image[] { IconConstants.RIGHT_ARROW_IMAGE, IconConstants.DOUBLE_RIGHT_ARROW_IMAGE, IconConstants.LEFT_ARROW_IMAGE, IconConstants.DOUBLE_LEFT_ARROW_IMAGE, IconConstants.SWAP_ARROW_IMAGE }, new Image[] { IconConstants.RIGHT_ARROW_DIS_IMAGE, IconConstants.DOUBLE_RIGHT_ARROW_DIS_IMAGE, IconConstants.LEFT_ARROW_DIS_IMAGE, IconConstants.DOUBLE_LEFT_ARROW_DIS_IMAGE, IconConstants.SWAP_ARROW_DIS_IMAGE }, new String[] { Messages.ProjectPropertyPageReusableProjectsDownToolTip, Messages .ProjectPropertyPageReusableProjectsAllDownToolTip, Messages.ProjectPropertyPageReusableProjectsUpToolTip, Messages .ProjectPropertyPageReusableProjectsAllUpToolTip, Messages.ProjectPropertyPageReusableProjectsSwapToolTip }, ListElementChooserComposite.VERTICAL); addListModifiedListener(this); } /** * {@inheritDoc} */ protected String checkSelectionUsedToAvailable(String [] selection) { for (String reusedName : selection) { IReusedProjectPO reused = m_projectMap.get(reusedName); if (reused != null) { java.util.List<IExecTestCasePO> execTcNames = NodePM.getUsedTestCaseNames( GeneralStorage.getInstance().getProject(), reused); if (execTcNames != null && !execTcNames.isEmpty()) { return execTcNames.get(0).getName(); } } } return null; } /** * {@inheritDoc} */ public void usedListModified(String[] newListEntries) { m_listEntries = newListEntries; } } /** * {@inheritDoc} */ public void okPressed() throws PMException { if (m_listEntries != null) { updateProjects(m_listEntries); } } }