package org.nightlabs.jfire.personrelation.ui.tree; import java.util.Collection; import java.util.Set; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.TableLayout; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.ui.part.DrillDownAdapter; import org.nightlabs.base.ui.tree.AbstractTreeComposite; import org.nightlabs.jdo.ObjectID; import org.nightlabs.jfire.base.ui.jdo.tree.lazy.JDOLazyTreeNodesChangedEvent; import org.nightlabs.jfire.base.ui.jdo.tree.lazy.JDOLazyTreeNodesChangedEventHandler; import org.nightlabs.jfire.personrelation.ui.resource.Messages; import org.nightlabs.jfire.prop.id.PropertySetID; /** * @author Marco Schulze * @author khaireel (at) nightlabs (dot) de */ public class PersonRelationTree<N extends PersonRelationTreeNode> extends AbstractTreeComposite<N> { private Collection<PropertySetID> personIDs; // Note: (since 2010.03.28) // The entire PersonRelationTreeLabelProvider has been upgraded to a become fully qualified class, along with its delegates. // This should allow us to extend the class further in order to give more control in manipulating the Graphics Control found in // the super class ColumnSpanLabelProvider. private PersonRelationTreeLabelProvider<N> personRelationTreeLabelProvider = null; protected PersonRelationTreeLabelProvider<N> createPersonRelationTreeLabelProvider(TreeViewer treeViewer) { // We supply the default PersonRelationTreeProvider here. Override it for more specificity. return new PersonRelationTreeLabelProvider<N>(treeViewer, true); } public void addPersonRelationTreeLabelProviderDelegate(IPersonRelationTreeLabelProviderDelegate delegate) { if (personRelationTreeLabelProvider != null) personRelationTreeLabelProvider.addPersonRelationTreeLabelProviderDelegate(delegate); // else we should throw something...? } protected Set<IPersonRelationTreeLabelProviderDelegate> getAllPersonRelationTreeLabelProviderDelegates() { return personRelationTreeLabelProvider == null ? null : personRelationTreeLabelProvider.getAllPersonRelationTreeLabelProviderDelegates(); } private void assertSWTThread() { if (Display.getCurrent() == null) throw new IllegalStateException("Wrong thread! This method must be called on the SWT UI thread!"); //$NON-NLS-1$ } private void assertNotDisposed() { if (isDisposed()) throw new IllegalStateException("This PersonRelationTree is already disposed! " + this); //$NON-NLS-1$ } private PersonRelationTreeController<N> personRelationTreeController; // ------ [Constructors: With options for more control parameters; for collapse-state and for context-menus] --------->> public PersonRelationTree(Composite parent) { this(parent, true); } public PersonRelationTree(Composite parent, boolean isRestoreCollapseState) { this(parent, isRestoreCollapseState, true, true); } public PersonRelationTree(Composite parent, boolean isRestoreCollapseState, boolean isCreateContextMenu, boolean isMenuWithDrillDownAdapter) { // We have to ensure that we dont trigger the Abstract-tree's init() method before setting // the restoring the collapse state of the tree. That is, we trigger init() only after setting the state. super(parent, SWT.VIRTUAL | SWT.FULL_SELECTION, true, false, true); setRestoreCollapseState(isRestoreCollapseState); init(); personRelationTreeController = createPersonRelationTreeController(); addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent event) { for (IPersonRelationTreeLabelProviderDelegate delegate : getAllPersonRelationTreeLabelProviderDelegates()) delegate.onDispose(); personRelationTreeController.close(); personRelationTreeController = null; } }); if (isCreateContextMenu) { TreeViewer treeViewer = getTreeViewer(); createContextMenu(isMenuWithDrillDownAdapter ? new DrillDownAdapter(treeViewer) : null, treeViewer.getControl()); } super.setInput(personRelationTreeController); } // // ------------------------------------------------------------------------------------------------------------------->> // /** // * Initialises the set of priorityOrderedContextMenuContributions by blending them into tree's SelectionChangeListener; // * i.e. mainly, this controls the UI's enabled (or disabled) state for which ever (context) item has been selected. // * Call this once, only when we are ready with all the menu items we want. For now, we handle only those {@link IViewActionDelegate}, // * for they have the method to handle 'selectionchanged()'. // * // * This also sets up the double-click behaviour, where in this setup, we assume that the (menu) items registered in the // * {@link AbstractTreeComposite} has been ordered in accordance to 'first-available-default' priority, this in turn will // * make them to be automatically used in this double-click context. See notes 2010.03.08. Kai. // * // * See first independent application usage in PersonRelationIssueTreeView. // */ // public void integratePriorityOrderedContextMenu() { // List<Object> orderedContextMenuContributions = getPriorityOrderedContextMenuContributions(); // if (orderedContextMenuContributions == null || orderedContextMenuContributions.isEmpty()) // return; // // // On selection changes. // addSelectionChangedListener(new ISelectionChangedListener() { // @Override // public void selectionChanged(SelectionChangedEvent event) { // if (event.getSelection().isEmpty()) // return; // // for (Object menuItem : getPriorityOrderedContextMenuContributions()) { // if (menuItem instanceof IViewActionDelegate) // ((IViewActionDelegate) menuItem).selectionChanged((IAction) menuItem, event.getSelection()); // } // } // }); // // // On double-click: 'first-available-default' priority execution. // addDoubleClickListener(new IDoubleClickListener() { // @Override // public void doubleClick(DoubleClickEvent event) { // if (event.getSelection().isEmpty()) // return; // // for (Object menuItem : getPriorityOrderedContextMenuContributions()) // if (menuItem instanceof IAction) { // IAction menuAction = (IAction) menuItem; // if (menuAction.isEnabled()) { // menuAction.run(); // return; // } // } // } // }); // } // // // ------------------------------------------------------------------------------------------------------------------->> /** * Override this method in order to control whether the TreeController and * LabelProvider should add the default delegates for PersonRelations. * @return In this case, <code>true</code>. */ protected boolean isAddDefaultDelegates() { return true; } protected PersonRelationTreeController<N> createPersonRelationTreeController() { return new PersonRelationTreeController<N>(isAddDefaultDelegates()) { @Override protected void onJDOObjectsChanged(JDOLazyTreeNodesChangedEvent<ObjectID, N> changedEvent) { JDOLazyTreeNodesChangedEventHandler.handle(getTreeViewer(), changedEvent); } @SuppressWarnings("unchecked") @Override protected N createNode() { return (N) new PersonRelationTreeNode(); } }; } public PersonRelationTreeController<N> getPersonRelationTreeController() { return personRelationTreeController; } @Override public void createTreeColumns(Tree tree) { TableLayout tableLayout = new TableLayout(); TreeColumn column = new TreeColumn(tree, SWT.LEFT); column.setText(Messages.getString("org.nightlabs.jfire.personrelation.ui.PersonRelationTree.tree.column.relation.text")); //$NON-NLS-1$ tableLayout.addColumnData(new ColumnWeightData(2)); // tableLayout.addColumnData(new ColumnPixelData(120)); column = new TreeColumn(tree, SWT.LEFT); column.setText(Messages.getString("org.nightlabs.jfire.personrelation.ui.PersonRelationTree.tree.column.person.text")); //$NON-NLS-1$ tableLayout.addColumnData(new ColumnWeightData(3)); // tableLayout.addColumnData(new ColumnWeightData(70)); tree.setLayout(tableLayout); tree.setHeaderVisible(true); } @Override public void setTreeProvider(TreeViewer treeViewer) { personRelationTreeLabelProvider = createPersonRelationTreeLabelProvider(treeViewer); treeViewer.setContentProvider(new PersonRelationTreeContentProvider<N>()); treeViewer.setLabelProvider(personRelationTreeLabelProvider.getLabelProviderToUseForTree()); } public void setInputPersonIDs(Collection<PropertySetID> personIDs, PropertySetID source) { assertSWTThread(); assertNotDisposed(); super.setInput(null); this.personIDs = personIDs; for (IPersonRelationTreeLabelProviderDelegate delegate : getAllPersonRelationTreeLabelProviderDelegates()) { delegate.clear(); } getPersonRelationTreeController().clear(); for (IPersonRelationTreeControllerDelegate delegate: getPersonRelationTreeController().getPersonRelationTreeControllerDelegates()) { delegate.setRootPersonIDs(personIDs); } super.setInput(personRelationTreeController); } public void setInputPersonIDs(Collection<PropertySetID> personIDs) { setInputPersonIDs(personIDs, null); } public Collection<PropertySetID> getInputPersonIDs() { return personIDs; } /** * @deprecated Do not call this method! It's only inherited and used * internally - use {@link #setInputPersonIDs(Collection)} instead. */ @Deprecated @Override public void setInput(Object input) { super.setInput(input); } }