/*
* Copyright (c) 2012 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* HUMBOLDT EU Integrated Project #030962
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.ui.service.schema.internal;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ICheckStateProvider;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.dialogs.PatternFilter;
import eu.esdihumboldt.hale.common.schema.SchemaSpaceID;
import eu.esdihumboldt.hale.common.schema.model.TypeDefinition;
import eu.esdihumboldt.hale.common.schema.model.TypeIndex;
import eu.esdihumboldt.hale.common.schema.model.constraint.type.MappingRelevantFlag;
import eu.esdihumboldt.hale.ui.common.definition.viewer.DefinitionComparator;
import eu.esdihumboldt.hale.ui.common.definition.viewer.DefinitionLabelProvider;
import eu.esdihumboldt.hale.ui.internal.HALEUIPlugin;
import eu.esdihumboldt.hale.ui.service.align.AlignmentService;
import eu.esdihumboldt.hale.ui.service.schema.util.NSTypeTreeContentProvider;
/**
* Wizard page to edit which types are mappable.
*
* @author Kai Schwierczek
*/
public class EditMappableTypesPage extends WizardPage {
private final TypeIndex typeIndex;
private final SchemaSpaceID spaceID;
private final Set<TypeDefinition> changedTypes = new HashSet<TypeDefinition>();
private CheckboxTreeViewer viewer;
private NSTypeTreeContentProvider contentProvider;
private ICheckStateProvider checkStateProvider;
private final ViewerFilter mappedTypeFilter = new ViewerFilter() {
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (element instanceof String)
return true;
TypeDefinition type = (TypeDefinition) element;
AlignmentService as = PlatformUI.getWorkbench().getService(AlignmentService.class);
if (as.getAlignment().getCells(type, spaceID).size() > 0)
return false;
return true;
}
};
private final DefinitionLabelProvider definitionLabels = new DefinitionLabelProvider(null) {
private final Image lockImg = HALEUIPlugin.getImageDescriptor("icons/lock.gif")
.createImage();
// @Override
// public String getText(Object element) {
// if (element instanceof Definition<?>) {
// // force displaying the local part as types are shown according to namespace
// return ((Definition<?>) element).getName().getLocalPart();
// }
// return super.getText(element);
// }
@Override
public Image getImage(Object element) {
if (element instanceof String)
return PlatformUI.getWorkbench().getSharedImages()
.getImage(ISharedImages.IMG_OBJ_FOLDER);
else if (!mappedTypeFilter.select(viewer, null, element))
return lockImg;
else
return super.getImage(element);
}
@Override
public void dispose() {
super.dispose();
lockImg.dispose();
}
};
/**
* Creates a new wizard page to edit which types in the given index are
* mappable.
*
* @param spaceID the schema space of which the types are
* @param typeIndex the type index to edit
*/
public EditMappableTypesPage(SchemaSpaceID spaceID, TypeIndex typeIndex) {
super("editMappableTypes", "Edit mappable types", null);
setDescription("Check which types should be mappable");
this.typeIndex = typeIndex;
this.spaceID = spaceID;
setPageComplete(true);
}
/**
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createControl(Composite parent) {
parent.setLayout(new GridLayout());
// create filtered tree
PatternFilter patternFilter = new PatternFilter();
patternFilter.setIncludeLeadingWildcard(true);
FilteredTree tree = new FilteredTree(parent,
SWT.BORDER | SWT.CHECK | SWT.H_SCROLL | SWT.V_SCROLL, patternFilter, true) {
@Override
protected TreeViewer doCreateTreeViewer(Composite parent, int style) {
return new CheckboxTreeViewer(parent, style);
}
};
// configure viewer
viewer = (CheckboxTreeViewer) tree.getViewer();
contentProvider = new NSTypeTreeContentProvider();
viewer.setContentProvider(contentProvider);
viewer.setComparator(new DefinitionComparator());
viewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
Object doubleClicked = selection.getFirstElement();
if (doubleClicked instanceof String)
viewer.setExpandedState(doubleClicked, !viewer.getExpandedState(doubleClicked));
else {
boolean newState = !checkStateProvider.isChecked(doubleClicked);
viewer.setChecked(doubleClicked, newState);
checkStateOfTypeChanged((TypeDefinition) doubleClicked, newState);
}
}
});
viewer.setLabelProvider(definitionLabels);
// because elements filtered by FilteredTree lose their checked state:
checkStateProvider = new ICheckStateProvider() {
@Override
public boolean isGrayed(Object element) {
if (element instanceof String) {
Object[] children = contentProvider.getChildren(element);
boolean containsChecked = false;
boolean containsUnchecked = false;
for (Object child : children) {
if (isChecked(child))
containsChecked = true;
else
containsUnchecked = true;
if (containsChecked && containsUnchecked)
return true;
}
}
return false;
}
@Override
public boolean isChecked(Object element) {
if (element instanceof String) {
for (Object child : contentProvider.getChildren(element))
if (isChecked(child))
return true;
return false;
}
return ((TypeDefinition) element).getConstraint(MappingRelevantFlag.class)
.isEnabled() != changedTypes.contains(element);
}
};
viewer.setCheckStateProvider(checkStateProvider);
viewer.addCheckStateListener(new ICheckStateListener() {
@Override
public void checkStateChanged(CheckStateChangedEvent event) {
if (event.getElement() instanceof String) {
// update children
viewer.setGrayed(event.getElement(), false);
for (Object child : contentProvider.getChildren(event.getElement())) {
// if (mappedTypeFilter.select(viewer, event.getElement(), child)) {
if (checkStateProvider.isChecked(child) != event.getChecked()) {
viewer.setChecked(child, event.getChecked());
checkStateOfTypeChanged((TypeDefinition) child, event.getChecked());
}
// }
}
viewer.setGrayed(event.getElement(),
checkStateProvider.isGrayed(event.getElement()));
// only two levels, no need to update any parents or
// children's children
}
else {
// if (mappedTypeFilter.select(viewer, null, event.getElement()))
checkStateOfTypeChanged((TypeDefinition) event.getElement(),
event.getChecked());
// else if (!event.getChecked())
// viewer.setChecked(event.getElement(), true);
}
}
});
// // filter types which are used in the current alignment
// viewer.addFilter(mappedTypeFilter);
// set input to all types in the given index
viewer.setInput(typeIndex.getTypes());
// expand all except XMLSchema
viewer.expandAll();
viewer.setExpandedState("http://www.w3.org/2001/XMLSchema", false);
// set control
setControl(viewer.getControl());
}
private void checkStateOfTypeChanged(TypeDefinition type, boolean checked) {
// if (mappedTypeFilter.select(viewer, null, type)) {
if (checked == type.getConstraint(MappingRelevantFlag.class).isEnabled())
changedTypes.remove(type);
else
changedTypes.add(type);
if (contentProvider != null && checkStateProvider != null) {
Object parent = contentProvider.getParent(type);
viewer.setGrayed(parent, checkStateProvider.isGrayed(parent));
viewer.setChecked(parent, checkStateProvider.isChecked(parent));
}
// }
// else if (!checked)
// viewer.setChecked(type, true);
}
/**
* Returns the set of types the user selected to change the mappable flag.
*
* @return the selected types
*/
public Set<TypeDefinition> getSelectedTypes() {
return changedTypes;
}
@Override
public void dispose() {
definitionLabels.dispose();
super.dispose();
}
}