package org.nightlabs.jfire.issuetracking.ui.overview;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TreeItem;
import org.nightlabs.base.ui.composite.XComposite;
import org.nightlabs.jdo.query.QueryEvent;
import org.nightlabs.jdo.query.QueryProvider;
import org.nightlabs.jdo.query.AbstractSearchQuery.FieldChangeCarrier;
import org.nightlabs.jfire.base.ui.jdo.tree.JDOObjectTreeNode;
import org.nightlabs.jfire.base.ui.jdo.tree.JDOTreeNodesChangedEvent;
import org.nightlabs.jfire.base.ui.jdo.tree.JDOTreeNodesChangedListener;
import org.nightlabs.jfire.base.ui.search.AbstractQueryFilterComposite;
import org.nightlabs.jfire.issue.project.Project;
import org.nightlabs.jfire.issue.project.id.ProjectID;
import org.nightlabs.jfire.issue.query.IssueQuery;
import org.nightlabs.jfire.issuetracking.ui.issue.ActiveProjectTreeController;
import org.nightlabs.jfire.issuetracking.ui.project.ProjectAdminTreeComposite;
import org.nightlabs.jfire.issuetracking.ui.project.ProjectTreeNode;
import org.nightlabs.jfire.issuetracking.ui.resource.Messages;
/**
* @author Chairat Kongarayawetchakun <!-- chairat [AT] nightlabs [DOT] de -->
*
*/
public class IssueFilterCompositeProjectRelated
extends AbstractQueryFilterComposite<IssueQuery>
{
private ProjectAdminTreeComposite projectTreeComposite;
private CheckboxTreeViewer checkboxTreeViewer;
private volatile Set<ProjectID> selectedProjectIDs = new HashSet<ProjectID>();
/**
* @param parent
* The parent to instantiate this filter into.
* @param style
* The style to apply.
* @param layoutMode
* The layout mode to use. See {@link XComposite.LayoutMode}.
* @param layoutDataMode
* The layout data mode to use. See {@link XComposite.LayoutDataMode}.
* @param queryProvider
* The queryProvider to use. It may be <code>null</code>, but the caller has to
* ensure, that it is set before {@link #getQuery()} is called!
*/
public IssueFilterCompositeProjectRelated(Composite parent, int style,
LayoutMode layoutMode, LayoutDataMode layoutDataMode,
QueryProvider<? super IssueQuery> queryProvider)
{
super(parent, style, layoutMode, layoutDataMode, queryProvider);
createComposite();
}
/**
* @param parent
* The this to instantiate this filter into.
* @param style
* The style to apply.
* @param queryProvider
* The queryProvider to use. It may be <code>null</code>, but the caller has to
* ensure, that it is set before {@link #getQuery()} is called!
*/
public IssueFilterCompositeProjectRelated(Composite parent, int style,
QueryProvider<? super IssueQuery> queryProvider)
{
super(parent, style, queryProvider);
createComposite();
}
@Override
public Class<IssueQuery> getQueryClass() {
return IssueQuery.class;
}
@Override
protected void createComposite()
{
this.setLayout(new GridLayout(3, false));
XComposite projectComposite = new XComposite(this, SWT.NONE,
LayoutMode.TIGHT_WRAPPER, LayoutDataMode.GRID_DATA);
projectComposite.getGridLayout().numColumns = 2;
new Label(projectComposite, SWT.NONE).setText(Messages.getString("org.nightlabs.jfire.issuetracking.ui.overview.IssueFilterCompositeProjectRelated.label.project.text")); //$NON-NLS-1$
projectTreeComposite = new ProjectAdminTreeComposite(projectComposite, SWT.CHECK, true);
checkboxTreeViewer = new CheckboxTreeViewer(projectTreeComposite.getTree());
checkboxTreeViewer.setContentProvider(projectTreeComposite.getTreeViewer().getContentProvider());
checkboxTreeViewer.setInput(projectTreeComposite.getTreeViewer().getInput());
checkboxTreeViewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
selectedProjectIDs.clear();
//Child Checking
final boolean isChecked = event.getChecked();
ProjectTreeNode checkedNode = (ProjectTreeNode)event.getElement();
projectTreeComposite.getTreeViewer().expandToLevel(checkedNode, AbstractTreeViewer.ALL_LEVELS);
checkedNode.getActiveJDOObjectTreeController().addJDOTreeNodesChangedListener(new JDOTreeNodesChangedListener<ProjectID, Project, ProjectTreeNode>() {
@Override
public void onJDOObjectsChanged(
JDOTreeNodesChangedEvent<ProjectID, ProjectTreeNode> changedEvent) {
for (ProjectTreeNode loadedNode : changedEvent.getLoadedTreeNodes()) {
projectTreeComposite.getTreeViewer().expandToLevel(loadedNode, AbstractTreeViewer.ALL_LEVELS);
checkboxTreeViewer.setChecked(loadedNode, isChecked);
if (isChecked)
selectedProjectIDs.add(loadedNode.getJdoObject().getObjectId());
}
}
});
//for isChecked == false
checkboxTreeViewer.setSubtreeChecked(checkedNode, isChecked);
automateParentCheck((ProjectTreeNode)checkedNode.getParent());
//End Child Checking
for (Object object : checkboxTreeViewer.getCheckedElements()) {
if (object instanceof ProjectTreeNode) {
ProjectTreeNode projectTreeNode = (ProjectTreeNode)object;
selectedProjectIDs.add(projectTreeNode.getJdoObject().getObjectId());
}
}
getQuery().setProjectIDs(selectedProjectIDs);
boolean enable = !selectedProjectIDs.isEmpty();
getQuery().setFieldEnabled(IssueQuery.FieldName.projectIDs, enable);
}
});
}
private void automateParentCheck(ProjectTreeNode parentNode) {
if (parentNode != null) {
// Kai: Added compliance to the generic definitions in JDOObjectTreeNode.
List<JDOObjectTreeNode<ProjectID, Project, ActiveProjectTreeController>> childCheckedNodes = parentNode.getChildNodes();
boolean needChecking = false;
for (JDOObjectTreeNode<ProjectID, Project, ActiveProjectTreeController> childCheckedNode : childCheckedNodes) {
if (checkboxTreeViewer.getChecked(childCheckedNode)) {
needChecking = true;
break;
}
}
checkboxTreeViewer.setChecked(parentNode, needChecking);
if (!needChecking)
automateParentCheck((ProjectTreeNode)parentNode.getParent());
}
}
@SuppressWarnings("unchecked")
@Override
protected void updateUI(QueryEvent event, List<FieldChangeCarrier> changedFields)
{
for (FieldChangeCarrier changedField : event.getChangedFields())
{
if (IssueQuery.FieldName.projectIDs.equals(changedField.getPropertyName()))
{
Set<ProjectID> newProjectIDs = (Set<ProjectID>) changedField.getNewValue();
if (newProjectIDs == null)
{
TreeItem[] treeItems = checkboxTreeViewer.getTree().getItems();
for (TreeItem treeItem : treeItems) {
treeItem.setChecked(false);
}
}
else
{
for (ProjectID projectID : newProjectIDs) {
TreeItem[] treeItems = checkboxTreeViewer.getTree().getItems();
for (TreeItem treeItem : treeItems) {
ProjectTreeNode projectTreeNode = (ProjectTreeNode)treeItem.getData();
if (projectTreeNode.getJdoObject().getProjectID() == projectID.projectID) {
treeItem.setChecked(true);
}
}
}
}
}
else if (getEnableFieldName(IssueQuery.FieldName.projectIDs).equals(
changedField.getPropertyName()))
{
Boolean active = (Boolean) changedField.getNewValue();
setSearchSectionActive(active);
if (!active) {
checkboxTreeViewer.setAllChecked(false);
getQuery().getProjectIDs().clear();
}
}
} // for (FieldChangeCarrier changedField : event.getChangedFields())
}
private static final Set<String> fieldNames;
static
{
fieldNames = new HashSet<String>(1);
fieldNames.add(IssueQuery.FieldName.projectIDs);
}
@Override
protected Set<String> getFieldNames()
{
return fieldNames;
}
/**
* Group ID for storing active states in the query.
*/
public static final String FILTER_GROUP_ID = "IssueFilterCompositeProjectRelated"; //$NON-NLS-1$
@Override
protected String getGroupID()
{
return FILTER_GROUP_ID;
}
}