/*******************************************************************************
* 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);
}
}
}