/****************************************************************************
* Copyright (c) 2006 Jeremy Dowdall
* 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:
* Jeremy Dowdall <jeremyd@aspencloud.com> - initial API and implementation
*****************************************************************************/
package org.eclipse.swt.nebula.nebface.ctabletreeviewer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.eclipse.jface.util.Assert;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ITreePathContentProvider;
import org.eclipse.jface.viewers.ITreeViewerListener;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.SWT;
import org.eclipse.swt.nebula.nebface.ctabletreeviewer.ccontainerviewer.CContainerViewer;
import org.eclipse.swt.nebula.nebface.ctabletreeviewer.ccontainerviewer.ICContainerLabelProvider;
import org.eclipse.swt.nebula.widgets.ctabletree.CContainerCell;
import org.eclipse.swt.nebula.widgets.ctabletree.CContainerItem;
import org.eclipse.swt.nebula.widgets.ctabletree.CTableTree;
import org.eclipse.swt.nebula.widgets.ctabletree.CTableTreeCell;
import org.eclipse.swt.nebula.widgets.ctabletree.CTableTreeItem;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Widget;
/**
* <p>
* NOTE: THIS VIEWER AND ITS API ARE STILL UNDER DEVELOPMENT. THIS IS A PRE-RELEASE ALPHA
* VERSION. USERS SHOULD EXPECT API CHANGES IN FUTURE VERSIONS.
* </p>
*/
public class CTableTreeViewer extends CContainerViewer {
private int treeColumn = -1;
/**
* Creates a CTableTree viewer on a newly-created CTableTree control under the given parent.
* The CTableTree control is created using the SWT style bits <code>MULTI, H_SCROLL, V_SCROLL,</code> and <code>BORDER</code>.
* The viewer has no input, no content provider, a default label provider,
* no sorter, and no filters.
*
* @param parent the parent control
*/
public CTableTreeViewer(Composite parent) {
super(new CTableTree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER));
}
/**
* Creates a CTableTree viewer on a newly-created CTableTree control under the given parent.
* The CTableTree control is created using the given SWT style bits.
* The viewer has no input, no content provider, a default label provider,
* no sorter, and no filters.
*
* @param parent the parent control
* @param style the SWT style bits
*/
public CTableTreeViewer(Composite parent, int style) {
super(new CTableTree(parent, style));
}
/**
* Creates a CTableTree viewer on the given CTableTree control.
* The viewer has no input, no content provider, a default label provider,
* no sorter, and no filters.
*
* @param list the list control
*/
public CTableTreeViewer(CTableTree cTableTree) {
super(cTableTree);
}
public void add(Object parentElement, Object childElement) {
add(parentElement, new Object[] { childElement });
}
public void add(Object parentElement, Object[] childElements) {
assertElementsNotNull(childElements);
Object[] filtered = filter(childElements);
for (int i = 0; i < filtered.length; i++) {
Object element = filtered[i];
int index = indexForElement(element);
createItem(parentElement, element, index);
}
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public void addTreeListener(ITreeViewerListener listener) {
// TODO Auto-generated method stub
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public void clear(int index) {
// TODO Auto-generated method stub
}
public void collapseAll() {
CContainerItem[] items = container.getItems();
for(int i = 0; i < items.length; i++) {
if(((CTableTreeItem) items[i]).getExpanded()) {
((CTableTreeItem) items[i]).setExpanded(false);
}
}
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public void collapseToLevel(Object element, int level) {
// TODO Auto-generated method stub
}
/**
* @param element
* @param index
*/
protected void createItem(Object element, int index) {
Object parent = null;
IContentProvider cp = getContentProvider();
if(cp != null && cp instanceof ITreeContentProvider) {
parent = ((ITreeContentProvider) cp).getParent(element);
}
else if(cp != null && cp instanceof ITreePathContentProvider) {
TreePath[] paths = ((ITreePathContentProvider) cp).getParents(element);
if(paths.length > 0) {
parent = paths[0].getLastSegment();
}
}
createItem(parent, element, index);
}
/**
* @param element
* @param index
*/
protected void createItem(Object parent, Object element, int index) {
Class[] classes = (cellProvider != null) ? cellProvider.getCellClasses(element) : null;
CTableTreeItem item = null;
Widget parentItem = findItem(parent);
if(parentItem != null && parentItem instanceof CTableTreeItem) {
item = new CTableTreeItem((CTableTreeItem) parentItem, SWT.NONE, index, classes);
}
if(item == null) item = new CTableTreeItem(getCTableTree(), SWT.NONE, index, classes);
updateItem(item, element);
}
protected void doUpdateCell(int index, CContainerCell cell, Object element, String[] properties) {
super.doUpdateCell(index, cell, element, properties);
IBaseLabelProvider prov = (IBaseLabelProvider) getLabelProvider();
if(prov != null) {
CTableTreeCell cttc = (CTableTreeCell) cell;
String text = null;
if(prov instanceof ICContainerLabelProvider) {
cttc.setImages(((ICContainerLabelProvider) prov).getColumnImages(element, index));
text = ((ITableLabelProvider) prov).getColumnText(element, index);
} else if(prov instanceof ITableLabelProvider) {
cttc.setImage(((ITableLabelProvider) prov).getColumnImage(element, index));
text = ((ITableLabelProvider) prov).getColumnText(element, index);
} else if(prov instanceof ILabelProvider) {
cttc.setImage(((ILabelProvider) prov).getImage(element));
text = ((ILabelProvider) prov).getText(element);
}
if(text == null) text = ""; //$NON-NLS-1$
cttc.setText(text);
}
}
public void expandAll() {
expandAll(false);
}
/**
* If allCells is true, it affects all the item's cells, not just the Tree Cell
* <p>If allCells is false, it simply call expandAll()</p>
* @param allCells
* @see org.eclipse.jface.viewers.TreeViewer#expandAll()
*/
public void expandAll(boolean allCells) {
if(allCells) {
CContainerItem[] items = container.getItems();
for(int i = 0; i < items.length; i++) {
// if(!items[i].getExpanded(allCells))
// items[i].setExpanded(true, allCells);
}
} else {
expandAll();
}
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public void expandToLevel(int level) {
// TODO Auto-generated method stub
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public void expandToLevel(Object element, int level) {
// TODO Auto-generated method stub
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public int getAutoExpandLevel() {
// TODO Auto-generated method stub
return 0;
}
public CTableTree getCTableTree() {
return (CTableTree) container;
}
public Object[] getExpandedElements() {
return getExpandedElements(false);
}
/**
* If allCells is true, it affects all the item's cells, not just the Tree Cell
* <p>If allCells is false, it is the same as getExpandedState(Object)</p>
* @param element
* @param allCells
* @return
* @see org.eclipse.jface.viewers.TreeViewer#getExpandedState(Object)
*/
public Object[] getExpandedElements(boolean allCells) {
List l = new ArrayList(Arrays.asList(container.getItems()));
// for(Iterator i = l.iterator(); i.hasNext(); ) {
// CTableTreeItem item = ((CTableTreeItem) i.next());
// if(!item.getExpanded(allCells)) i.remove();
// }
Object[] elements = new Object[l.size()];
for(int i = 0; i < elements.length; i++) {
elements[i] = ((CTableTreeItem) l.get(i)).getData();
}
return elements;
}
// /**
// * If allCells is true, it affects all the item's cells, not just the Tree Cell
// * <p>If allCells is false, it simply call collapseAll()</p>
// * @param allCells
// * @see org.eclipse.jface.viewers.TreeViewer#collapseAll()
// */
// public void collapseAll(boolean allCells) {
// if(allCells) {
// CTableTreeItem[] items = cTableTree.getItems();
// for(int i = 0; i < items.length; i++) {
// if(items[i].getExpanded(allCells))
// items[i].setExpanded(false, allCells);
// }
// } else {
// collapseAll();
// }
// }
public boolean getExpandedState(Object element) {
return getExpandedState(element, false);
}
/**
* If allCells is true, it affects all the item's cells, not just the Tree Cell
* <p>If allCells is false, it is the same as getExpandedState(Object)</p>
* @param element
* @param allCells
* @return
* @see org.eclipse.jface.viewers.TreeViewer#getExpandedState(Object)
*/
public boolean getExpandedState(Object element, boolean allCells) {
// CTableTreeItem item = (CTableTreeItem) findItem(element);
// if(item != null) return item.getExpanded(allCells);
return false;
}
protected Object[] getRawChildren(Object parent) {
Object[] result = null;
TreePath path;
if(parent instanceof TreePath) {
path = (TreePath) parent;
parent = path.getLastSegment();
} else {
path = null;
}
if(parent != null) {
IStructuredContentProvider cp = (IStructuredContentProvider) getContentProvider();
if(cp != null) {
if(cp instanceof ITreeContentProvider) {
ITreeContentProvider tcp = (ITreeContentProvider) cp;
// if Flat, must iteratively get all children and return them as one array
// so that the filters and sorters hit every element
// if NOT Flat (Hierarchical) then only return the direct elements or children
// requested - the getSortedChildren method will compile all branches after
// being filtered
if(getCTableTree().isFlat()) {
Object[] oa;
if(equals(parent, getRoot())) {
oa = tcp.getElements(parent);
} else {
oa = tcp.getChildren(parent);
}
Set s = new HashSet(oa.length);
for(int i = 0; i < oa.length; i++) {
s.add(oa[i]);
s.addAll(Arrays.asList(getRawChildren(oa[i])));
}
result = s.isEmpty() ? new Object[0] : s.toArray();
} else {
if(equals(parent, getRoot())) {
result = tcp.getElements(parent);
} else {
result = tcp.getChildren(parent);
}
}
}
else if(cp instanceof ITreePathContentProvider) {
ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
// if Flat, must iteratively get all children and return them as one array
// so that the filters and sorters hit every element
// if NOT Flat (Hierarchical) then only return the direct elements or children
// requested - the getSortedChildren method will compile all branches after
// being filtered
if(getCTableTree().isFlat()) {
Object[] oa;
if(equals(parent, getRoot())) {
oa = tpcp.getElements(parent);
} else {
if(path == null) {
// A path was not provided so try and find one
Widget w = findItem(parent);
if (w instanceof Item) {
Item item = (Item) w;
path = getTreePathFromItem(item);
}
if (path == null) {
path = new TreePath(new Object[] { parent });
}
}
oa = tpcp.getChildren(path);
}
Set s = new HashSet(oa.length);
for(int i = 0; i < oa.length; i++) {
s.add(oa[i]);
s.addAll(Arrays.asList(getRawChildren(oa[i])));
}
result = s.isEmpty() ? new Object[0] : s.toArray();
} else {
if(equals(parent, getRoot())) {
result = tpcp.getElements(parent);
} else {
if(path == null) {
// A path was not provided so try and find one
Widget w = findItem(parent);
if (w instanceof Item) {
Item item = (Item) w;
path = getTreePathFromItem(item);
}
if (path == null) {
path = new TreePath(new Object[] { parent });
}
}
result = tpcp.getChildren(path);
}
}
} else {
result = cp.getElements(parent);
}
assertElementsNotNull(result);
}
}
return (result != null) ? result : new Object[0];
}
protected Object[] getSortedChildren(Object parent) {
Object[] result = null;
if (parent != null) {
if(getCTableTree().isFlat()) {
result = super.getSortedChildren(parent);
} else {
Object[] oa = getFilteredChildren(parent);
if(getSorter() != null) {
oa = (Object[]) oa.clone();
getSorter().sort(this, oa);
}
List l = new ArrayList();
for(int i = 0; i < oa.length; i++) {
l.add(oa[i]);
if(getContentProvider() instanceof ITreeContentProvider) {
l.addAll(Arrays.asList(getSortedChildren(oa[i])));
}
}
result = l.isEmpty() ? new Object[0] : l.toArray();
}
}
return (result != null) ? result : new Object[0];
}
/**
* Returns the tree path for the given item.
* from abstracttreeviewer
* @since 3.2
*/
protected TreePath getTreePathFromItem(Widget item) {
LinkedList segments = new LinkedList();
while(item!=null) {
Object segment = item.getData();
Assert.isNotNull(segment);
segments.addFirst(segment);
item = ((CTableTreeItem) item).getParentItem();
}
return new TreePath(segments.toArray());
}
public Object[] getVisibleExpandedElements() {
List l = new ArrayList(Arrays.asList(container.getItems()));
for(Iterator i = l.iterator(); i.hasNext(); ) {
CTableTreeItem item = ((CTableTreeItem) i.next());
if(!getCTableTree().isVisible(item)) i.remove();
}
Object[] elements = new Object[l.size()];
for(int i = 0; i < elements.length; i++) {
elements[i] = ((CTableTreeItem) l.get(i)).getData();
}
return elements;
}
/**
* Refresh all of the elements of the table. update the
* labels if updatLabels is true;
* @param updateLabels
*
* @since 3.1
*/
protected void internalRefreshAll(boolean updateLabels) {
Object[] expanded = getExpandedElements(true);
if(treeColumn == getCTableTree().getTreeColumn()) {
super.internalRefreshAll(updateLabels);
} else {
Object[] children = getSortedChildren(getRoot());
CContainerItem[] items = getCTableTree().getItems();
treeColumn = getCTableTree().getTreeColumn();
for(int i = 0; i < items.length; i++) {
Object data = items[i].getData();
if(data != null) {
disassociate(items[i]);
}
}
container.removeAll();
add(children);
}
setExpandedElements(expanded, true);
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public boolean isExpandable(Object element) {
// TODO Auto-generated method stub
return false;
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public void removeTreeListener(ITreeViewerListener listener) {
// TODO Auto-generated method stub
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public void replace(Object parent, int index, Object element) {
// TODO Auto-generated method stub
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public void setAutoExpandLevel(int level) {
// TODO Auto-generated method stub
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public void setChildCount(Object element, int count) {
// TODO Auto-generated method stub
}
public void setExpandedElements(Object[] elements) {
setExpandedElements(elements, false);
}
public void setExpandedElements(Object[] elements, boolean allCells) {
// CTableTreeItem[] items = cTableTree.getItems();
// for(int i = 0; i < items.length; i++) {
// items[i].setExpanded(false, allCells);
// }
// for(int i = 0; i < elements.length; i++) {
// CTableTreeItem item = (CTableTreeItem) findItem(elements[i]);
// if(item != null) item.setExpanded(true, allCells);
// }
}
public void setExpandedState(Object element, boolean expanded) {
setExpandedState(element, expanded, false);
}
public void setExpandedState(Object element, boolean expanded, boolean allCells) {
// CTableTreeItem item = (CTableTreeItem) findItem(element);
// if(item != null) item.setExpanded(expanded, allCells);
}
/**
* not yet implemented
* <p>post a feature request if you need it enabled</p>
*/
public void setItemCount(int count) {
// TODO Auto-generated method stub
}
}