/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kie.eclipse.wizard.project; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IRequirement; import org.eclipse.equinox.p2.metadata.expression.IMatchExpression; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTreeViewer; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.ICheckStateProvider; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.events.SelectionAdapter; 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.widgets.Composite; import org.eclipse.swt.widgets.Tree; public class IUTreeViewer extends CheckboxTreeViewer { private List<SelectionListener> selectionListeners = new ArrayList<SelectionListener>(); class IUTreeItem { final private IInstallableUnit iu; final private IUTreeViewer.IUTreeItem parent; final private IUTreeViewer.IUTreeContentProvider provider; private Collection<IUTreeViewer.IUTreeItem> children; private boolean checked; public IUTreeItem(IUTreeViewer.IUTreeContentProvider provider, IUTreeViewer.IUTreeItem parent, IInstallableUnit iu) { this.provider = provider; this.parent = parent; this.iu = iu; checked = false; } public boolean isChecked() { if (parent==null) { for (IUTreeViewer.IUTreeItem child : getChildren()) { if (child.isChecked()) return true; } return false; } return checked; } public boolean isGrayed() { if (parent==null) { int countChecked = 0; for (IUTreeViewer.IUTreeItem child : getChildren()) { if (child.isChecked()) ++countChecked; } return countChecked>0 && countChecked!=children.size(); } return false; } public void setChecked(boolean checked) { this.checked = checked; } public IUTreeViewer.IUTreeItem getParent() { return parent; } public Collection<IUTreeViewer.IUTreeItem> getChildren() { if (children==null) { children = new ArrayList<IUTreeViewer.IUTreeItem>(); if (parent==null) { for (IRequirement r : iu.getRequirements()) { for (IInstallableUnit riu : provider.getInstallableUnits()) { if (r.isMatch(riu)) { IMatchExpression<IInstallableUnit> me = r.getFilter(); if (me!=null) { if (me.isMatch(riu)) children.add(new IUTreeItem(provider, this, riu)); } else children.add(new IUTreeItem(provider, this, riu)); } } } } } return children; } public String getName() { if (parent==null) return iu.getProperty(IInstallableUnit.PROP_NAME); return iu.getProperty(IInstallableUnit.PROP_NAME) + " (v" + iu.getVersion() + ")"; } public void setSubtreeChecked(boolean checked) { this.checked = checked; if (parent==null) { for (IUTreeItem child : getChildren()) { child.checked = checked; } } } public int getSubtreeCheckedCount() { if (parent==null) { int count = 0; for (IUTreeItem child : getChildren()) { count += child.checked ? 1 : 0; } return count; } return checked ? 1 : 0; } } class IUTreeContentProvider implements ITreeContentProvider { Collection<IUTreeViewer.IUTreeItem> elements = new ArrayList<IUTreeViewer.IUTreeItem>(); Collection<IInstallableUnit> installableUnits = new ArrayList<IInstallableUnit>(); @Override public void dispose() { } public Collection<IInstallableUnit> getInstallableUnits() { return installableUnits; } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { elements.clear(); installableUnits.clear(); if (newInput instanceof IQueryResult) { for (Object o : (IQueryResult<?>)newInput) { if (o instanceof IInstallableUnit) { IInstallableUnit iu = (IInstallableUnit) o; installableUnits.add(iu); if (isGroup(iu)) { elements.add(new IUTreeItem(this, null, iu)); } } } } } @Override public Object[] getElements(Object inputElement) { return elements.toArray(new Object[elements.size()]); } @Override public Object[] getChildren(Object parentElement) { if (parentElement instanceof IUTreeViewer.IUTreeItem) { Collection<IUTreeViewer.IUTreeItem> children = ((IUTreeViewer.IUTreeItem)parentElement).getChildren(); return children.toArray(new Object[children.size()]); } return null; } @Override public Object getParent(Object element) { if (element instanceof IUTreeViewer.IUTreeItem) return ((IUTreeViewer.IUTreeItem)element).getParent(); return null; } @Override public boolean hasChildren(Object element) { if (element instanceof IUTreeViewer.IUTreeItem) return isGroup(((IUTreeViewer.IUTreeItem)element).iu); return false; } public boolean isGroup(IInstallableUnit iu) { String isGroup = iu==null ? null : iu.getProperty("org.eclipse.equinox.p2.type.group"); return Boolean.valueOf(isGroup); } } class IUTreeLabelProvider implements ILabelProvider { @Override public void addListener(ILabelProviderListener listener) { } @Override public void dispose() { } @Override public boolean isLabelProperty(Object element, String property) { return false; } @Override public void removeListener(ILabelProviderListener listener) { } @Override public Image getImage(Object element) { return null; } @Override public String getText(Object element) { if (element instanceof IUTreeViewer.IUTreeItem) return ((IUTreeViewer.IUTreeItem)element).getName(); return element.toString(); } } class IUTreeCheckStateListener implements ICheckStateListener { private IUTreeViewer treeViewer; public IUTreeCheckStateListener(IUTreeViewer treeViewer) { this.treeViewer = treeViewer; } @Override public void checkStateChanged(CheckStateChangedEvent event) { boolean checked = event.getChecked(); Object element = event.getElement(); if (element instanceof IUTreeItem) { IUTreeItem item = (IUTreeItem)element; updateDescendents(item, checked); updateAncestors(item.getParent(), checked); if (item.parent!=null) item = item.parent; for (Object e : treeViewer.getElements()) { if (e instanceof IUTreeItem) { if (e != item) updateDescendents((IUTreeItem)e, false); } } } } void updateDescendents(IUTreeItem item, boolean checked) { for (IUTreeItem child : item.getChildren()) { updateDescendents(child,checked); } item.setSubtreeChecked(checked); treeViewer.setSubtreeChecked(item, checked); treeViewer.setChecked(item, checked); treeViewer.setGrayed(item, false); } void updateAncestors(IUTreeItem item, boolean checked) { while (item!=null) { int checkedCount = item.getSubtreeCheckedCount(); int size = item.getChildren().size(); if (checkedCount==0) { treeViewer.setChecked(item, false); item.setChecked(false); checked = true; } else if (checkedCount==size) { treeViewer.setChecked(item, true); treeViewer.setGrayed(item, false); item.setChecked(true); } else { treeViewer.setGrayChecked(item, true); item.setChecked(true); } item = item.getParent(); } } }; public IUTreeViewer(Composite parent, int style) { super(parent, style); final Tree tree = getTree(); GridData gd = new GridData(GridData.FILL_BOTH); gd.minimumHeight = 3 * tree.getItemHeight(); tree.setLayoutData(gd); } public void initialize() { setContentProvider(new IUTreeContentProvider()); setCheckStateProvider(new ICheckStateProvider() { @Override public boolean isChecked(Object element) { if (element instanceof IUTreeViewer.IUTreeItem) return ((IUTreeViewer.IUTreeItem)element).isChecked(); return false; } @Override public boolean isGrayed(Object element) { if (element instanceof IUTreeViewer.IUTreeItem) return ((IUTreeViewer.IUTreeItem)element).isGrayed(); return false; } }); setLabelProvider(new IUTreeLabelProvider()); final Tree tree = getTree(); tree.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (tree.getSelectionCount()==1) { IUTreeItem item = (IUTreeItem) tree.getSelection()[0].getData(); e.data = item.iu; for (SelectionListener l : selectionListeners) { l.widgetSelected(e); } } } }); addCheckStateListener(new IUTreeCheckStateListener(this)); } /** * Returns only the installable units that are features, ignoring feature groups. * * @return */ public List<IInstallableUnit> getSelectedIUs(){ List<IInstallableUnit> result = new ArrayList<IInstallableUnit>(); for (Object o : getCheckedElements()) { if (o instanceof IUTreeItem) { IUTreeItem item = (IUTreeItem) o; if (item.parent!=null) result.add(item.iu); } } return result; } public Object[] getElements() { return ((IUTreeContentProvider)getContentProvider()).getElements(null); } public void addSelectionListener(SelectionListener listener) { if (!selectionListeners.contains(listener)) selectionListeners.add(listener); } public void removeSelectionListener(SelectionListener listener) { if (selectionListeners.contains(listener)) selectionListeners.remove(listener); } public void dispose() { if (getTree()!=null && !getTree().isDisposed()) { getTree().dispose(); } } }