/*******************************************************************************
* 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.widgets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jubula.client.ui.rcp.i18n.Messages;
import org.eclipse.jubula.client.ui.utils.ErrorHandlingUtil;
import org.eclipse.jubula.client.ui.utils.LayoutUtil;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.jubula.tools.internal.exception.Assert;
import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
/**
* Composite with a tree and a list. Content can be shifted between the tree
* and list.
*
* @author BREDEX GmbH
* @created Jun 13, 2007
*/
@SuppressWarnings("synthetic-access")
public class TreeElementChooserComposite extends Composite {
/**
* @author BREDEX GmbH
* @created Aug 17, 2007
*/
public interface IUsedListModifiedListener {
/**
* Handle list modified event.
* @param newListEntries All entries after the list has been modified
*/
public void usedListModified(String [] newListEntries);
}
/** horizontal style */
public static final int HORIZONTAL = 0;
/** vertical style */
public static final int VERTICAL = 1;
/** string that begins the display value */
private static final String DISPLAY_VALUE_START = " ["; //$NON-NLS-1$
/** string that ends the display value */
private static final String DISPLAY_VALUE_END = "]"; //$NON-NLS-1$
/***/
private static final String LABEL = "Label"; //$NON-NLS-1$
/** number of columns = 1 */
private static final int NUM_COLUMNS_1 = 1;
/** number of columns = 2 */
private static final int NUM_COLUMNS_2 = 2;
/** number of columns = 3 */
private static final int NUM_COLUMNS_3 = 3;
/** the list field for the available items */
private Tree m_availableTree;
/** the list field for the used items */
private List m_usedList;
/** the button to shift a selection from used list to available tree */
private Button m_selectionAvailableToUsedButton;
/** the button to shift all from available tree to used list */
private Button m_allAvailableToUsedButton;
/** the button to shift a selection from used list to available tree */
private Button m_selectionUsedToAvailableButton;
/** the button to shift all from available tree to used list */
private Button m_allUsedToAvailableButton;
/** the button to swap an item between the tree and list */
private Button m_swapButton;
/** disabled button content array */
private Object[] m_disabledButtonContents;
/** button content array */
private Object[] m_buttonContents;
/** Parents that have a child that is used */
private Set<String> m_usedParents = new HashSet<String>();
/** the StateController */
private final WidgetSelectionListener m_selectionListener =
new WidgetSelectionListener();
/** Mapping between display Strings and corresponding GUI objects */
private Map<String, IChooserCompositeGuiObject> m_listItemsToGuiObjects =
new HashMap<String, IChooserCompositeGuiObject>();
/** Mapping between TreeItems and corresponding GUI objects */
private Map<TreeItem, IChooserCompositeGuiObject> m_treeItemsToGuiObjects =
new HashMap<TreeItem, IChooserCompositeGuiObject>();
/** list listeners */
private Set<IUsedListModifiedListener> m_listeners =
new HashSet<IUsedListModifiedListener>();
/**
* Composite, with two listBoxes. You can shift the content between the two ListBoxes.
* @param parent The parent composite.
* @param availableLabel Label text of the available tree.
* @param availableObjects All available objects.
* @param usedLabel Label text of the used list.
* @param usedObjects Objects to be placed in the used list.
* @param lineNumber The number of lines of both ListBoxes.
* @param buttonTexts The texts of the 5 buttons (example: ">",">>","<","<<")
* @param buttonToolTips The texts of the toolTips of 5 buttons.
* @param style <p>ListElementChooserComposite.HORIZONTAL (ListBoxes are side by side) or</p>
* <p>ListElementChooserComposite.VERTICAL (ListBoxe one is below ListBox two)</p>
*/
public TreeElementChooserComposite(Composite parent, String availableLabel,
Set<IChooserCompositeGuiObject> availableObjects, String usedLabel,
Set<IChooserCompositeGuiObject> usedObjects, int lineNumber,
String[] buttonTexts, String[] buttonToolTips, int style) {
super(parent, SWT.NONE);
m_disabledButtonContents = buttonTexts;
m_buttonContents = buttonTexts;
createControl(availableLabel, availableObjects, usedLabel,
usedObjects, lineNumber, buttonToolTips, style);
}
/**
* @param parent The parent composite.
* @param availableLabel Label text of the available tree.
* @param availableObjects All available objects.
* @param usedLabel Label text of the used list.
* @param usedObjects Objects to be placed in the used list.
* @param lineNumber The number of lines of both ListBoxes.
* @param buttonImages The images of the 5 buttons.
* @param disabledButtonImages The disabled images of the 5 buttons.
* @param buttonToolTips The texts of the toolTips of 5 buttons.
* @param style <p>ListElementChooserComposite.HORIZONTAL (ListBoxes are side by side) or</p>
* <p>ListElementChooserComposite.VERTICAL (ListBoxe one is below ListBox two)</p>
*/
public TreeElementChooserComposite(Composite parent, String availableLabel,
Set<IChooserCompositeGuiObject> availableObjects, String usedLabel,
Set<IChooserCompositeGuiObject> usedObjects, int lineNumber,
Image[] buttonImages, Image[] disabledButtonImages,
String[] buttonToolTips, int style) {
super(parent, SWT.NONE);
m_disabledButtonContents = disabledButtonImages;
m_buttonContents = buttonImages;
createControl(availableLabel, availableObjects, usedLabel,
usedObjects, lineNumber, buttonToolTips, style);
}
/**
* Creates the ListElementChooserComposite.
* @param availableLabel Label text of the available tree.
* @param availableObjects All available objects.
* @param usedLabel Label text of the used list.
* @param usedObjects Objects to be placed in the used list.
* @param lineNumber The number of lines of both ListBoxes.
* @param buttonToolTips The texts of the toolTips of 5 buttons.
* @param style ListElementChooserComposite.HORIZONTAL or ListElementChooserComposite.VERTICAL
*/
private void createControl(String availableLabel,
Set<IChooserCompositeGuiObject> availableObjects, String usedLabel,
Set<IChooserCompositeGuiObject> usedObjects, int lineNumber,
String[] buttonToolTips, int style) {
if (style == HORIZONTAL) {
createHorizontalLayout(availableLabel, usedLabel,
lineNumber, buttonToolTips, style);
} else {
Composite composite = this;
GridLayout compositeLayout = new GridLayout();
compositeLayout.numColumns = NUM_COLUMNS_3;
compositeLayout.marginHeight = 0;
compositeLayout.marginWidth = 0;
composite.setLayout(compositeLayout);
GridData compositeData = new GridData();
compositeData.horizontalAlignment = GridData.FILL;
compositeData.grabExcessHorizontalSpace = true;
composite.setLayoutData(compositeData);
createVerticalLayout(composite, availableLabel, usedLabel,
lineNumber, buttonToolTips, style);
}
initFields(availableObjects, usedObjects);
addListener();
checkButtons();
}
/**
* Creates the layout with Vertical alignment.
* @param parent The parent composite.
* @param listOneLabel Label text of the first ListBox.
* @param listTwoLabel Label text of the second ListBox.
* @param lineNumber The number of lines of both ListBoxes.
* @param buttonToolTips The texts of the toolTips of 5 buttons.
* @param style ListElementChooserComposite.HORIZONTAL or ListElementChooserComposite.VERTICAL
*/
private void createVerticalLayout(Composite parent, String listOneLabel,
String listTwoLabel, int lineNumber, String[] buttonToolTips,
int style) {
Composite compositeLeft = createComposite(parent, NUM_COLUMNS_1,
GridData.FILL, true);
Composite compositeMiddle = createComposite(parent, NUM_COLUMNS_1,
GridData.FILL, false);
Composite compositeRight = createComposite(parent, NUM_COLUMNS_1,
GridData.FILL, true);
m_availableTree = createAvailableTree(compositeLeft, listOneLabel,
lineNumber);
m_availableTree.addSelectionListener(m_selectionListener);
createShiftButtons(style, compositeMiddle, buttonToolTips);
m_usedList = createListField(compositeRight, listTwoLabel,
lineNumber);
m_usedList.addSelectionListener(m_selectionListener);
}
/**
* Creates the layout with Horizontal alignment.
* @param listOneLabel Label text of the first ListBox.
* @param listTwoLabel Label text of the second ListBox.
* @param lineNumber The number of lines of both ListBoxes.
* @param buttonToolTips The texts of the toolTips of 5 buttons.
* @param style ListElementChooserComposite.HORIZONTAL or ListElementChooserComposite.VERTICAL
*/
private void createHorizontalLayout(String listOneLabel,
String listTwoLabel, int lineNumber, String[] buttonToolTips,
int style) {
Composite composite = this;
GridLayout compositeLayout = new GridLayout();
compositeLayout.numColumns = NUM_COLUMNS_2;
compositeLayout.marginHeight = 0;
compositeLayout.marginWidth = 0;
composite.setLayout(compositeLayout);
GridData compositeData = new GridData(GridData.FILL_BOTH);
compositeData.grabExcessHorizontalSpace = true;
compositeData.grabExcessVerticalSpace = false;
compositeData.verticalAlignment = GridData.BEGINNING;
composite.setLayoutData(compositeData);
m_availableTree = createAvailableTree(composite, listOneLabel,
lineNumber);
m_availableTree.addSelectionListener(m_selectionListener);
createShiftButtons(style, composite, buttonToolTips);
m_usedList = createListField(composite, listTwoLabel,
lineNumber);
m_usedList.addSelectionListener(m_selectionListener);
}
/**
* Inits all swt field in this page.
* @param availableObjects All available objects.
* @param usedObjects Objects to be placed in the used list.
*/
protected void initFields(Set<IChooserCompositeGuiObject> availableObjects,
Set<IChooserCompositeGuiObject> usedObjects) {
Map<String, TreeItem> parentsThatExist =
new HashMap<String, TreeItem>();
for (IChooserCompositeGuiObject guiObject : availableObjects) {
String parent = guiObject.getParent();
if (!parentsThatExist.containsKey(parent)) {
TreeItem parentItem = new TreeItem(m_availableTree, SWT.NONE);
parentItem.setText(parent);
parentsThatExist.put(parent, parentItem);
}
boolean isValueInUsedList =
usedObjects.contains(guiObject);
if (!isValueInUsedList) {
TreeItem valueItem =
new TreeItem(parentsThatExist.get(parent), SWT.NONE);
valueItem.setText(guiObject.getTitle());
m_treeItemsToGuiObjects.put(valueItem, guiObject);
}
}
sortTreeItems();
for (IChooserCompositeGuiObject item : usedObjects) {
m_usedList.add(item.getDisplayString());
m_listItemsToGuiObjects.put(item.getDisplayString(), item);
m_usedParents.add(item.getParent());
}
sortListItems();
}
/**
* Sorts all items in the used list alphabetically.
*/
private void sortListItems() {
String [] items = m_usedList.getItems();
Arrays.sort(items);
m_usedList.removeAll();
for (String listItem : items) {
m_usedList.add(listItem);
}
}
/**
* Creates the 5 arrow buttons
* @param style ListElementChooserComposite.HORIZONTAL or ListElementChooserComposite.VERTICAL
* @param parent The parent composite.
* @param buttonToolTips The texts of the toolTips of 5 buttons.
*/
private void createShiftButtons(int style, Composite parent,
String[] buttonToolTips) {
if (style == HORIZONTAL) {
createComposite(parent, NUM_COLUMNS_1, GridData.BEGINNING, false);
Composite composite = createComposite(parent, NUM_COLUMNS_2,
GridData.FILL, true);
Composite leftComposite = createComposite(composite, NUM_COLUMNS_2,
GridData.FILL, true);
Composite rightComposite = createComposite(composite, NUM_COLUMNS_2,
GridData.FILL, true);
m_selectionAvailableToUsedButton =
new Button(leftComposite, SWT.PUSH);
m_allAvailableToUsedButton = new Button(leftComposite, SWT.PUSH);
m_selectionUsedToAvailableButton =
new Button(rightComposite, SWT.PUSH);
m_allUsedToAvailableButton = new Button(rightComposite, SWT.PUSH);
m_swapButton = new Button(rightComposite, SWT.PUSH);
} else {
createLabel(parent, StringConstants.EMPTY);
m_selectionAvailableToUsedButton = new Button(parent, SWT.PUSH);
m_allAvailableToUsedButton = new Button(parent, SWT.PUSH);
createLabel(parent, StringConstants.EMPTY);
m_selectionUsedToAvailableButton = new Button(parent, SWT.PUSH);
m_allUsedToAvailableButton = new Button(parent, SWT.PUSH);
m_swapButton = new Button(parent, SWT.PUSH);
}
GridData selectionOneToTwoGridData = new GridData();
selectionOneToTwoGridData.horizontalAlignment = GridData.FILL;
if (style == HORIZONTAL) {
selectionOneToTwoGridData.horizontalAlignment = GridData.END;
}
selectionOneToTwoGridData.grabExcessHorizontalSpace = true;
m_selectionAvailableToUsedButton.setLayoutData(
selectionOneToTwoGridData);
m_selectionAvailableToUsedButton.setImage(
(Image)m_disabledButtonContents[0]);
m_selectionAvailableToUsedButton.setEnabled(false);
GridData allOneToTwoGridData = new GridData();
allOneToTwoGridData.horizontalAlignment = GridData.FILL;
if (style == HORIZONTAL) {
allOneToTwoGridData.horizontalAlignment = GridData.BEGINNING;
}
allOneToTwoGridData.grabExcessHorizontalSpace = true;
m_allAvailableToUsedButton.setLayoutData(allOneToTwoGridData);
m_allAvailableToUsedButton.setImage((Image)m_disabledButtonContents[1]);
m_allAvailableToUsedButton.setEnabled(false);
GridData selectionTwoToOneGridData = new GridData();
selectionTwoToOneGridData.horizontalAlignment = GridData.FILL;
if (style == HORIZONTAL) {
selectionTwoToOneGridData.horizontalAlignment = GridData.END;
}
selectionTwoToOneGridData.grabExcessHorizontalSpace = true;
m_selectionUsedToAvailableButton.setLayoutData(
selectionTwoToOneGridData);
m_selectionUsedToAvailableButton.setImage(
(Image)m_disabledButtonContents[2]);
m_selectionUsedToAvailableButton.setEnabled(false);
GridData allTwoToOneGridData = new GridData();
allTwoToOneGridData.horizontalAlignment = GridData.FILL;
if (style == HORIZONTAL) {
allTwoToOneGridData.horizontalAlignment = GridData.BEGINNING;
}
allTwoToOneGridData.grabExcessHorizontalSpace = true;
m_allUsedToAvailableButton.setLayoutData(allTwoToOneGridData);
m_allUsedToAvailableButton.setImage((Image)m_disabledButtonContents[3]);
m_allUsedToAvailableButton.setEnabled(false);
setButtonRepresentations();
setTooltips(buttonToolTips);
}
/**
* Sets the text or image data for the buttons.
*/
private void setButtonRepresentations() {
if (m_buttonContents instanceof Image[]) {
m_selectionAvailableToUsedButton.setImage(
(Image)m_buttonContents[0]);
m_allAvailableToUsedButton.setImage((Image)m_buttonContents[1]);
m_selectionUsedToAvailableButton.setImage(
(Image)m_buttonContents[2]);
m_allUsedToAvailableButton.setImage((Image)m_buttonContents[3]);
} else {
m_selectionAvailableToUsedButton.setText(
(String)m_buttonContents[0]);
m_allAvailableToUsedButton.setText((String)m_buttonContents[1]);
m_selectionUsedToAvailableButton.setText(
(String)m_buttonContents[2]);
m_allUsedToAvailableButton.setText((String)m_buttonContents[3]);
}
}
/**
* Sets the tooltips for the buttons.
* @param buttonToolTips The texts of the toolTips of 5 buttons.
*/
private void setTooltips(String[] buttonToolTips) {
m_selectionAvailableToUsedButton.setToolTipText(buttonToolTips[0]);
m_allAvailableToUsedButton.setToolTipText(buttonToolTips[1]);
m_selectionUsedToAvailableButton.setToolTipText(buttonToolTips[2]);
m_allUsedToAvailableButton.setToolTipText(buttonToolTips[3]);
m_swapButton.setToolTipText(buttonToolTips[4]);
}
/**
* Sorts all items in the available tree alphabetically.
*/
private void sortTreeItems() {
SortedMap<String, java.util.List<String>> sortedTree =
new TreeMap<String, java.util.List<String>>();
Set<IChooserCompositeGuiObject> tempSet =
new HashSet<IChooserCompositeGuiObject>();
boolean [] isItemExpanded =
new boolean [m_availableTree.getItemCount()];
for (int i = 0; i < m_availableTree.getItemCount(); i++) {
TreeItem parentItem = m_availableTree.getItem(i);
isItemExpanded[i] = parentItem.getExpanded();
java.util.List<String> childNames = new ArrayList<String>();
for (TreeItem childItem : parentItem.getItems()) {
childNames.add(childItem.getText());
IChooserCompositeGuiObject guiObj =
m_treeItemsToGuiObjects.get(childItem);
tempSet.add(guiObj);
}
Collections.sort(childNames);
sortedTree.put(parentItem.getText(), childNames);
}
m_availableTree.removeAll();
m_treeItemsToGuiObjects.clear();
for (String parentName : sortedTree.keySet()) {
TreeItem parentItem = new TreeItem(m_availableTree, SWT.NONE);
parentItem.setText(parentName);
for (String childName : sortedTree.get(parentName)) {
TreeItem childItem = new TreeItem(parentItem, SWT.NONE);
childItem.setText(childName);
for (IChooserCompositeGuiObject obj : tempSet) {
if (obj.getParent().equals(parentName)
&& obj.getTitle().equals(childName)) {
m_treeItemsToGuiObjects.put(childItem, obj);
break;
}
}
}
}
for (int i = 0; i < m_availableTree.getItemCount(); i++) {
if (isItemExpanded[i]) {
TreeItem item = m_availableTree.getItem(i);
Event expandEvent = new Event();
expandEvent.time = (int)System.currentTimeMillis();
expandEvent.type = SWT.Expand;
expandEvent.widget = m_availableTree;
expandEvent.item = item;
m_availableTree.notifyListeners(SWT.Expand, expandEvent);
item.setExpanded(true);
m_availableTree.update();
}
}
}
/**
* Use the GUI object represented by the given item.
* @param item the item that represents the object to use.
*/
private void useObject(TreeItem item) {
IChooserCompositeGuiObject guiObj = m_treeItemsToGuiObjects.get(item);
String displayString = guiObj.getDisplayString();
m_listItemsToGuiObjects.put(displayString, guiObj);
m_usedList.add(displayString);
item.dispose();
m_usedParents.add(guiObj.getParent());
sortListItems();
}
/**
* Make the given object available.
* @param obj the object to make available.
* @param swapping Flag to indicate that a 'swap' is currently in progress.
*/
private void makeObjectAvailable(IChooserCompositeGuiObject obj,
boolean swapping) {
m_listItemsToGuiObjects.remove(obj.getDisplayString());
if (!swapping) {
m_usedParents.remove(obj.getParent());
}
m_usedList.remove(obj.getDisplayString());
if (obj.getParent() != null) {
TreeItem parentItem = null;
String parentText = obj.getParent();
for (TreeItem parent : m_availableTree.getItems()) {
if (parent.getText().equals(parentText)) {
parentItem = parent;
break;
}
}
if (parentItem != null) {
TreeItem item = new TreeItem(parentItem, SWT.NONE);
item.setText(obj.getTitle());
m_treeItemsToGuiObjects.put(item, obj);
sortTreeItems();
}
}
}
/**
* Informs all listeners that the list has been modified.
*/
private void fireListModified() {
for (IUsedListModifiedListener listener : m_listeners) {
listener.usedListModified(m_usedList.getItems());
}
}
/**
* Creates a label for this composite.
* @param text The label text to set.
* @param parent The composite.
* @return a new label
*/
private Label createLabel(Composite parent, String text) {
Label label = new Label(parent, SWT.NONE);
label.setText(text);
GridData labelGrid = new GridData(GridData.BEGINNING, GridData.CENTER,
false, false, 1, 1);
label.setLayoutData(labelGrid);
return label;
}
/**
* Creates a new composite.
* @param parent The parent composite.
* @param numColumns the number of columns for this composite.
* @param alignment The horizontalAlignment.
* @param horizontalSpace The horizontalSpace.
* @return The new composite.
*/
private Composite createComposite(Composite parent, int numColumns,
int alignment, boolean horizontalSpace) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayout compositeLayout = new GridLayout();
compositeLayout.numColumns = numColumns;
compositeLayout.marginHeight = 0;
compositeLayout.marginWidth = 0;
composite.setLayout(compositeLayout);
GridData compositeData = new GridData();
compositeData.horizontalAlignment = alignment;
compositeData.grabExcessHorizontalSpace = horizontalSpace;
composite.setLayoutData(compositeData);
return composite;
}
/**
* Creates a new multiline textfield
* @param composite The parent composite.
* @param labelText The text for the label.
* @param lines The quantity of lines of this list.
* @return The new multiline textfield.
*/
private List createListField(Composite composite,
String labelText, int lines) {
Composite leftComposite = createComposite(composite, NUM_COLUMNS_2,
GridData.BEGINNING, false);
Composite rightComposite = createComposite(composite, NUM_COLUMNS_1,
GridData.FILL, true);
Label label = createLabel(leftComposite, labelText);
List listField =
new List(rightComposite, LayoutUtil.MULTI_TEXT_STYLE);
listField.setData(LABEL, label);
GridData listGridData = new GridData();
listGridData.horizontalAlignment = GridData.FILL;
listGridData.horizontalSpan = NUM_COLUMNS_1;
listGridData.grabExcessHorizontalSpace = true;
listGridData.heightHint = Dialog.convertHeightInCharsToPixels(
LayoutUtil.getFontMetrics(listField), lines);
listField.setLayoutData(listGridData);
return listField;
}
/**
* Creates a new tree
* @param composite The parent composite.
* @param labelText The text for the label.
* @param lines The quantity of lines of this list.
* @return The new tree.
*/
private Tree createAvailableTree(Composite composite,
String labelText, int lines) {
Composite leftComposite = createComposite(composite, NUM_COLUMNS_2,
GridData.BEGINNING, false);
Composite rightComposite = createComposite(composite, NUM_COLUMNS_1,
GridData.FILL, true);
Label label = createLabel(leftComposite, labelText);
Tree tree =
new Tree(rightComposite, LayoutUtil.MULTI_TEXT_STYLE);
tree.setData(LABEL, label);
GridData listGridData = new GridData();
listGridData.horizontalAlignment = GridData.FILL;
listGridData.horizontalSpan = NUM_COLUMNS_1;
listGridData.grabExcessHorizontalSpace = true;
listGridData.heightHint = Dialog.convertHeightInCharsToPixels(
LayoutUtil.getFontMetrics(tree), lines);
tree.setLayoutData(listGridData);
return tree;
}
/**
* @param key The key string
* @param value The value string
* @return a <code>String</code> that represents the combination of
* <code>key</code> and <code>value</code>
*/
protected String getDisplayValue(String key, String value) {
String displayValue = key + DISPLAY_VALUE_START + value
+ DISPLAY_VALUE_END;
return displayValue;
}
/**
* Handles the selectionEvent of the selectionOneToTwoButton.
*/
protected void handleSelectionAvailableToUsedButtonEvent() {
if (m_selectionAvailableToUsedButton.getEnabled()) {
for (TreeItem item : m_availableTree.getSelection()) {
useObject(item);
}
sortListItems();
fireListModified();
checkButtons();
}
}
/**
* Handles the selectionEvent of the selectionTwoToOneButton.
*/
protected void handleSelectionUsedToAvailableButtonEvent() {
if (m_selectionUsedToAvailableButton.getEnabled()) {
String [] usedSelection = m_usedList.getSelection();
if (checkSelectionUsedToAvailable(usedSelection) == null) {
for (String sel : m_usedList.getSelection()) {
IChooserCompositeGuiObject guiObj =
m_listItemsToGuiObjects.get(sel);
makeObjectAvailable(guiObj, false);
}
checkButtons();
fireListModified();
} else {
Dialog dialog = ErrorHandlingUtil.createMessageDialog(
MessageIDs.I_COULD_NOT_REMOVE_REUSED_PROJECTS);
dialog.getReturnCode();
}
}
}
/**
* @param selection The array of selected elements.
* @return An error message <code>String</code> if not all elements can be removed.
* Otherwise <code>null</code>.
*/
protected String checkSelectionUsedToAvailable(String [] selection) {
return null;
}
/**
* Handles the selectionEvent of the allOneToTwoButton.
*/
protected void handleAllAvailableToUsedButtonEvent() {
for (TreeItem keyItem : m_availableTree.getItems()) {
// Should only be enabled if each key item has one and only one child item
useObject(keyItem.getItem(0));
}
String[] selection = m_usedList.getItems();
Arrays.sort(selection);
m_usedList.removeAll();
m_usedList.setItems(selection);
fireListModified();
checkButtons();
}
/**
* Handles the selectionEvent of the allTwoToOneButton.
*/
protected void handleAllUsedToAvailableButtonEvent() {
String [] usedItems = m_usedList.getItems();
String errorMsg = checkSelectionUsedToAvailable(usedItems);
if (errorMsg == null) {
for (String listItem : usedItems) {
makeObjectAvailable(
m_listItemsToGuiObjects.get(listItem), false);
}
m_usedList.removeAll();
fireListModified();
checkButtons();
} else {
Dialog dialog = ErrorHandlingUtil.createMessageDialog(
MessageIDs.I_COULD_NOT_REMOVE_REUSED_PROJECTS);
dialog.getReturnCode();
}
}
/**
* Handles the selectionEvent of the allTwoToOneButton.
*/
protected void handleSwapButtonEvent() {
String usedSelection = m_usedList.getSelection()[0];
TreeItem availableSelection = m_availableTree.getSelection()[0];
useObject(availableSelection);
makeObjectAvailable(m_listItemsToGuiObjects.get(usedSelection), true);
fireListModified();
checkButtons();
}
/**
* Dis-/Enables the UP-/Down-/SwapButtons.
*/
public void checkButtons() {
// allOneToTwo: no parent item has more than one element and at least one parent has one element
boolean parentHasMoreThanOneElement = false;
boolean parentsHaveNoElements = true;
boolean enableAllOneToTwo = true;
// allTwoToOne: list contains at least one element
boolean listContainsAnElement, enableAllTwoToOne = false;
// selectionOneToTwo: some selection and no selection is a parent item and none of selections' parents are already somehow in list
// and no selected items share a parent
boolean someSelectionOne, selectionContainsParentItem = false;
boolean partOfSelectionIsInList = false;
boolean availableSelectionShareParent = false;
boolean enableSelectionOneToTwo = true;
// selectionTwoToOne: some selection
boolean someSelectionTwo = false;
boolean enableSelectionTwoToOne = true;
// swap: one element selected for each and both selections share a common parent
boolean oneElementSelectedOne, oneElementSelectedTwo = false;
boolean elementsShareCommonParent = false;
boolean enableSwap = true;
parentHasMoreThanOneElement = hasMultipleChildren();
enableAllOneToTwo = !parentHasMoreThanOneElement
&& !parentsHaveNoElements;
listContainsAnElement = m_usedList.getItemCount() > 0;
enableAllTwoToOne = listContainsAnElement;
TreeItem[] treeSelection = m_availableTree.getSelection();
someSelectionOne = treeSelection.length > 0;
Set<String> parentsOfSelection = new HashSet<String>();
for (TreeItem selItem : treeSelection) {
if (selItem.getParentItem() == null) {
selectionContainsParentItem = true;
break;
}
String parent = m_treeItemsToGuiObjects.get(selItem).getParent();
if (!parentsOfSelection.contains(parent)) {
parentsOfSelection.add(parent);
} else {
availableSelectionShareParent = true;
break;
}
if (isChildItemUsed(selItem.getParentItem().getText())) {
partOfSelectionIsInList = true;
break;
}
}
enableSelectionOneToTwo = someSelectionOne
&& !selectionContainsParentItem
&& !partOfSelectionIsInList
&& !availableSelectionShareParent;
someSelectionTwo = m_usedList.getSelectionCount() > 0;
enableSelectionTwoToOne = someSelectionTwo;
oneElementSelectedOne = m_availableTree.getSelectionCount() == 1;
oneElementSelectedTwo = m_usedList.getSelectionCount() == 1;
if (oneElementSelectedOne && oneElementSelectedTwo) {
elementsShareCommonParent =
isCommonParentForElements(selectionContainsParentItem);
}
enableSwap = elementsShareCommonParent;
enableSelectionOneToTwoButton(enableSelectionOneToTwo);
enableSelectionTwoToOneButton(enableSelectionTwoToOne);
enableAllOneToTwoButton(enableAllOneToTwo);
enableAllTwoToOneButton(enableAllTwoToOne);
enableSwapButton(enableSwap);
}
/**
* @param selectionContainsParentItem does the current selection contain a
* parent item
* @return <code>true</code> if the selected elements have the same parent.
* Otherwise, <code>false</code>.
*/
private boolean isCommonParentForElements(
boolean selectionContainsParentItem) {
boolean elementsShareCommonParent;
IChooserCompositeGuiObject availableObj =
m_treeItemsToGuiObjects.get(m_availableTree.getSelection()[0]);
IChooserCompositeGuiObject usedObj =
m_listItemsToGuiObjects.get(m_usedList.getSelection()[0]);
elementsShareCommonParent = !selectionContainsParentItem
&& availableObj != null && usedObj != null
&& availableObj.getParent().equals(usedObj.getParent());
return elementsShareCommonParent;
}
/**
* @return <code>true</code> if any GUI objects share a parent. Otherwise,
* <code>false</code>.
*/
private boolean hasMultipleChildren() {
Set<IChooserCompositeGuiObject> guiObjects =
new HashSet<IChooserCompositeGuiObject>(
m_treeItemsToGuiObjects.values());
guiObjects.addAll(m_listItemsToGuiObjects.values());
Set<String> parentSet = new HashSet<String>();
for (IChooserCompositeGuiObject obj : guiObjects) {
String parentString = obj.getParent();
if (!parentSet.contains(parentString)) {
parentSet.add(parentString);
} else {
return true;
}
}
return false;
}
/**
* @param text the parent text.
* @return <code>true</code> if a used GUI object has the given text as
* parent. Otherwise, <code>false</code>.
*/
private boolean isChildItemUsed(String text) {
return m_usedParents.contains(text);
}
/**
*
* @param enable <code>true</code> if the button should be enabled. <code>false</code>
* if the button should be disabled.
*/
private void enableSelectionOneToTwoButton(boolean enable) {
if (enable) {
m_selectionAvailableToUsedButton.setImage(
(Image)m_buttonContents[0]);
m_selectionAvailableToUsedButton.setEnabled(true);
} else {
m_selectionAvailableToUsedButton.setImage(
(Image)m_disabledButtonContents[0]);
m_selectionAvailableToUsedButton.setEnabled(false);
}
}
/**
*
* @param enable <code>true</code> if the button should be enabled. <code>false</code>
* if the button should be disabled.
*/
private void enableSelectionTwoToOneButton(boolean enable) {
if (enable) {
m_selectionUsedToAvailableButton.setImage(
(Image)m_buttonContents[2]);
m_selectionUsedToAvailableButton.setEnabled(true);
} else {
m_selectionUsedToAvailableButton.setImage(
(Image)m_disabledButtonContents[2]);
m_selectionUsedToAvailableButton.setEnabled(false);
}
}
/**
*
* @param enable <code>true</code> if the button should be enabled. <code>false</code>
* if the button should be disabled.
*/
private void enableAllOneToTwoButton(boolean enable) {
if (enable) {
m_allAvailableToUsedButton.setImage(
(Image)m_buttonContents[1]);
m_allAvailableToUsedButton.setEnabled(true);
} else {
m_allAvailableToUsedButton.setImage(
(Image)m_disabledButtonContents[1]);
m_allAvailableToUsedButton.setEnabled(false);
}
}
/**
*
* @param enable <code>true</code> if the button should be enabled. <code>false</code>
* if the button should be disabled.
*/
private void enableAllTwoToOneButton(boolean enable) {
if (enable) {
m_allUsedToAvailableButton.setImage(
(Image)m_buttonContents[3]);
m_allUsedToAvailableButton.setEnabled(true);
} else {
m_allUsedToAvailableButton.setImage(
(Image)m_disabledButtonContents[3]);
m_allUsedToAvailableButton.setEnabled(false);
}
}
/**
*
* @param enable <code>true</code> if the button should be enabled. <code>false</code>
* if the button should be disabled.
*/
private void enableSwapButton(boolean enable) {
if (enable) {
m_swapButton.setImage(
(Image)m_buttonContents[4]);
m_swapButton.setEnabled(true);
} else {
m_swapButton.setImage(
(Image)m_disabledButtonContents[4]);
m_swapButton.setEnabled(false);
}
}
/**
* Disposes the SWT widgets.
*/
public void dispose() {
removeListener();
super.dispose();
}
/**
*
* @param listener The listener to add.
*/
public void addListModifiedListener(IUsedListModifiedListener listener) {
m_listeners.add(listener);
}
/**
*
* @param listener The listener to remove.
*/
public void removeListModifiedListener(IUsedListModifiedListener listener) {
m_listeners.remove(listener);
}
/**
* Adds necessary listeners.
*/
private void addListener() {
m_selectionUsedToAvailableButton.addSelectionListener(
m_selectionListener);
m_selectionAvailableToUsedButton.addSelectionListener(
m_selectionListener);
m_allAvailableToUsedButton.addSelectionListener(m_selectionListener);
m_allUsedToAvailableButton.addSelectionListener(m_selectionListener);
m_swapButton.addSelectionListener(m_selectionListener);
}
/**
* Removes all listeners.
*/
private void removeListener() {
m_selectionAvailableToUsedButton.removeSelectionListener(
m_selectionListener);
m_selectionUsedToAvailableButton.removeSelectionListener(
m_selectionListener);
m_allAvailableToUsedButton.removeSelectionListener(m_selectionListener);
m_allUsedToAvailableButton.removeSelectionListener(m_selectionListener);
m_availableTree.removeSelectionListener(m_selectionListener);
m_usedList.removeSelectionListener(m_selectionListener);
}
/**
* The object from the model that can be chosen/unchosen.
*
* @author BREDEX GmbH
* @created Aug 16, 2007
*/
public interface IChooserCompositeGuiObject {
/**
* Indicates the name of the tree item that will be the receiver's
* parent when it is available.
*
* @return the name of the parent when the receiver is available.
*/
public String getParent();
/**
* Indicates the displayed title of the object when it is available.
*
* @return the title that represents the receiver when it is available.
*/
public String getTitle();
/**
* Indicates the displayed title of the object when it is used.
*
* @return the title that represents the receiver when it is used.
*/
public String getDisplayString();
/**
* @return the model object represented by the receiver.
*/
public Object getModelObject();
}
/**
* This private inner class contains a new SelectionListener.
* @author BREDEX GmbH
* @created 10.02.2005
*/
@SuppressWarnings("synthetic-access")
private class WidgetSelectionListener implements SelectionListener {
/**
* {@inheritDoc}
*/
public void widgetSelected(SelectionEvent e) {
Object o = e.getSource();
if (o.equals(m_selectionAvailableToUsedButton)) {
handleSelectionAvailableToUsedButtonEvent();
return;
} else if (o.equals(m_selectionUsedToAvailableButton)) {
handleSelectionUsedToAvailableButtonEvent();
return;
} else if (o.equals(m_allAvailableToUsedButton)) {
handleAllAvailableToUsedButtonEvent();
return;
} else if (o.equals(m_allUsedToAvailableButton)) {
handleAllUsedToAvailableButtonEvent();
return;
} else if (o.equals(m_swapButton)) {
handleSwapButtonEvent();
return;
} else if (o.equals(m_availableTree)) {
checkButtons();
return;
} else if (o.equals(m_usedList)) {
checkButtons();
return;
}
Assert.notReached(Messages.EventActivatedByUnknownWidget
+ StringConstants.DOT);
}
/**
* {@inheritDoc}
*/
public void widgetDefaultSelected(SelectionEvent e) {
Object o = e.getSource();
if (o.equals(m_availableTree)) {
handleSelectionAvailableToUsedButtonEvent();
return;
} else if (o.equals(m_usedList)) {
handleSelectionUsedToAvailableButtonEvent();
return;
}
Assert.notReached(Messages.EventActivatedByUnknownWidget
+ StringConstants.DOT);
}
}
/**
* @return Returns the allOneToTwoButton.
*/
public Button getAllAvailableToUsedButton() {
return m_allAvailableToUsedButton;
}
/**
* @return Returns the allTwoToOneButton.
*/
public Button getAllUsedToAvailableButton() {
return m_allUsedToAvailableButton;
}
/**
* @return Returns the listOne.
*/
public Tree getAvailableTree() {
return m_availableTree;
}
/**
* @return Returns the listTwo.
*/
public List getUsedList() {
return m_usedList;
}
/**
* @return Returns the selectionOneToTwoButton.
*/
public Button getSelectionAvailableToUsedButton() {
return m_selectionAvailableToUsedButton;
}
/**
* @return Returns the selectionTwoToOneButton.
*/
public Button getSelectionUsedToAvailableButton() {
return m_selectionUsedToAvailableButton;
}
/**
* @return Returns the label of ListBox one.
*/
public Label getListOneLabel() {
return (Label)m_availableTree.getData(LABEL);
}
/**
* @return Returns the label of ListBox two.
*/
public Label getListTwoLabel() {
return (Label)m_usedList.getData(LABEL);
}
}